diff options
Diffstat (limited to 'node_modules/css-selector-tokenizer/lib/parseValues.js')
-rw-r--r-- | node_modules/css-selector-tokenizer/lib/parseValues.js | 167 |
1 files changed, 167 insertions, 0 deletions
diff --git a/node_modules/css-selector-tokenizer/lib/parseValues.js b/node_modules/css-selector-tokenizer/lib/parseValues.js new file mode 100644 index 0000000..690c093 --- /dev/null +++ b/node_modules/css-selector-tokenizer/lib/parseValues.js @@ -0,0 +1,167 @@ +"use strict"; + +var Parser = require("fastparse"); + +function commentMatch(match, content) { + this.value.nodes.push({ + type: "comment", + content: content + }); +} + +function spacingMatch(match) { + var item = this.value.nodes[this.value.nodes.length - 1]; + item.after = (item.after || "") + match; +} + +function initialSpacingMatch(match) { + this.value.before = match; +} + +function endSpacingMatch(match) { + this.value.after = match; +} + +function unescapeString(content) { + return content.replace(/\\(?:([a-fA-F0-9]{1,6})|(.))/g, function(all, unicode, otherCharacter) { + if (otherCharacter) { + return otherCharacter; + } + + var C = parseInt(unicode, 16); + if(C < 0x10000) { + return String.fromCharCode(C); + } else { + return String.fromCharCode(Math.floor((C - 0x10000) / 0x400) + 0xD800) + + String.fromCharCode((C - 0x10000) % 0x400 + 0xDC00); + } + }); +} + +function stringMatch(match, content) { + var value = unescapeString(content); + this.value.nodes.push({ + type: "string", + value: value, + stringType: match[0] + }); +} + +function commaMatch(match, spacing) { + var newValue = { + type: "value", + nodes: [] + }; + if(spacing) { + newValue.before = spacing; + } + this.root.nodes.push(newValue); + this.value = newValue; +} + +function itemMatch(match) { + this.value.nodes.push({ + type: "item", + name: match + }); +} + +function nestedItemMatch(match, name, spacing) { + this.stack.push(this.root); + this.root = { + type: "nested-item", + name: name, + nodes: [ + { type: "value", nodes: [] } + ] + }; + if(spacing) { + this.root.nodes[0].before = spacing; + } + this.value.nodes.push(this.root); + this.value = this.root.nodes[0]; +} + +function nestedItemEndMatch(match, spacing, remaining) { + if(this.stack.length === 0) { + if(spacing) { + var item = this.value.nodes[this.value.nodes.length - 1]; + item.after = (item.after || "") + spacing; + } + this.value.nodes.push({ + type: "invalid", + value: remaining + }); + } else { + if(spacing) { + this.value.after = spacing; + } + this.root = this.stack.pop(); + this.value = this.root.nodes[this.root.nodes.length - 1]; + } +} + +function urlMatch(match, innerSpacingBefore, content, innerSpacingAfter) { + var item = { + type: "url" + }; + if(innerSpacingBefore) { + item.innerSpacingBefore = innerSpacingBefore; + } + if(innerSpacingAfter) { + item.innerSpacingAfter = innerSpacingAfter; + } + switch(content[0]) { + case "\"": + item.stringType = "\""; + item.url = unescapeString(content.substr(1, content.length - 2)); + break; + case "'": + item.stringType = "'"; + item.url = unescapeString(content.substr(1, content.length - 2)); + break; + default: + item.url = unescapeString(content); + break; + } + this.value.nodes.push(item); +} + +var parser = new Parser({ + decl: { + "^\\s+": initialSpacingMatch, + "/\\*([\\s\\S]*?)\\*/": commentMatch, + "\"((?:[^\\\\\"]|\\\\.)*)\"": stringMatch, + "'((?:[^\\\\']|\\\\.)*)'": stringMatch, + "url\\((\\s*)(\"(?:[^\\\\\"]|\\\\.)*\")(\\s*)\\)": urlMatch, + "url\\((\\s*)('(?:[^\\\\']|\\\\.)*')(\\s*)\\)": urlMatch, + "url\\((\\s*)((?:[^\\\\)'\"]|\\\\.)*)(\\s*)\\)": urlMatch, + "([\\w-]+)\\((\\s*)": nestedItemMatch, + "(\\s*)(\\))": nestedItemEndMatch, + ",(\\s*)": commaMatch, + "\\s+$": endSpacingMatch, + "\\s+": spacingMatch, + "[^\\s,)]+": itemMatch + } +}); + +function parseValues(str) { + var valueNode = { + type: "value", + nodes: [] + }; + var rootNode = { + type: "values", + nodes: [ + valueNode + ] + }; + parser.parse("decl", str, { + stack: [], + root: rootNode, + value: valueNode + }); + return rootNode; +} + +module.exports = parseValues; |