Spaces:
Sleeping
Sleeping
| ; | |
| var openParentheses = "(".charCodeAt(0); | |
| var closeParentheses = ")".charCodeAt(0); | |
| var singleQuote = "'".charCodeAt(0); | |
| var doubleQuote = '"'.charCodeAt(0); | |
| var backslash = "\\".charCodeAt(0); | |
| var slash = "/".charCodeAt(0); | |
| var comma = ",".charCodeAt(0); | |
| var colon = ":".charCodeAt(0); | |
| var star = "*".charCodeAt(0); | |
| var uLower = "u".charCodeAt(0); | |
| var uUpper = "U".charCodeAt(0); | |
| var plus = "+".charCodeAt(0); | |
| var isUnicodeRange = /^[a-f0-9?-]+$/i; | |
| module.exports = function(input) { | |
| var tokens = []; | |
| var value = input; | |
| var next, quote, prev, token, escape, escapePos, whitespacePos, parenthesesOpenPos; | |
| var pos = 0; | |
| var code = value.charCodeAt(pos); | |
| var max = value.length; | |
| var stack = [ | |
| { | |
| nodes: tokens | |
| } | |
| ]; | |
| var balanced = 0; | |
| var parent; | |
| var name = ""; | |
| var before = ""; | |
| var after = ""; | |
| while(pos < max){ | |
| // Whitespaces | |
| if (code <= 32) { | |
| next = pos; | |
| do { | |
| next += 1; | |
| code = value.charCodeAt(next); | |
| }while (code <= 32); | |
| token = value.slice(pos, next); | |
| prev = tokens[tokens.length - 1]; | |
| if (code === closeParentheses && balanced) { | |
| after = token; | |
| } else if (prev && prev.type === "div") { | |
| prev.after = token; | |
| prev.sourceEndIndex += token.length; | |
| } else if (code === comma || code === colon || code === slash && value.charCodeAt(next + 1) !== star && (!parent || parent && parent.type === "function" && false)) { | |
| before = token; | |
| } else { | |
| tokens.push({ | |
| type: "space", | |
| sourceIndex: pos, | |
| sourceEndIndex: next, | |
| value: token | |
| }); | |
| } | |
| pos = next; | |
| // Quotes | |
| } else if (code === singleQuote || code === doubleQuote) { | |
| next = pos; | |
| quote = code === singleQuote ? "'" : '"'; | |
| token = { | |
| type: "string", | |
| sourceIndex: pos, | |
| quote: quote | |
| }; | |
| do { | |
| escape = false; | |
| next = value.indexOf(quote, next + 1); | |
| if (~next) { | |
| escapePos = next; | |
| while(value.charCodeAt(escapePos - 1) === backslash){ | |
| escapePos -= 1; | |
| escape = !escape; | |
| } | |
| } else { | |
| value += quote; | |
| next = value.length - 1; | |
| token.unclosed = true; | |
| } | |
| }while (escape); | |
| token.value = value.slice(pos + 1, next); | |
| token.sourceEndIndex = token.unclosed ? next : next + 1; | |
| tokens.push(token); | |
| pos = next + 1; | |
| code = value.charCodeAt(pos); | |
| // Comments | |
| } else if (code === slash && value.charCodeAt(pos + 1) === star) { | |
| next = value.indexOf("*/", pos); | |
| token = { | |
| type: "comment", | |
| sourceIndex: pos, | |
| sourceEndIndex: next + 2 | |
| }; | |
| if (next === -1) { | |
| token.unclosed = true; | |
| next = value.length; | |
| token.sourceEndIndex = next; | |
| } | |
| token.value = value.slice(pos + 2, next); | |
| tokens.push(token); | |
| pos = next + 2; | |
| code = value.charCodeAt(pos); | |
| // Operation within calc | |
| } else if ((code === slash || code === star) && parent && parent.type === "function" && true) { | |
| token = value[pos]; | |
| tokens.push({ | |
| type: "word", | |
| sourceIndex: pos - before.length, | |
| sourceEndIndex: pos + token.length, | |
| value: token | |
| }); | |
| pos += 1; | |
| code = value.charCodeAt(pos); | |
| // Dividers | |
| } else if (code === slash || code === comma || code === colon) { | |
| token = value[pos]; | |
| tokens.push({ | |
| type: "div", | |
| sourceIndex: pos - before.length, | |
| sourceEndIndex: pos + token.length, | |
| value: token, | |
| before: before, | |
| after: "" | |
| }); | |
| before = ""; | |
| pos += 1; | |
| code = value.charCodeAt(pos); | |
| // Open parentheses | |
| } else if (openParentheses === code) { | |
| // Whitespaces after open parentheses | |
| next = pos; | |
| do { | |
| next += 1; | |
| code = value.charCodeAt(next); | |
| }while (code <= 32); | |
| parenthesesOpenPos = pos; | |
| token = { | |
| type: "function", | |
| sourceIndex: pos - name.length, | |
| value: name, | |
| before: value.slice(parenthesesOpenPos + 1, next) | |
| }; | |
| pos = next; | |
| if (name === "url" && code !== singleQuote && code !== doubleQuote) { | |
| next -= 1; | |
| do { | |
| escape = false; | |
| next = value.indexOf(")", next + 1); | |
| if (~next) { | |
| escapePos = next; | |
| while(value.charCodeAt(escapePos - 1) === backslash){ | |
| escapePos -= 1; | |
| escape = !escape; | |
| } | |
| } else { | |
| value += ")"; | |
| next = value.length - 1; | |
| token.unclosed = true; | |
| } | |
| }while (escape); | |
| // Whitespaces before closed | |
| whitespacePos = next; | |
| do { | |
| whitespacePos -= 1; | |
| code = value.charCodeAt(whitespacePos); | |
| }while (code <= 32); | |
| if (parenthesesOpenPos < whitespacePos) { | |
| if (pos !== whitespacePos + 1) { | |
| token.nodes = [ | |
| { | |
| type: "word", | |
| sourceIndex: pos, | |
| sourceEndIndex: whitespacePos + 1, | |
| value: value.slice(pos, whitespacePos + 1) | |
| } | |
| ]; | |
| } else { | |
| token.nodes = []; | |
| } | |
| if (token.unclosed && whitespacePos + 1 !== next) { | |
| token.after = ""; | |
| token.nodes.push({ | |
| type: "space", | |
| sourceIndex: whitespacePos + 1, | |
| sourceEndIndex: next, | |
| value: value.slice(whitespacePos + 1, next) | |
| }); | |
| } else { | |
| token.after = value.slice(whitespacePos + 1, next); | |
| token.sourceEndIndex = next; | |
| } | |
| } else { | |
| token.after = ""; | |
| token.nodes = []; | |
| } | |
| pos = next + 1; | |
| token.sourceEndIndex = token.unclosed ? next : pos; | |
| code = value.charCodeAt(pos); | |
| tokens.push(token); | |
| } else { | |
| balanced += 1; | |
| token.after = ""; | |
| token.sourceEndIndex = pos + 1; | |
| tokens.push(token); | |
| stack.push(token); | |
| tokens = token.nodes = []; | |
| parent = token; | |
| } | |
| name = ""; | |
| // Close parentheses | |
| } else if (closeParentheses === code && balanced) { | |
| pos += 1; | |
| code = value.charCodeAt(pos); | |
| parent.after = after; | |
| parent.sourceEndIndex += after.length; | |
| after = ""; | |
| balanced -= 1; | |
| stack[stack.length - 1].sourceEndIndex = pos; | |
| stack.pop(); | |
| parent = stack[balanced]; | |
| tokens = parent.nodes; | |
| // Words | |
| } else { | |
| next = pos; | |
| do { | |
| if (code === backslash) { | |
| next += 1; | |
| } | |
| next += 1; | |
| code = value.charCodeAt(next); | |
| }while (next < max && !(code <= 32 || code === singleQuote || code === doubleQuote || code === comma || code === colon || code === slash || code === openParentheses || code === star && parent && parent.type === "function" && true || code === slash && parent.type === "function" && true || code === closeParentheses && balanced)); | |
| token = value.slice(pos, next); | |
| if (openParentheses === code) { | |
| name = token; | |
| } else if ((uLower === token.charCodeAt(0) || uUpper === token.charCodeAt(0)) && plus === token.charCodeAt(1) && isUnicodeRange.test(token.slice(2))) { | |
| tokens.push({ | |
| type: "unicode-range", | |
| sourceIndex: pos, | |
| sourceEndIndex: next, | |
| value: token | |
| }); | |
| } else { | |
| tokens.push({ | |
| type: "word", | |
| sourceIndex: pos, | |
| sourceEndIndex: next, | |
| value: token | |
| }); | |
| } | |
| pos = next; | |
| } | |
| } | |
| for(pos = stack.length - 1; pos; pos -= 1){ | |
| stack[pos].unclosed = true; | |
| stack[pos].sourceEndIndex = value.length; | |
| } | |
| return stack[0].nodes; | |
| }; | |