Skip to content

Commit 76cc438

Browse files
committed
First draft of canonicalize, which transforms a parsed tree via a grammar into a more reasonable form.
1 parent a878df1 commit 76cc438

File tree

1 file changed

+132
-0
lines changed

1 file changed

+132
-0
lines changed

parse-css.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
12891419
exports.CSSParserRule = CSSParserRule;
12901420
exports.Stylesheet = Stylesheet;
@@ -1301,5 +1431,7 @@ exports.parseAListOfDeclarations = parseAListOfDeclarations;
13011431
exports.parseAComponentValue = parseAComponentValue;
13021432
exports.parseAListOfComponentValues = parseAListOfComponentValues;
13031433
exports.parseACommaSeparatedListOfComponentValues = parseACommaSeparatedListOfComponentValues;
1434+
exports.canonicalizeRule = canonicalize;
1435+
exports.CSSGrammar = CSSGrammar;
13041436

13051437
}));

0 commit comments

Comments
 (0)