@@ -1285,6 +1285,136 @@ Func.prototype.toJSON = function() {
12851285 return json ;
12861286}
12871287
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+
12881418// Exportation.
12891419exports . CSSParserRule = CSSParserRule ;
12901420exports . Stylesheet = Stylesheet ;
@@ -1301,5 +1431,7 @@ exports.parseAListOfDeclarations = parseAListOfDeclarations;
13011431exports . parseAComponentValue = parseAComponentValue ;
13021432exports . parseAListOfComponentValues = parseAListOfComponentValues ;
13031433exports . parseACommaSeparatedListOfComponentValues = parseACommaSeparatedListOfComponentValues ;
1434+ exports . canonicalizeRule = canonicalize ;
1435+ exports . CSSGrammar = CSSGrammar ;
13041436
13051437} ) ) ;
0 commit comments