diff options
| author | Michael Williamson <mike@zwobble.org> | 2013-03-29 23:50:12 +0000 |
|---|---|---|
| committer | Michael Williamson <mike@zwobble.org> | 2013-03-29 23:50:12 +0000 |
| commit | b2d02fec9a161cfd657f240806b25bdaca315eea (patch) | |
| tree | 690fd3747257537c3f952f1a8e128df64b133acf /lib/style-reader.js | |
| parent | bdf1832cbc2f9e0dc7355bb7d435a9f6ab574d7e (diff) | |
Use lop to parse styles
Diffstat (limited to 'lib/style-reader.js')
| -rw-r--r-- | lib/style-reader.js | 100 |
1 files changed, 90 insertions, 10 deletions
diff --git a/lib/style-reader.js b/lib/style-reader.js index 7ee36c2..1da03ba 100644 --- a/lib/style-reader.js +++ b/lib/style-reader.js @@ -1,3 +1,6 @@ +var lop = require("lop"); +var StringSource = lop.StringSource; + var styles = require("./styles"); exports.read = read; @@ -10,16 +13,93 @@ function read(string) { } function readElement(string) { - var colonParts = string.split(":"); - var parts = colonParts[0].split("."); - var tagName = parts[0]; - var classNames = parts.slice(1); - var options = {}; - if (classNames.length > 0) { - options["class"] = classNames.join(" "); + var capture = lop.rules.sequence.capture; + + var identifierRule = lop.rules.tokenOfType("identifier"); + var classRule = lop.rules.sequence( + lop.rules.tokenOfType("dot"), + capture(identifierRule) + ).head(); + var freshRule = lop.rules.then( + lop.rules.optional(lop.rules.sequence( + lop.rules.tokenOfType("colon"), + lop.rules.token("identifier", "fresh") + )), + function(option) { + return option.map(function() { + return true; + }).valueOrElse(false); + } + ); + + var styleRule = lop.rules.sequence( + capture(identifierRule), + capture(lop.rules.zeroOrMore(classRule)), + capture(freshRule) + ).map(function(tagName, classNames, fresh) { + var options = {}; + if (classNames.length > 0) { + options["class"] = classNames.join(" "); + } + if (fresh) { + options["fresh"] = true; + } + return styles.element(tagName, options); + }); + + var tokens = tokenise(string); + var parser = lop.Parser(); + var parseResult = parser.parseTokens(styleRule, tokens); + if (!parseResult.isSuccess()) { + throw new Error("Failed to parse: " + describeFailure(parseResult)); } - if (colonParts[1] === "fresh") { - options.fresh = true; + return parseResult.value(); +} + +function describeFailure(parseResult) { + return parseResult.errors().map(describeError).join("\n"); + + function describeError(error) { + return error.describe(); } - return styles.element(tagName, options); } + +function tokenise(string) { + var source = new StringSource(string, "raw string"); + var index = 0; + var tokens = []; + + while (index < string.length) { + var nextToken = readNextToken(string, index, source); + if (!nextToken) { + throw new Error("Could not read token from: " + string.substring(index)); + } + index += nextToken.value.length; + tokens.push(nextToken); + } + tokens.push(new lop.Token("end", null, source.range(string.length, string.length))); + return tokens; +} + +function readNextToken(string, startIndex, source) { + for (var i = 0; i < tokenRegexes.length; i++) { + var regex = tokenRegexes[i].regex; + regex.lastIndex = startIndex; + var result = regex.exec(string); + if (result && result.index === startIndex) { + var value = result[0]; + return new lop.Token( + tokenRegexes[i].name, + value, + source.range(startIndex, startIndex + value.length) + ); + } + } +} + +var tokenRegexes = [ + {name: "identifier", regex: /([a-z][a-z0-9\-]*)/g}, + {name: "dot", regex: /\./g}, + {name: "colon", regex: /:/g}, + {name: "whitespace", regex: /\s+/g} +]; |
