/frontend/node_modules/css-tree/dist/csstree.js
https://gitlab.com/sogeta_albazi/books-and-movies · JavaScript · 1656 lines · 1135 code · 321 blank · 200 comment · 202 complexity · 75fc2642ceda38e0a4c622e933bd8d64 MD5 · raw file
- (function (global, factory) {
- typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
- typeof define === 'function' && define.amd ? define(factory) :
- (global = global || self, global.csstree = factory());
- }(this, function () { 'use strict';
- //
- // list
- // ┌──────┐
- // ┌──────────────┼─head │
- // │ │ tail─┼──────────────┐
- // │ └──────┘ │
- // ▼ ▼
- // item item item item
- // ┌──────┐ ┌──────┐ ┌──────┐ ┌──────┐
- // null ◀──┼─prev │◀───┼─prev │◀───┼─prev │◀───┼─prev │
- // │ next─┼───▶│ next─┼───▶│ next─┼───▶│ next─┼──▶ null
- // ├──────┤ ├──────┤ ├──────┤ ├──────┤
- // │ data │ │ data │ │ data │ │ data │
- // └──────┘ └──────┘ └──────┘ └──────┘
- //
- function createItem(data) {
- return {
- prev: null,
- next: null,
- data: data
- };
- }
- function allocateCursor(node, prev, next) {
- var cursor;
- if (cursors !== null) {
- cursor = cursors;
- cursors = cursors.cursor;
- cursor.prev = prev;
- cursor.next = next;
- cursor.cursor = node.cursor;
- } else {
- cursor = {
- prev: prev,
- next: next,
- cursor: node.cursor
- };
- }
- node.cursor = cursor;
- return cursor;
- }
- function releaseCursor(node) {
- var cursor = node.cursor;
- node.cursor = cursor.cursor;
- cursor.prev = null;
- cursor.next = null;
- cursor.cursor = cursors;
- cursors = cursor;
- }
- var cursors = null;
- var List = function() {
- this.cursor = null;
- this.head = null;
- this.tail = null;
- };
- List.createItem = createItem;
- List.prototype.createItem = createItem;
- List.prototype.updateCursors = function(prevOld, prevNew, nextOld, nextNew) {
- var cursor = this.cursor;
- while (cursor !== null) {
- if (cursor.prev === prevOld) {
- cursor.prev = prevNew;
- }
- if (cursor.next === nextOld) {
- cursor.next = nextNew;
- }
- cursor = cursor.cursor;
- }
- };
- List.prototype.getSize = function() {
- var size = 0;
- var cursor = this.head;
- while (cursor) {
- size++;
- cursor = cursor.next;
- }
- return size;
- };
- List.prototype.fromArray = function(array) {
- var cursor = null;
- this.head = null;
- for (var i = 0; i < array.length; i++) {
- var item = createItem(array[i]);
- if (cursor !== null) {
- cursor.next = item;
- } else {
- this.head = item;
- }
- item.prev = cursor;
- cursor = item;
- }
- this.tail = cursor;
- return this;
- };
- List.prototype.toArray = function() {
- var cursor = this.head;
- var result = [];
- while (cursor) {
- result.push(cursor.data);
- cursor = cursor.next;
- }
- return result;
- };
- List.prototype.toJSON = List.prototype.toArray;
- List.prototype.isEmpty = function() {
- return this.head === null;
- };
- List.prototype.first = function() {
- return this.head && this.head.data;
- };
- List.prototype.last = function() {
- return this.tail && this.tail.data;
- };
- List.prototype.each = function(fn, context) {
- var item;
- if (context === undefined) {
- context = this;
- }
- // push cursor
- var cursor = allocateCursor(this, null, this.head);
- while (cursor.next !== null) {
- item = cursor.next;
- cursor.next = item.next;
- fn.call(context, item.data, item, this);
- }
- // pop cursor
- releaseCursor(this);
- };
- List.prototype.forEach = List.prototype.each;
- List.prototype.eachRight = function(fn, context) {
- var item;
- if (context === undefined) {
- context = this;
- }
- // push cursor
- var cursor = allocateCursor(this, this.tail, null);
- while (cursor.prev !== null) {
- item = cursor.prev;
- cursor.prev = item.prev;
- fn.call(context, item.data, item, this);
- }
- // pop cursor
- releaseCursor(this);
- };
- List.prototype.forEachRight = List.prototype.eachRight;
- List.prototype.nextUntil = function(start, fn, context) {
- if (start === null) {
- return;
- }
- var item;
- if (context === undefined) {
- context = this;
- }
- // push cursor
- var cursor = allocateCursor(this, null, start);
- while (cursor.next !== null) {
- item = cursor.next;
- cursor.next = item.next;
- if (fn.call(context, item.data, item, this)) {
- break;
- }
- }
- // pop cursor
- releaseCursor(this);
- };
- List.prototype.prevUntil = function(start, fn, context) {
- if (start === null) {
- return;
- }
- var item;
- if (context === undefined) {
- context = this;
- }
- // push cursor
- var cursor = allocateCursor(this, start, null);
- while (cursor.prev !== null) {
- item = cursor.prev;
- cursor.prev = item.prev;
- if (fn.call(context, item.data, item, this)) {
- break;
- }
- }
- // pop cursor
- releaseCursor(this);
- };
- List.prototype.some = function(fn, context) {
- var cursor = this.head;
- if (context === undefined) {
- context = this;
- }
- while (cursor !== null) {
- if (fn.call(context, cursor.data, cursor, this)) {
- return true;
- }
- cursor = cursor.next;
- }
- return false;
- };
- List.prototype.map = function(fn, context) {
- var result = new List();
- var cursor = this.head;
- if (context === undefined) {
- context = this;
- }
- while (cursor !== null) {
- result.appendData(fn.call(context, cursor.data, cursor, this));
- cursor = cursor.next;
- }
- return result;
- };
- List.prototype.filter = function(fn, context) {
- var result = new List();
- var cursor = this.head;
- if (context === undefined) {
- context = this;
- }
- while (cursor !== null) {
- if (fn.call(context, cursor.data, cursor, this)) {
- result.appendData(cursor.data);
- }
- cursor = cursor.next;
- }
- return result;
- };
- List.prototype.clear = function() {
- this.head = null;
- this.tail = null;
- };
- List.prototype.copy = function() {
- var result = new List();
- var cursor = this.head;
- while (cursor !== null) {
- result.insert(createItem(cursor.data));
- cursor = cursor.next;
- }
- return result;
- };
- List.prototype.prepend = function(item) {
- // head
- // ^
- // item
- this.updateCursors(null, item, this.head, item);
- // insert to the beginning of the list
- if (this.head !== null) {
- // new item <- first item
- this.head.prev = item;
- // new item -> first item
- item.next = this.head;
- } else {
- // if list has no head, then it also has no tail
- // in this case tail points to the new item
- this.tail = item;
- }
- // head always points to new item
- this.head = item;
- return this;
- };
- List.prototype.prependData = function(data) {
- return this.prepend(createItem(data));
- };
- List.prototype.append = function(item) {
- return this.insert(item);
- };
- List.prototype.appendData = function(data) {
- return this.insert(createItem(data));
- };
- List.prototype.insert = function(item, before) {
- if (before !== undefined && before !== null) {
- // prev before
- // ^
- // item
- this.updateCursors(before.prev, item, before, item);
- if (before.prev === null) {
- // insert to the beginning of list
- if (this.head !== before) {
- throw new Error('before doesn\'t belong to list');
- }
- // since head points to before therefore list doesn't empty
- // no need to check tail
- this.head = item;
- before.prev = item;
- item.next = before;
- this.updateCursors(null, item);
- } else {
- // insert between two items
- before.prev.next = item;
- item.prev = before.prev;
- before.prev = item;
- item.next = before;
- }
- } else {
- // tail
- // ^
- // item
- this.updateCursors(this.tail, item, null, item);
- // insert to the ending of the list
- if (this.tail !== null) {
- // last item -> new item
- this.tail.next = item;
- // last item <- new item
- item.prev = this.tail;
- } else {
- // if list has no tail, then it also has no head
- // in this case head points to new item
- this.head = item;
- }
- // tail always points to new item
- this.tail = item;
- }
- return this;
- };
- List.prototype.insertData = function(data, before) {
- return this.insert(createItem(data), before);
- };
- List.prototype.remove = function(item) {
- // item
- // ^
- // prev next
- this.updateCursors(item, item.prev, item, item.next);
- if (item.prev !== null) {
- item.prev.next = item.next;
- } else {
- if (this.head !== item) {
- throw new Error('item doesn\'t belong to list');
- }
- this.head = item.next;
- }
- if (item.next !== null) {
- item.next.prev = item.prev;
- } else {
- if (this.tail !== item) {
- throw new Error('item doesn\'t belong to list');
- }
- this.tail = item.prev;
- }
- item.prev = null;
- item.next = null;
- return item;
- };
- List.prototype.push = function(data) {
- this.insert(createItem(data));
- };
- List.prototype.pop = function() {
- if (this.tail !== null) {
- return this.remove(this.tail);
- }
- };
- List.prototype.unshift = function(data) {
- this.prepend(createItem(data));
- };
- List.prototype.shift = function() {
- if (this.head !== null) {
- return this.remove(this.head);
- }
- };
- List.prototype.prependList = function(list) {
- return this.insertList(list, this.head);
- };
- List.prototype.appendList = function(list) {
- return this.insertList(list);
- };
- List.prototype.insertList = function(list, before) {
- // ignore empty lists
- if (list.head === null) {
- return this;
- }
- if (before !== undefined && before !== null) {
- this.updateCursors(before.prev, list.tail, before, list.head);
- // insert in the middle of dist list
- if (before.prev !== null) {
- // before.prev <-> list.head
- before.prev.next = list.head;
- list.head.prev = before.prev;
- } else {
- this.head = list.head;
- }
- before.prev = list.tail;
- list.tail.next = before;
- } else {
- this.updateCursors(this.tail, list.tail, null, list.head);
- // insert to end of the list
- if (this.tail !== null) {
- // if destination list has a tail, then it also has a head,
- // but head doesn't change
- // dest tail -> source head
- this.tail.next = list.head;
- // dest tail <- source head
- list.head.prev = this.tail;
- } else {
- // if list has no a tail, then it also has no a head
- // in this case points head to new item
- this.head = list.head;
- }
- // tail always start point to new item
- this.tail = list.tail;
- }
- list.head = null;
- list.tail = null;
- return this;
- };
- List.prototype.replace = function(oldItem, newItemOrList) {
- if ('head' in newItemOrList) {
- this.insertList(newItemOrList, oldItem);
- } else {
- this.insert(newItemOrList, oldItem);
- }
- this.remove(oldItem);
- };
- var List_1 = List;
- var createCustomError = function createCustomError(name, message) {
- // use Object.create(), because some VMs prevent setting line/column otherwise
- // (iOS Safari 10 even throws an exception)
- var error = Object.create(SyntaxError.prototype);
- var errorStack = new Error();
- error.name = name;
- error.message = message;
- Object.defineProperty(error, 'stack', {
- get: function() {
- return (errorStack.stack || '').replace(/^(.+\n){1,3}/, name + ': ' + message + '\n');
- }
- });
- return error;
- };
- var MAX_LINE_LENGTH = 100;
- var OFFSET_CORRECTION = 60;
- var TAB_REPLACEMENT = ' ';
- function sourceFragment(error, extraLines) {
- function processLines(start, end) {
- return lines.slice(start, end).map(function(line, idx) {
- var num = String(start + idx + 1);
- while (num.length < maxNumLength) {
- num = ' ' + num;
- }
- return num + ' |' + line;
- }).join('\n');
- }
- var lines = error.source.split(/\r\n?|\n|\f/);
- var line = error.line;
- var column = error.column;
- var startLine = Math.max(1, line - extraLines) - 1;
- var endLine = Math.min(line + extraLines, lines.length + 1);
- var maxNumLength = Math.max(4, String(endLine).length) + 1;
- var cutLeft = 0;
- // column correction according to replaced tab before column
- column += (TAB_REPLACEMENT.length - 1) * (lines[line - 1].substr(0, column - 1).match(/\t/g) || []).length;
- if (column > MAX_LINE_LENGTH) {
- cutLeft = column - OFFSET_CORRECTION + 3;
- column = OFFSET_CORRECTION - 2;
- }
- for (var i = startLine; i <= endLine; i++) {
- if (i >= 0 && i < lines.length) {
- lines[i] = lines[i].replace(/\t/g, TAB_REPLACEMENT);
- lines[i] =
- (cutLeft > 0 && lines[i].length > cutLeft ? '\u2026' : '') +
- lines[i].substr(cutLeft, MAX_LINE_LENGTH - 2) +
- (lines[i].length > cutLeft + MAX_LINE_LENGTH - 1 ? '\u2026' : '');
- }
- }
- return [
- processLines(startLine, line),
- new Array(column + maxNumLength + 2).join('-') + '^',
- processLines(line, endLine)
- ].filter(Boolean).join('\n');
- }
- var SyntaxError$1 = function(message, source, offset, line, column) {
- var error = createCustomError('SyntaxError', message);
- error.source = source;
- error.offset = offset;
- error.line = line;
- error.column = column;
- error.sourceFragment = function(extraLines) {
- return sourceFragment(error, isNaN(extraLines) ? 0 : extraLines);
- };
- Object.defineProperty(error, 'formattedMessage', {
- get: function() {
- return (
- 'Parse error: ' + error.message + '\n' +
- sourceFragment(error, 2)
- );
- }
- });
- // for backward capability
- error.parseError = {
- offset: offset,
- line: line,
- column: column
- };
- return error;
- };
- var _SyntaxError = SyntaxError$1;
- // CSS Syntax Module Level 3
- // https://www.w3.org/TR/css-syntax-3/
- var TYPE = {
- EOF: 0, // <EOF-token>
- Ident: 1, // <ident-token>
- Function: 2, // <function-token>
- AtKeyword: 3, // <at-keyword-token>
- Hash: 4, // <hash-token>
- String: 5, // <string-token>
- BadString: 6, // <bad-string-token>
- Url: 7, // <url-token>
- BadUrl: 8, // <bad-url-token>
- Delim: 9, // <delim-token>
- Number: 10, // <number-token>
- Percentage: 11, // <percentage-token>
- Dimension: 12, // <dimension-token>
- WhiteSpace: 13, // <whitespace-token>
- CDO: 14, // <CDO-token>
- CDC: 15, // <CDC-token>
- Colon: 16, // <colon-token> :
- Semicolon: 17, // <semicolon-token> ;
- Comma: 18, // <comma-token> ,
- LeftSquareBracket: 19, // <[-token>
- RightSquareBracket: 20, // <]-token>
- LeftParenthesis: 21, // <(-token>
- RightParenthesis: 22, // <)-token>
- LeftCurlyBracket: 23, // <{-token>
- RightCurlyBracket: 24, // <}-token>
- Comment: 25
- };
- var NAME = Object.keys(TYPE).reduce(function(result, key) {
- result[TYPE[key]] = key;
- return result;
- }, {});
- var _const = {
- TYPE: TYPE,
- NAME: NAME
- };
- var EOF = 0;
- // https://drafts.csswg.org/css-syntax-3/
- // § 4.2. Definitions
- // digit
- // A code point between U+0030 DIGIT ZERO (0) and U+0039 DIGIT NINE (9).
- function isDigit(code) {
- return code >= 0x0030 && code <= 0x0039;
- }
- // hex digit
- // A digit, or a code point between U+0041 LATIN CAPITAL LETTER A (A) and U+0046 LATIN CAPITAL LETTER F (F),
- // or a code point between U+0061 LATIN SMALL LETTER A (a) and U+0066 LATIN SMALL LETTER F (f).
- function isHexDigit(code) {
- return (
- isDigit(code) || // 0 .. 9
- (code >= 0x0041 && code <= 0x0046) || // A .. F
- (code >= 0x0061 && code <= 0x0066) // a .. f
- );
- }
- // uppercase letter
- // A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z).
- function isUppercaseLetter(code) {
- return code >= 0x0041 && code <= 0x005A;
- }
- // lowercase letter
- // A code point between U+0061 LATIN SMALL LETTER A (a) and U+007A LATIN SMALL LETTER Z (z).
- function isLowercaseLetter(code) {
- return code >= 0x0061 && code <= 0x007A;
- }
- // letter
- // An uppercase letter or a lowercase letter.
- function isLetter(code) {
- return isUppercaseLetter(code) || isLowercaseLetter(code);
- }
- // non-ASCII code point
- // A code point with a value equal to or greater than U+0080 <control>.
- function isNonAscii(code) {
- return code >= 0x0080;
- }
- // name-start code point
- // A letter, a non-ASCII code point, or U+005F LOW LINE (_).
- function isNameStart(code) {
- return isLetter(code) || isNonAscii(code) || code === 0x005F;
- }
- // name code point
- // A name-start code point, a digit, or U+002D HYPHEN-MINUS (-).
- function isName(code) {
- return isNameStart(code) || isDigit(code) || code === 0x002D;
- }
- // non-printable code point
- // A code point between U+0000 NULL and U+0008 BACKSPACE, or U+000B LINE TABULATION,
- // or a code point between U+000E SHIFT OUT and U+001F INFORMATION SEPARATOR ONE, or U+007F DELETE.
- function isNonPrintable(code) {
- return (
- (code >= 0x0000 && code <= 0x0008) ||
- (code === 0x000B) ||
- (code >= 0x000E && code <= 0x001F) ||
- (code === 0x007F)
- );
- }
- // newline
- // U+000A LINE FEED. Note that U+000D CARRIAGE RETURN and U+000C FORM FEED are not included in this definition,
- // as they are converted to U+000A LINE FEED during preprocessing.
- // TODO: we doesn't do a preprocessing, so check a code point for U+000D CARRIAGE RETURN and U+000C FORM FEED
- function isNewline(code) {
- return code === 0x000A || code === 0x000D || code === 0x000C;
- }
- // whitespace
- // A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE.
- function isWhiteSpace(code) {
- return isNewline(code) || code === 0x0020 || code === 0x0009;
- }
- // § 4.3.8. Check if two code points are a valid escape
- function isValidEscape(first, second) {
- // If the first code point is not U+005C REVERSE SOLIDUS (\), return false.
- if (first !== 0x005C) {
- return false;
- }
- // Otherwise, if the second code point is a newline or EOF, return false.
- if (isNewline(second) || second === EOF) {
- return false;
- }
- // Otherwise, return true.
- return true;
- }
- // § 4.3.9. Check if three code points would start an identifier
- function isIdentifierStart(first, second, third) {
- // Look at the first code point:
- // U+002D HYPHEN-MINUS
- if (first === 0x002D) {
- // If the second code point is a name-start code point or a U+002D HYPHEN-MINUS,
- // or the second and third code points are a valid escape, return true. Otherwise, return false.
- return (
- isNameStart(second) ||
- second === 0x002D ||
- isValidEscape(second, third)
- );
- }
- // name-start code point
- if (isNameStart(first)) {
- // Return true.
- return true;
- }
- // U+005C REVERSE SOLIDUS (\)
- if (first === 0x005C) {
- // If the first and second code points are a valid escape, return true. Otherwise, return false.
- return isValidEscape(first, second);
- }
- // anything else
- // Return false.
- return false;
- }
- // § 4.3.10. Check if three code points would start a number
- function isNumberStart(first, second, third) {
- // Look at the first code point:
- // U+002B PLUS SIGN (+)
- // U+002D HYPHEN-MINUS (-)
- if (first === 0x002B || first === 0x002D) {
- // If the second code point is a digit, return true.
- if (isDigit(second)) {
- return 2;
- }
- // Otherwise, if the second code point is a U+002E FULL STOP (.)
- // and the third code point is a digit, return true.
- // Otherwise, return false.
- return second === 0x002E && isDigit(third) ? 3 : 0;
- }
- // U+002E FULL STOP (.)
- if (first === 0x002E) {
- // If the second code point is a digit, return true. Otherwise, return false.
- return isDigit(second) ? 2 : 0;
- }
- // digit
- if (isDigit(first)) {
- // Return true.
- return 1;
- }
- // anything else
- // Return false.
- return 0;
- }
- //
- // Misc
- //
- // detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
- function isBOM(code) {
- // UTF-16BE
- if (code === 0xFEFF) {
- return 1;
- }
- // UTF-16LE
- if (code === 0xFFFE) {
- return 1;
- }
- return 0;
- }
- // Fast code category
- //
- // https://drafts.csswg.org/css-syntax/#tokenizer-definitions
- // > non-ASCII code point
- // > A code point with a value equal to or greater than U+0080 <control>
- // > name-start code point
- // > A letter, a non-ASCII code point, or U+005F LOW LINE (_).
- // > name code point
- // > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-)
- // That means only ASCII code points has a special meaning and we define a maps for 0..127 codes only
- var CATEGORY = new Array(0x80);
- charCodeCategory.Eof = 0x80;
- charCodeCategory.WhiteSpace = 0x82;
- charCodeCategory.Digit = 0x83;
- charCodeCategory.NameStart = 0x84;
- charCodeCategory.NonPrintable = 0x85;
- for (var i = 0; i < CATEGORY.length; i++) {
- switch (true) {
- case isWhiteSpace(i):
- CATEGORY[i] = charCodeCategory.WhiteSpace;
- break;
- case isDigit(i):
- CATEGORY[i] = charCodeCategory.Digit;
- break;
- case isNameStart(i):
- CATEGORY[i] = charCodeCategory.NameStart;
- break;
- case isNonPrintable(i):
- CATEGORY[i] = charCodeCategory.NonPrintable;
- break;
- default:
- CATEGORY[i] = i || charCodeCategory.Eof;
- }
- }
- function charCodeCategory(code) {
- return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart;
- }
- var charCodeDefinitions = {
- isDigit: isDigit,
- isHexDigit: isHexDigit,
- isUppercaseLetter: isUppercaseLetter,
- isLowercaseLetter: isLowercaseLetter,
- isLetter: isLetter,
- isNonAscii: isNonAscii,
- isNameStart: isNameStart,
- isName: isName,
- isNonPrintable: isNonPrintable,
- isNewline: isNewline,
- isWhiteSpace: isWhiteSpace,
- isValidEscape: isValidEscape,
- isIdentifierStart: isIdentifierStart,
- isNumberStart: isNumberStart,
- isBOM: isBOM,
- charCodeCategory: charCodeCategory
- };
- var isDigit$1 = charCodeDefinitions.isDigit;
- var isHexDigit$1 = charCodeDefinitions.isHexDigit;
- var isUppercaseLetter$1 = charCodeDefinitions.isUppercaseLetter;
- var isName$1 = charCodeDefinitions.isName;
- var isWhiteSpace$1 = charCodeDefinitions.isWhiteSpace;
- var isValidEscape$1 = charCodeDefinitions.isValidEscape;
- function getCharCode(source, offset) {
- return offset < source.length ? source.charCodeAt(offset) : 0;
- }
- function getNewlineLength(source, offset, code) {
- if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) {
- return 2;
- }
- return 1;
- }
- function cmpChar(testStr, offset, referenceCode) {
- var code = testStr.charCodeAt(offset);
- // code.toLowerCase() for A..Z
- if (isUppercaseLetter$1(code)) {
- code = code | 32;
- }
- return code === referenceCode;
- }
- function cmpStr(testStr, start, end, referenceStr) {
- if (end - start !== referenceStr.length) {
- return false;
- }
- if (start < 0 || end > testStr.length) {
- return false;
- }
- for (var i = start; i < end; i++) {
- var testCode = testStr.charCodeAt(i);
- var referenceCode = referenceStr.charCodeAt(i - start);
- // testCode.toLowerCase() for A..Z
- if (isUppercaseLetter$1(testCode)) {
- testCode = testCode | 32;
- }
- if (testCode !== referenceCode) {
- return false;
- }
- }
- return true;
- }
- function findWhiteSpaceStart(source, offset) {
- for (; offset >= 0; offset--) {
- if (!isWhiteSpace$1(source.charCodeAt(offset))) {
- break;
- }
- }
- return offset + 1;
- }
- function findWhiteSpaceEnd(source, offset) {
- for (; offset < source.length; offset++) {
- if (!isWhiteSpace$1(source.charCodeAt(offset))) {
- break;
- }
- }
- return offset;
- }
- function findDecimalNumberEnd(source, offset) {
- for (; offset < source.length; offset++) {
- if (!isDigit$1(source.charCodeAt(offset))) {
- break;
- }
- }
- return offset;
- }
- // § 4.3.7. Consume an escaped code point
- function consumeEscaped(source, offset) {
- // It assumes that the U+005C REVERSE SOLIDUS (\) has already been consumed and
- // that the next input code point has already been verified to be part of a valid escape.
- offset += 2;
- // hex digit
- if (isHexDigit$1(getCharCode(source, offset - 1))) {
- // Consume as many hex digits as possible, but no more than 5.
- // Note that this means 1-6 hex digits have been consumed in total.
- for (var maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) {
- if (!isHexDigit$1(getCharCode(source, offset))) {
- break;
- }
- }
- // If the next input code point is whitespace, consume it as well.
- var code = getCharCode(source, offset);
- if (isWhiteSpace$1(code)) {
- offset += getNewlineLength(source, offset, code);
- }
- }
- return offset;
- }
- // §4.3.11. Consume a name
- // Note: This algorithm does not do the verification of the first few code points that are necessary
- // to ensure the returned code points would constitute an <ident-token>. If that is the intended use,
- // ensure that the stream starts with an identifier before calling this algorithm.
- function consumeName(source, offset) {
- // Let result initially be an empty string.
- // Repeatedly consume the next input code point from the stream:
- for (; offset < source.length; offset++) {
- var code = source.charCodeAt(offset);
- // name code point
- if (isName$1(code)) {
- // Append the code point to result.
- continue;
- }
- // the stream starts with a valid escape
- if (isValidEscape$1(code, getCharCode(source, offset + 1))) {
- // Consume an escaped code point. Append the returned code point to result.
- offset = consumeEscaped(source, offset) - 1;
- continue;
- }
- // anything else
- // Reconsume the current input code point. Return result.
- break;
- }
- return offset;
- }
- // §4.3.12. Consume a number
- function consumeNumber(source, offset) {
- var code = source.charCodeAt(offset);
- // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-),
- // consume it and append it to repr.
- if (code === 0x002B || code === 0x002D) {
- code = source.charCodeAt(offset += 1);
- }
- // 3. While the next input code point is a digit, consume it and append it to repr.
- if (isDigit$1(code)) {
- offset = findDecimalNumberEnd(source, offset + 1);
- code = source.charCodeAt(offset);
- }
- // 4. If the next 2 input code points are U+002E FULL STOP (.) followed by a digit, then:
- if (code === 0x002E && isDigit$1(source.charCodeAt(offset + 1))) {
- // 4.1 Consume them.
- // 4.2 Append them to repr.
- code = source.charCodeAt(offset += 2);
- // 4.3 Set type to "number".
- // TODO
- // 4.4 While the next input code point is a digit, consume it and append it to repr.
- offset = findDecimalNumberEnd(source, offset);
- }
- // 5. If the next 2 or 3 input code points are U+0045 LATIN CAPITAL LETTER E (E)
- // or U+0065 LATIN SMALL LETTER E (e), ... , followed by a digit, then:
- if (cmpChar(source, offset, 101 /* e */)) {
- var sign = 0;
- code = source.charCodeAt(offset + 1);
- // ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ...
- if (code === 0x002D || code === 0x002B) {
- sign = 1;
- code = source.charCodeAt(offset + 2);
- }
- // ... followed by a digit
- if (isDigit$1(code)) {
- // 5.1 Consume them.
- // 5.2 Append them to repr.
- // 5.3 Set type to "number".
- // TODO
- // 5.4 While the next input code point is a digit, consume it and append it to repr.
- offset = findDecimalNumberEnd(source, offset + 1 + sign + 1);
- }
- }
- return offset;
- }
- // § 4.3.14. Consume the remnants of a bad url
- // ... its sole use is to consume enough of the input stream to reach a recovery point
- // where normal tokenizing can resume.
- function consumeBadUrlRemnants(source, offset) {
- // Repeatedly consume the next input code point from the stream:
- for (; offset < source.length; offset++) {
- var code = source.charCodeAt(offset);
- // U+0029 RIGHT PARENTHESIS ())
- // EOF
- if (code === 0x0029) {
- // Return.
- offset++;
- break;
- }
- if (isValidEscape$1(code, getCharCode(source, offset + 1))) {
- // Consume an escaped code point.
- // Note: This allows an escaped right parenthesis ("\)") to be encountered
- // without ending the <bad-url-token>. This is otherwise identical to
- // the "anything else" clause.
- offset = consumeEscaped(source, offset);
- }
- }
- return offset;
- }
- var utils = {
- consumeEscaped: consumeEscaped,
- consumeName: consumeName,
- consumeNumber: consumeNumber,
- consumeBadUrlRemnants: consumeBadUrlRemnants,
- cmpChar: cmpChar,
- cmpStr: cmpStr,
- getNewlineLength: getNewlineLength,
- findWhiteSpaceStart: findWhiteSpaceStart,
- findWhiteSpaceEnd: findWhiteSpaceEnd
- };
- var TYPE$1 = _const.TYPE;
- var NAME$1 = _const.NAME;
- var cmpStr$1 = utils.cmpStr;
- var EOF$1 = TYPE$1.EOF;
- var WHITESPACE = TYPE$1.WhiteSpace;
- var COMMENT = TYPE$1.Comment;
- var OFFSET_MASK = 0x00FFFFFF;
- var TYPE_SHIFT = 24;
- var TokenStream = function() {
- this.offsetAndType = null;
- this.balance = null;
- this.reset();
- };
- TokenStream.prototype = {
- reset: function() {
- this.eof = false;
- this.tokenIndex = -1;
- this.tokenType = 0;
- this.tokenStart = this.firstCharOffset;
- this.tokenEnd = this.firstCharOffset;
- },
- lookupType: function(offset) {
- offset += this.tokenIndex;
- if (offset < this.tokenCount) {
- return this.offsetAndType[offset] >> TYPE_SHIFT;
- }
- return EOF$1;
- },
- lookupOffset: function(offset) {
- offset += this.tokenIndex;
- if (offset < this.tokenCount) {
- return this.offsetAndType[offset - 1] & OFFSET_MASK;
- }
- return this.source.length;
- },
- lookupValue: function(offset, referenceStr) {
- offset += this.tokenIndex;
- if (offset < this.tokenCount) {
- return cmpStr$1(
- this.source,
- this.offsetAndType[offset - 1] & OFFSET_MASK,
- this.offsetAndType[offset] & OFFSET_MASK,
- referenceStr
- );
- }
- return false;
- },
- getTokenStart: function(tokenIndex) {
- if (tokenIndex === this.tokenIndex) {
- return this.tokenStart;
- }
- if (tokenIndex > 0) {
- return tokenIndex < this.tokenCount
- ? this.offsetAndType[tokenIndex - 1] & OFFSET_MASK
- : this.offsetAndType[this.tokenCount] & OFFSET_MASK;
- }
- return this.firstCharOffset;
- },
- // TODO: -> skipUntilBalanced
- getRawLength: function(startToken, mode) {
- var cursor = startToken;
- var balanceEnd;
- var offset = this.offsetAndType[Math.max(cursor - 1, 0)] & OFFSET_MASK;
- var type;
- loop:
- for (; cursor < this.tokenCount; cursor++) {
- balanceEnd = this.balance[cursor];
- // stop scanning on balance edge that points to offset before start token
- if (balanceEnd < startToken) {
- break loop;
- }
- type = this.offsetAndType[cursor] >> TYPE_SHIFT;
- // check token is stop type
- switch (mode(type, this.source, offset)) {
- case 1:
- break loop;
- case 2:
- cursor++;
- break loop;
- default:
- offset = this.offsetAndType[cursor] & OFFSET_MASK;
- // fast forward to the end of balanced block
- if (this.balance[balanceEnd] === cursor) {
- cursor = balanceEnd;
- }
- }
- }
- return cursor - this.tokenIndex;
- },
- isBalanceEdge: function(pos) {
- return this.balance[this.tokenIndex] < pos;
- },
- isDelim: function(code, offset) {
- if (offset) {
- return (
- this.lookupType(offset) === TYPE$1.Delim &&
- this.source.charCodeAt(this.lookupOffset(offset)) === code
- );
- }
- return (
- this.tokenType === TYPE$1.Delim &&
- this.source.charCodeAt(this.tokenStart) === code
- );
- },
- getTokenValue: function() {
- return this.source.substring(this.tokenStart, this.tokenEnd);
- },
- getTokenLength: function() {
- return this.tokenEnd - this.tokenStart;
- },
- substrToCursor: function(start) {
- return this.source.substring(start, this.tokenStart);
- },
- skipWS: function() {
- for (var i = this.tokenIndex, skipTokenCount = 0; i < this.tokenCount; i++, skipTokenCount++) {
- if ((this.offsetAndType[i] >> TYPE_SHIFT) !== WHITESPACE) {
- break;
- }
- }
- if (skipTokenCount > 0) {
- this.skip(skipTokenCount);
- }
- },
- skipSC: function() {
- while (this.tokenType === WHITESPACE || this.tokenType === COMMENT) {
- this.next();
- }
- },
- skip: function(tokenCount) {
- var next = this.tokenIndex + tokenCount;
- if (next < this.tokenCount) {
- this.tokenIndex = next;
- this.tokenStart = this.offsetAndType[next - 1] & OFFSET_MASK;
- next = this.offsetAndType[next];
- this.tokenType = next >> TYPE_SHIFT;
- this.tokenEnd = next & OFFSET_MASK;
- } else {
- this.tokenIndex = this.tokenCount;
- this.next();
- }
- },
- next: function() {
- var next = this.tokenIndex + 1;
- if (next < this.tokenCount) {
- this.tokenIndex = next;
- this.tokenStart = this.tokenEnd;
- next = this.offsetAndType[next];
- this.tokenType = next >> TYPE_SHIFT;
- this.tokenEnd = next & OFFSET_MASK;
- } else {
- this.tokenIndex = this.tokenCount;
- this.eof = true;
- this.tokenType = EOF$1;
- this.tokenStart = this.tokenEnd = this.source.length;
- }
- },
- dump: function() {
- var offset = this.firstCharOffset;
- return Array.prototype.slice.call(this.offsetAndType, 0, this.tokenCount).map(function(item, idx) {
- var start = offset;
- var end = item & OFFSET_MASK;
- offset = end;
- return {
- idx: idx,
- type: NAME$1[item >> TYPE_SHIFT],
- chunk: this.source.substring(start, end),
- balance: this.balance[idx]
- };
- }, this);
- }
- };
- var TokenStream_1 = TokenStream;
- function noop(value) {
- return value;
- }
- function generateMultiplier(multiplier) {
- if (multiplier.min === 0 && multiplier.max === 0) {
- return '*';
- }
- if (multiplier.min === 0 && multiplier.max === 1) {
- return '?';
- }
- if (multiplier.min === 1 && multiplier.max === 0) {
- return multiplier.comma ? '#' : '+';
- }
- if (multiplier.min === 1 && multiplier.max === 1) {
- return '';
- }
- return (
- (multiplier.comma ? '#' : '') +
- (multiplier.min === multiplier.max
- ? '{' + multiplier.min + '}'
- : '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}'
- )
- );
- }
- function generateTypeOpts(node) {
- switch (node.type) {
- case 'Range':
- return (
- ' [' +
- (node.min === null ? '-∞' : node.min) +
- ',' +
- (node.max === null ? '∞' : node.max) +
- ']'
- );
- default:
- throw new Error('Unknown node type `' + node.type + '`');
- }
- }
- function generateSequence(node, decorate, forceBraces, compact) {
- var combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' ';
- var result = node.terms.map(function(term) {
- return generate(term, decorate, forceBraces, compact);
- }).join(combinator);
- if (node.explicit || forceBraces) {
- result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
- }
- return result;
- }
- function generate(node, decorate, forceBraces, compact) {
- var result;
- switch (node.type) {
- case 'Group':
- result =
- generateSequence(node, decorate, forceBraces, compact) +
- (node.disallowEmpty ? '!' : '');
- break;
- case 'Multiplier':
- // return since node is a composition
- return (
- generate(node.term, decorate, forceBraces, compact) +
- decorate(generateMultiplier(node), node)
- );
- case 'Type':
- result = '<' + node.name + (node.opts ? decorate(generateTypeOpts(node.opts), node.opts) : '') + '>';
- break;
- case 'Property':
- result = '<\'' + node.name + '\'>';
- break;
- case 'Keyword':
- result = node.name;
- break;
- case 'AtKeyword':
- result = '@' + node.name;
- break;
- case 'Function':
- result = node.name + '(';
- break;
- case 'String':
- case 'Token':
- result = node.value;
- break;
- case 'Comma':
- result = ',';
- break;
- default:
- throw new Error('Unknown node type `' + node.type + '`');
- }
- return decorate(result, node);
- }
- var generate_1 = function(node, options) {
- var decorate = noop;
- var forceBraces = false;
- var compact = false;
- if (typeof options === 'function') {
- decorate = options;
- } else if (options) {
- forceBraces = Boolean(options.forceBraces);
- compact = Boolean(options.compact);
- if (typeof options.decorate === 'function') {
- decorate = options.decorate;
- }
- }
- return generate(node, decorate, forceBraces, compact);
- };
- function fromMatchResult(matchResult) {
- var tokens = matchResult.tokens;
- var longestMatch = matchResult.longestMatch;
- var node = longestMatch < tokens.length ? tokens[longestMatch].node : null;
- var mismatchOffset = -1;
- var entries = 0;
- var css = '';
- for (var i = 0; i < tokens.length; i++) {
- if (i === longestMatch) {
- mismatchOffset = css.length;
- }
- if (node !== null && tokens[i].node === node) {
- if (i <= longestMatch) {
- entries++;
- } else {
- entries = 0;
- }
- }
- css += tokens[i].value;
- }
- return {
- node: node,
- css: css,
- mismatchOffset: mismatchOffset === -1 ? css.length : mismatchOffset,
- last: node === null || entries > 1
- };
- }
- function getLocation(node, point) {
- var loc = node && node.loc && node.loc[point];
- if (loc) {
- return {
- offset: loc.offset,
- line: loc.line,
- column: loc.column
- };
- }
- return null;
- }
- var SyntaxReferenceError = function(type, referenceName) {
- var error = createCustomError(
- 'SyntaxReferenceError',
- type + (referenceName ? ' `' + referenceName + '`' : '')
- );
- error.reference = referenceName;
- return error;
- };
- var MatchError = function(message, syntax, node, matchResult) {
- var error = createCustomError('SyntaxMatchError', message);
- var details = fromMatchResult(matchResult);
- var mismatchOffset = details.mismatchOffset || 0;
- var badNode = details.node || node;
- var end = getLocation(badNode, 'end');
- var start = details.last ? end : getLocation(badNode, 'start');
- var css = details.css;
- error.rawMessage = message;
- error.syntax = syntax ? generate_1(syntax) : '<generic>';
- error.css = css;
- error.mismatchOffset = mismatchOffset;
- error.loc = {
- source: (badNode && badNode.loc && badNode.loc.source) || '<unknown>',
- start: start,
- end: end
- };
- error.line = start ? start.line : undefined;
- error.column = start ? start.column : undefined;
- error.offset = start ? start.offset : undefined;
- error.message = message + '\n' +
- ' syntax: ' + error.syntax + '\n' +
- ' value: ' + (error.css || '<empty string>') + '\n' +
- ' --------' + new Array(error.mismatchOffset + 1).join('-') + '^';
- return error;
- };
- var error = {
- SyntaxReferenceError: SyntaxReferenceError,
- MatchError: MatchError
- };
- var hasOwnProperty = Object.prototype.hasOwnProperty;
- var keywords = Object.create(null);
- var properties = Object.create(null);
- var HYPHENMINUS = 45; // '-'.charCodeAt()
- function isCustomProperty(str, offset) {
- offset = offset || 0;
- return str.length - offset >= 2 &&
- str.charCodeAt(offset) === HYPHENMINUS &&
- str.charCodeAt(offset + 1) === HYPHENMINUS;
- }
- function getVendorPrefix(str, offset) {
- offset = offset || 0;
- // verdor prefix should be at least 3 chars length
- if (str.length - offset >= 3) {
- // vendor prefix starts with hyper minus following non-hyper minus
- if (str.charCodeAt(offset) === HYPHENMINUS &&
- str.charCodeAt(offset + 1) !== HYPHENMINUS) {
- // vendor prefix should contain a hyper minus at the ending
- var secondDashIndex = str.indexOf('-', offset + 2);
- if (secondDashIndex !== -1) {
- return str.substring(offset, secondDashIndex + 1);
- }
- }
- }
- return '';
- }
- function getKeywordDescriptor(keyword) {
- if (hasOwnProperty.call(keywords, keyword)) {
- return keywords[keyword];
- }
- var name = keyword.toLowerCase();
- if (hasOwnProperty.call(keywords, name)) {
- return keywords[keyword] = keywords[name];
- }
- var custom = isCustomProperty(name, 0);
- var vendor = !custom ? getVendorPrefix(name, 0) : '';
- return keywords[keyword] = Object.freeze({
- basename: name.substr(vendor.length),
- name: name,
- vendor: vendor,
- prefix: vendor,
- custom: custom
- });
- }
- function getPropertyDescriptor(property) {
- if (hasOwnProperty.call(p