@@ -1285,6 +1285,136 @@ Func.prototype.toJSON = function() {
1285
1285
return json ;
1286
1286
}
1287
1287
1288
+
1289
+ /* Grammar Application */
1290
+
1291
+ function canonicalize ( rule , grammar , topGrammar ) {
1292
+ if ( grammar === undefined ) grammar = CSSGrammar ;
1293
+ if ( topGrammar === undefined ) topGrammar = grammar
1294
+ if ( ! validateGrammar ( grammar ) ) return ;
1295
+ if ( grammar ) {
1296
+ if ( grammar . stylesheet ) grammar = topGrammar ;
1297
+ var unknownTransformer = grammar . unknown || function ( ) { return } ;
1298
+ }
1299
+ var ret = { "type" :rule . type . toLowerCase ( ) } ;
1300
+
1301
+ if ( rule . type == "STYLESHEET" ) {
1302
+ var contents = rule . value ;
1303
+ } else if ( rule . type == "BLOCK" ) {
1304
+ var unparsedContents = rule . value ;
1305
+ } else if ( rule . type == "QUALIFIED-RULE" ) {
1306
+ var unparsedContents = rule . value . value ;
1307
+ } else if ( rule . type == "AT-RULE" ) {
1308
+ var unparsedContents = rule . value . value ;
1309
+ ret . name = rule . name ;
1310
+ ret . prelude = rule . prelude ;
1311
+ } else if ( rule . type == "DECLARATION" ) {
1312
+ // I don't do grammar-checking of declarations yet.
1313
+ ret . name = rule . name ;
1314
+ ret . value = rule . value ;
1315
+ ret . important = rule . important ;
1316
+ return ret ;
1317
+ }
1318
+ if ( unparsedContents ) {
1319
+ if ( grammar . declarations ) {
1320
+ var contents = parseAListOfDeclarations ( unparsedContents ) ;
1321
+ } else if ( grammar . qualified ) {
1322
+ var contents = parseAListOfRules ( unparsedContents ) ;
1323
+ }
1324
+ }
1325
+
1326
+ if ( ! grammar ) {
1327
+ return ret ;
1328
+ } else if ( grammar . declarations ) {
1329
+ ret . declarations = { } ; // simple key/value map of declarations
1330
+ ret . rules = [ ] ; // in-order list of both decls and at-rules
1331
+ ret . errors = [ ] ;
1332
+ for ( var i = 0 ; i < contents . length ; i ++ ) {
1333
+ var rule = contents [ i ] ;
1334
+ if ( rule instanceof Declaration ) {
1335
+ var decl = canonicalize ( rule , { } , topGrammar ) ;
1336
+ ret . declarations [ rule . name ] = decl ;
1337
+ ret . rules . push ( decl ) ;
1338
+ } else { // rule is instanceof AtRule
1339
+ var subGrammar = grammar [ "@" + rule . name ] ;
1340
+ if ( subGrammar ) { // Rule is valid in this context
1341
+ ret . rules . push ( canonicalize ( rule , subGrammar , topGrammar ) ) ;
1342
+ } else {
1343
+ var result = unknownTransformer ( rule ) ;
1344
+ if ( result ) {
1345
+ ret . rules . push ( result ) ;
1346
+ } else {
1347
+ ret . errors . push ( result ) ;
1348
+ }
1349
+ }
1350
+ }
1351
+ }
1352
+ } else {
1353
+ ret . rules = [ ] ;
1354
+ ret . errors = [ ] ;
1355
+ for ( var i = 0 ; i < contents . length ; i ++ ) {
1356
+ var rule = contents [ i ] ;
1357
+ if ( rule instanceof QualifiedRule ) {
1358
+ ret . rules . push ( canonicalize ( rule , grammar . qualified , topGrammar ) ) ;
1359
+ } else {
1360
+ var subGrammar = grammar [ "@" + rule . name ] ;
1361
+ if ( subGrammar ) { // Rule is valid in this context
1362
+ ret . rules . push ( canonicalize ( rule , subGrammar , topGrammar ) ) ;
1363
+ } else {
1364
+ var result = unknownTransformer ( rule ) ;
1365
+ if ( result ) {
1366
+ ret . rules . push ( result ) ;
1367
+ } else {
1368
+ ret . errors . push ( result ) ;
1369
+ }
1370
+ }
1371
+ }
1372
+ }
1373
+ }
1374
+ return ret ;
1375
+ }
1376
+
1377
+ function validateGrammar ( grammar ) {
1378
+ // TODO
1379
+ return true
1380
+ }
1381
+
1382
+ var CSSGrammar = {
1383
+ qualified : { declarations :true } ,
1384
+ "@media" : { stylesheet :true } ,
1385
+ "@keyframes" : { qualified :{ declarations :true } } ,
1386
+ "@font-face" : { declarations :true } ,
1387
+ "@supports" : { stylesheet :true } ,
1388
+ "@scope" : { stylesheet :true } ,
1389
+ "@counter-style" : { declarations :true } ,
1390
+ "@import" : null ,
1391
+ "@font-feature-values" : { declarations :true } ,
1392
+ "@viewport" : { declarations :true } ,
1393
+ "@page" : {
1394
+ declarations : true ,
1395
+ "@top-left-corner" : { declarations :true } ,
1396
+ "@top-left" : { declarations :true } ,
1397
+ "@top-center" : { declarations :true } ,
1398
+ "@top-right" : { declarations :true } ,
1399
+ "@top-right-corner" : { declarations :true } ,
1400
+ "@right-top" : { declarations :true } ,
1401
+ "@right-middle" : { declarations :true } ,
1402
+ "@right-bottom" : { declarations :true } ,
1403
+ "@right-bottom-corner" : { declarations :true } ,
1404
+ "@bottom-right" : { declarations :true } ,
1405
+ "@bottom-center" : { declarations :true } ,
1406
+ "@bottom-left" : { declarations :true } ,
1407
+ "@bottom-left-corner" : { declarations :true } ,
1408
+ "@left-bottom" : { declarations :true } ,
1409
+ "@left-center" : { declarations :true } ,
1410
+ "@left-top" : { declarations :true } ,
1411
+ } ,
1412
+ "@custom-selector" : null ,
1413
+ "@custom-media" : null
1414
+ }
1415
+
1416
+
1417
+
1288
1418
// Exportation.
1289
1419
exports . CSSParserRule = CSSParserRule ;
1290
1420
exports . Stylesheet = Stylesheet ;
@@ -1301,5 +1431,7 @@ exports.parseAListOfDeclarations = parseAListOfDeclarations;
1301
1431
exports . parseAComponentValue = parseAComponentValue ;
1302
1432
exports . parseAListOfComponentValues = parseAListOfComponentValues ;
1303
1433
exports . parseACommaSeparatedListOfComponentValues = parseACommaSeparatedListOfComponentValues ;
1434
+ exports . canonicalizeRule = canonicalize ;
1435
+ exports . CSSGrammar = CSSGrammar ;
1304
1436
1305
1437
} ) ) ;
0 commit comments