Spaces:
Running
Running
| const SINGLE_QUOTE = "'".charCodeAt(0) | |
| const DOUBLE_QUOTE = '"'.charCodeAt(0) | |
| const BACKSLASH = '\\'.charCodeAt(0) | |
| const SLASH = '/'.charCodeAt(0) | |
| const NEWLINE = '\n'.charCodeAt(0) | |
| const SPACE = ' '.charCodeAt(0) | |
| const FEED = '\f'.charCodeAt(0) | |
| const TAB = '\t'.charCodeAt(0) | |
| const CR = '\r'.charCodeAt(0) | |
| const OPEN_SQUARE = '['.charCodeAt(0) | |
| const CLOSE_SQUARE = ']'.charCodeAt(0) | |
| const OPEN_PARENTHESES = '('.charCodeAt(0) | |
| const CLOSE_PARENTHESES = ')'.charCodeAt(0) | |
| const OPEN_CURLY = '{'.charCodeAt(0) | |
| const CLOSE_CURLY = '}'.charCodeAt(0) | |
| const SEMICOLON = ';'.charCodeAt(0) | |
| const ASTERISK = '*'.charCodeAt(0) | |
| const COLON = ':'.charCodeAt(0) | |
| const AT = '@'.charCodeAt(0) | |
| const RE_AT_END = /[\t\n\f\r "#'()/;[\\\]{}]/g | |
| const RE_WORD_END = /[\t\n\f\r !"#'():;@[\\\]{}]|\/(?=\*)/g | |
| const RE_BAD_BRACKET = /.[\n"'(/\\]/ | |
| const RE_HEX_ESCAPE = /[\da-f]/i | |
| module.exports = function tokenizer(input, options = {}) { | |
| let css = input.css.valueOf() | |
| let ignore = options.ignoreErrors | |
| let code, next, quote, content, escape | |
| let escaped, escapePos, prev, n, currentToken | |
| let length = css.length | |
| let pos = 0 | |
| let buffer = [] | |
| let returned = [] | |
| function position() { | |
| return pos | |
| } | |
| function unclosed(what) { | |
| throw input.error('Unclosed ' + what, pos) | |
| } | |
| function endOfFile() { | |
| return returned.length === 0 && pos >= length | |
| } | |
| function nextToken(opts) { | |
| if (returned.length) return returned.pop() | |
| if (pos >= length) return | |
| let ignoreUnclosed = opts ? opts.ignoreUnclosed : false | |
| code = css.charCodeAt(pos) | |
| switch (code) { | |
| case NEWLINE: | |
| case SPACE: | |
| case TAB: | |
| case CR: | |
| case FEED: { | |
| next = pos | |
| do { | |
| next += 1 | |
| code = css.charCodeAt(next) | |
| } while ( | |
| code === SPACE || | |
| code === NEWLINE || | |
| code === TAB || | |
| code === CR || | |
| code === FEED | |
| ) | |
| currentToken = ['space', css.slice(pos, next)] | |
| pos = next - 1 | |
| break | |
| } | |
| case OPEN_SQUARE: | |
| case CLOSE_SQUARE: | |
| case OPEN_CURLY: | |
| case CLOSE_CURLY: | |
| case COLON: | |
| case SEMICOLON: | |
| case CLOSE_PARENTHESES: { | |
| let controlChar = String.fromCharCode(code) | |
| currentToken = [controlChar, controlChar, pos] | |
| break | |
| } | |
| case OPEN_PARENTHESES: { | |
| prev = buffer.length ? buffer.pop()[1] : '' | |
| n = css.charCodeAt(pos + 1) | |
| if ( | |
| prev === 'url' && | |
| n !== SINGLE_QUOTE && | |
| n !== DOUBLE_QUOTE && | |
| n !== SPACE && | |
| n !== NEWLINE && | |
| n !== TAB && | |
| n !== FEED && | |
| n !== CR | |
| ) { | |
| next = pos | |
| do { | |
| escaped = false | |
| next = css.indexOf(')', next + 1) | |
| if (next === -1) { | |
| if (ignore || ignoreUnclosed) { | |
| next = pos | |
| break | |
| } else { | |
| unclosed('bracket') | |
| } | |
| } | |
| escapePos = next | |
| while (css.charCodeAt(escapePos - 1) === BACKSLASH) { | |
| escapePos -= 1 | |
| escaped = !escaped | |
| } | |
| } while (escaped) | |
| currentToken = ['brackets', css.slice(pos, next + 1), pos, next] | |
| pos = next | |
| } else { | |
| next = css.indexOf(')', pos + 1) | |
| content = css.slice(pos, next + 1) | |
| if (next === -1 || RE_BAD_BRACKET.test(content)) { | |
| currentToken = ['(', '(', pos] | |
| } else { | |
| currentToken = ['brackets', content, pos, next] | |
| pos = next | |
| } | |
| } | |
| break | |
| } | |
| case SINGLE_QUOTE: | |
| case DOUBLE_QUOTE: { | |
| quote = code === SINGLE_QUOTE ? "'" : '"' | |
| next = pos | |
| do { | |
| escaped = false | |
| next = css.indexOf(quote, next + 1) | |
| if (next === -1) { | |
| if (ignore || ignoreUnclosed) { | |
| next = pos + 1 | |
| break | |
| } else { | |
| unclosed('string') | |
| } | |
| } | |
| escapePos = next | |
| while (css.charCodeAt(escapePos - 1) === BACKSLASH) { | |
| escapePos -= 1 | |
| escaped = !escaped | |
| } | |
| } while (escaped) | |
| currentToken = ['string', css.slice(pos, next + 1), pos, next] | |
| pos = next | |
| break | |
| } | |
| case AT: { | |
| RE_AT_END.lastIndex = pos + 1 | |
| RE_AT_END.test(css) | |
| if (RE_AT_END.lastIndex === 0) { | |
| next = css.length - 1 | |
| } else { | |
| next = RE_AT_END.lastIndex - 2 | |
| } | |
| currentToken = ['at-word', css.slice(pos, next + 1), pos, next] | |
| pos = next | |
| break | |
| } | |
| case BACKSLASH: { | |
| next = pos | |
| escape = true | |
| while (css.charCodeAt(next + 1) === BACKSLASH) { | |
| next += 1 | |
| escape = !escape | |
| } | |
| code = css.charCodeAt(next + 1) | |
| if ( | |
| escape && | |
| code !== SLASH && | |
| code !== SPACE && | |
| code !== NEWLINE && | |
| code !== TAB && | |
| code !== CR && | |
| code !== FEED | |
| ) { | |
| next += 1 | |
| if (RE_HEX_ESCAPE.test(css.charAt(next))) { | |
| while (RE_HEX_ESCAPE.test(css.charAt(next + 1))) { | |
| next += 1 | |
| } | |
| if (css.charCodeAt(next + 1) === SPACE) { | |
| next += 1 | |
| } | |
| } | |
| } | |
| currentToken = ['word', css.slice(pos, next + 1), pos, next] | |
| pos = next | |
| break | |
| } | |
| default: { | |
| if (code === SLASH && css.charCodeAt(pos + 1) === ASTERISK) { | |
| next = css.indexOf('*/', pos + 2) + 1 | |
| if (next === 0) { | |
| if (ignore || ignoreUnclosed) { | |
| next = css.length | |
| } else { | |
| unclosed('comment') | |
| } | |
| } | |
| currentToken = ['comment', css.slice(pos, next + 1), pos, next] | |
| pos = next | |
| } else { | |
| RE_WORD_END.lastIndex = pos + 1 | |
| RE_WORD_END.test(css) | |
| if (RE_WORD_END.lastIndex === 0) { | |
| next = css.length - 1 | |
| } else { | |
| next = RE_WORD_END.lastIndex - 2 | |
| } | |
| currentToken = ['word', css.slice(pos, next + 1), pos, next] | |
| buffer.push(currentToken) | |
| pos = next | |
| } | |
| break | |
| } | |
| } | |
| pos++ | |
| return currentToken | |
| } | |
| function back(token) { | |
| returned.push(token) | |
| } | |
| return { | |
| back, | |
| nextToken, | |
| endOfFile, | |
| position | |
| } | |
| } | |