From e48bb6073b9b217863195918437a24fc0c10a7ac Mon Sep 17 00:00:00 2001 From: Tom MacWright Date: Wed, 19 Jan 2011 15:06:42 -0500 Subject: [PATCH] Start unstable branch - kkaefer's flatten work --- bin/messc | 24 ++++++------- lib/mess/parser.js | 74 +++++++++++++++++++++++++++++++++------- lib/mess/tree/rule.js | 3 +- lib/mess/tree/ruleset.js | 73 +++++++++++++++++++++++++++++++++++++++ 4 files changed, 149 insertions(+), 25 deletions(-) diff --git a/bin/messc b/bin/messc index d25bd06..2602b8d 100755 --- a/bin/messc +++ b/bin/messc @@ -94,22 +94,22 @@ fs.readFile(input, 'utf-8', function (e, data) { }).parse(data, function (err, tree) { if (err) { mess.writeError(err, options); - process.exit(1); + // process.exit(1); } else { try { - if (options.debug) { - try { - require('eyes').inspect(tree.toAST()); - } catch (e) { - console.log(e); - console.log(tree.toAST()); - } - } - css = tree.toCSS({ compress: options.compress }); - sys.print(css); + // if (options.debug) { + // try { + // require('eyes').inspect(tree.toAST()); + // } catch (e) { + // console.log(e); + // console.log(tree.toAST()); + // } + // } + var mss = tree.toMSS({ compress: options.compress }); + sys.print(mss); } catch (e) { mess.writeError(e, options); - process.exit(2); + // process.exit(2); } } }); diff --git a/lib/mess/parser.js b/lib/mess/parser.js index 22e459d..8dc8ce2 100644 --- a/lib/mess/parser.js +++ b/lib/mess/parser.js @@ -304,6 +304,55 @@ mess.Parser = function Parser(env) { })(root.eval); + root.toMSS = (function() { + var line, lines, column; + + return function(options, variables) { + options = options || {}; + options.compress = 'compress' in options ? options.compress : (env.compress || false); + + try { + var rulesets = this.flatten(); + var mss = []; + rulesets.sort(specificitySort); + for (var i = 0; i < rulesets.length; i++) { + mss.push(rulesets[i].toCSS([], env)); + } + return mss.join('\n'); + } + catch (e) { + lines = input.split('\n'); + line = getLine(e.index); + + for (var n = e.index, column = -1; + n >= 0 && input.charAt(n) !== '\n'; + n--) { column++ } + + throw { + type: e.type, + message: e.message, + filename: env.filename, + index: e.index, + line: typeof(line) === 'number' ? line + 1 : null, + callLine: e.call && (getLine(e.call) + 1), + callExtract: lines[getLine(e.call)], + stack: e.stack, + column: column, + extract: [ + lines[line - 1], + lines[line], + lines[line + 1] + ] + } + } + + function getLine(index) { + return index ? (input.slice(0, index).match(/\n/g) || '').length : null; + } + }; + })(); + + var flattenRulesets = function(ast, list) { if (ast.rulesets) { for (var i in ast.rulesets) { @@ -317,19 +366,20 @@ mess.Parser = function Parser(env) { return list; } - /* - var sortRulesets = function(ast) { - ast.sort(function(a, b) { - if (a.selector[0][0] && b.selector) { - a.selector[0][0].specificity() > - b.selector[0][0].specificity(); - } else { - return 1; - } - }); + /** + * Sort rules by specificity: this only works with + * single-selector rules. + * + * Written to be used as a .sort(Function); + * argument. + */ + var specificitySort = function(a, b) { + if (a.selectors.length > 0 && b.selectors.length > 0) { + return a.selectors[0].specificity() < + b.selectors[0].specificity(); + } }; - */ - + root.toAST = (function(evaluate) { var line, lines, column; diff --git a/lib/mess/tree/rule.js b/lib/mess/tree/rule.js index 90785e1..2bc047e 100644 --- a/lib/mess/tree/rule.js +++ b/lib/mess/tree/rule.js @@ -26,7 +26,8 @@ tree.Rule.prototype.toCSS = function(env) { this.name + ', a ' + tree.Reference.selector(this.name).type + - ' is expected', + ' is expected. ' + require('sys').inspect(this.value) + + ' was given.', index: this.index }; } diff --git a/lib/mess/tree/ruleset.js b/lib/mess/tree/ruleset.js index 7430fb9..f04e504 100644 --- a/lib/mess/tree/ruleset.js +++ b/lib/mess/tree/ruleset.js @@ -104,6 +104,53 @@ tree.Ruleset.prototype = { }); return this._lookups[key] = rules; }, + + + flatten: function(parentSelectors) { + var selectors = []; + for (var i = 0; i < this.selectors.length; i++) { + var selector = this.selectors[i]; + + if (parentSelectors.length) { + for (var j = 0; j < parentSelectors.length; j++) { + var parent = parentSelectors[j]; + + // Create a new object for each so that we can have different + // elements and filters in the selector. + var instance = new tree.Selector(); + instance.elements = parent.elements.concat(selector.elements); + instance.filters = parent.filters.concat(selector.filters); + instance.label = 'label' in selector ? selector.label : parent.label; + + selectors.push(instance); + } + } + else { + selectors.push(selector); + } + } + + var rules = []; + var rulesets = []; + for (var i = 0; i < this.rules.length; i++) { + var rule = this.rules[i]; + + if (rule instanceof tree.Ruleset) { + Array.prototype.push.apply(rulesets, rule.flatten(selectors)); + } + else { + rule.value = rule.value.value[0]; + rules.push(rule); + } + } + + var ruleset = new tree.Ruleset(selectors, rules); + ruleset.flattened = true; + rulesets.push(ruleset); + + return rulesets; + }, + // // Entry point for code generation // @@ -174,6 +221,32 @@ tree.Ruleset.prototype = { rules: rules }; }, + + toMSS: function(env) { + var rules = this.rules.map(function(rule) { + rule.value = rule.value.value[0]; + console.log(rule); + + return rule.toCSS(); + }); + + var styles = this.selectors.map(function(selector) { + var filters = selector.filters.map(function(filter) { + return filter.toCSS(); + }); + + return ' \n'; + }); + + return styles.join(''); + }, + // // Entry point for code generation //