first commit
This commit is contained in:
627
build/node_modules/css-tree/lib/tokenizer/Tokenizer.js
generated
vendored
Normal file
627
build/node_modules/css-tree/lib/tokenizer/Tokenizer.js
generated
vendored
Normal file
@@ -0,0 +1,627 @@
|
||||
'use strict';
|
||||
|
||||
var CssSyntaxError = require('./error');
|
||||
|
||||
var constants = require('./const');
|
||||
var TYPE = constants.TYPE;
|
||||
var NAME = constants.NAME;
|
||||
var SYMBOL_TYPE = constants.SYMBOL_TYPE;
|
||||
|
||||
var utils = require('./utils');
|
||||
var firstCharOffset = utils.firstCharOffset;
|
||||
var cmpStr = utils.cmpStr;
|
||||
var isNumber = utils.isNumber;
|
||||
var findLastNonSpaceLocation = utils.findLastNonSpaceLocation;
|
||||
var findWhiteSpaceEnd = utils.findWhiteSpaceEnd;
|
||||
var findCommentEnd = utils.findCommentEnd;
|
||||
var findStringEnd = utils.findStringEnd;
|
||||
var findNumberEnd = utils.findNumberEnd;
|
||||
var findIdentifierEnd = utils.findIdentifierEnd;
|
||||
var findUrlRawEnd = utils.findUrlRawEnd;
|
||||
|
||||
var NULL = 0;
|
||||
var WHITESPACE = TYPE.WhiteSpace;
|
||||
var IDENTIFIER = TYPE.Identifier;
|
||||
var NUMBER = TYPE.Number;
|
||||
var STRING = TYPE.String;
|
||||
var COMMENT = TYPE.Comment;
|
||||
var PUNCTUATOR = TYPE.Punctuator;
|
||||
var CDO = TYPE.CDO;
|
||||
var CDC = TYPE.CDC;
|
||||
var ATRULE = TYPE.Atrule;
|
||||
var FUNCTION = TYPE.Function;
|
||||
var URL = TYPE.Url;
|
||||
var RAW = TYPE.Raw;
|
||||
|
||||
var N = 10;
|
||||
var F = 12;
|
||||
var R = 13;
|
||||
var STAR = TYPE.Asterisk;
|
||||
var SLASH = TYPE.Solidus;
|
||||
var FULLSTOP = TYPE.FullStop;
|
||||
var PLUSSIGN = TYPE.PlusSign;
|
||||
var HYPHENMINUS = TYPE.HyphenMinus;
|
||||
var GREATERTHANSIGN = TYPE.GreaterThanSign;
|
||||
var LESSTHANSIGN = TYPE.LessThanSign;
|
||||
var EXCLAMATIONMARK = TYPE.ExclamationMark;
|
||||
var COMMERCIALAT = TYPE.CommercialAt;
|
||||
var QUOTATIONMARK = TYPE.QuotationMark;
|
||||
var APOSTROPHE = TYPE.Apostrophe;
|
||||
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
|
||||
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
|
||||
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
|
||||
var RIGHTCURLYBRACKET = TYPE.RightCurlyBracket;
|
||||
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;
|
||||
var RIGHTSQUAREBRACKET = TYPE.RightSquareBracket;
|
||||
|
||||
var MIN_BUFFER_SIZE = 16 * 1024;
|
||||
var OFFSET_MASK = 0x00FFFFFF;
|
||||
var TYPE_SHIFT = 24;
|
||||
var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported
|
||||
|
||||
function computeLinesAndColumns(tokenizer, source) {
|
||||
var sourceLength = source.length;
|
||||
var start = firstCharOffset(source);
|
||||
var lines = tokenizer.lines;
|
||||
var line = tokenizer.startLine;
|
||||
var columns = tokenizer.columns;
|
||||
var column = tokenizer.startColumn;
|
||||
|
||||
if (lines === null || lines.length < sourceLength + 1) {
|
||||
lines = new SafeUint32Array(Math.max(sourceLength + 1024, MIN_BUFFER_SIZE));
|
||||
columns = new SafeUint32Array(lines.length);
|
||||
}
|
||||
|
||||
for (var i = start; i < sourceLength; i++) {
|
||||
var code = source.charCodeAt(i);
|
||||
|
||||
lines[i] = line;
|
||||
columns[i] = column++;
|
||||
|
||||
if (code === N || code === R || code === F) {
|
||||
if (code === R && i + 1 < sourceLength && source.charCodeAt(i + 1) === N) {
|
||||
i++;
|
||||
lines[i] = line;
|
||||
columns[i] = column;
|
||||
}
|
||||
|
||||
line++;
|
||||
column = 1;
|
||||
}
|
||||
}
|
||||
|
||||
lines[i] = line;
|
||||
columns[i] = column;
|
||||
|
||||
tokenizer.linesAnsColumnsComputed = true;
|
||||
tokenizer.lines = lines;
|
||||
tokenizer.columns = columns;
|
||||
}
|
||||
|
||||
function tokenLayout(tokenizer, source, startPos) {
|
||||
var sourceLength = source.length;
|
||||
var offsetAndType = tokenizer.offsetAndType;
|
||||
var balance = tokenizer.balance;
|
||||
var tokenCount = 0;
|
||||
var prevType = 0;
|
||||
var offset = startPos;
|
||||
var anchor = 0;
|
||||
var balanceCloseCode = 0;
|
||||
var balanceStart = 0;
|
||||
var balancePrev = 0;
|
||||
|
||||
if (offsetAndType === null || offsetAndType.length < sourceLength + 1) {
|
||||
offsetAndType = new SafeUint32Array(sourceLength + 1024);
|
||||
balance = new SafeUint32Array(sourceLength + 1024);
|
||||
}
|
||||
|
||||
while (offset < sourceLength) {
|
||||
var code = source.charCodeAt(offset);
|
||||
var type = code < 0x80 ? SYMBOL_TYPE[code] : IDENTIFIER;
|
||||
|
||||
balance[tokenCount] = sourceLength;
|
||||
|
||||
switch (type) {
|
||||
case WHITESPACE:
|
||||
offset = findWhiteSpaceEnd(source, offset + 1);
|
||||
break;
|
||||
|
||||
case PUNCTUATOR:
|
||||
switch (code) {
|
||||
case balanceCloseCode:
|
||||
balancePrev = balanceStart & OFFSET_MASK;
|
||||
balanceStart = balance[balancePrev];
|
||||
balanceCloseCode = balanceStart >> TYPE_SHIFT;
|
||||
balance[tokenCount] = balancePrev;
|
||||
balance[balancePrev++] = tokenCount;
|
||||
for (; balancePrev < tokenCount; balancePrev++) {
|
||||
if (balance[balancePrev] === sourceLength) {
|
||||
balance[balancePrev] = tokenCount;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case LEFTSQUAREBRACKET:
|
||||
balance[tokenCount] = balanceStart;
|
||||
balanceCloseCode = RIGHTSQUAREBRACKET;
|
||||
balanceStart = (balanceCloseCode << TYPE_SHIFT) | tokenCount;
|
||||
break;
|
||||
|
||||
case LEFTCURLYBRACKET:
|
||||
balance[tokenCount] = balanceStart;
|
||||
balanceCloseCode = RIGHTCURLYBRACKET;
|
||||
balanceStart = (balanceCloseCode << TYPE_SHIFT) | tokenCount;
|
||||
break;
|
||||
|
||||
case LEFTPARENTHESIS:
|
||||
balance[tokenCount] = balanceStart;
|
||||
balanceCloseCode = RIGHTPARENTHESIS;
|
||||
balanceStart = (balanceCloseCode << TYPE_SHIFT) | tokenCount;
|
||||
break;
|
||||
}
|
||||
|
||||
// /*
|
||||
if (code === STAR && prevType === SLASH) {
|
||||
type = COMMENT;
|
||||
offset = findCommentEnd(source, offset + 1);
|
||||
tokenCount--; // rewrite prev token
|
||||
break;
|
||||
}
|
||||
|
||||
// edge case for -.123 and +.123
|
||||
if (code === FULLSTOP && (prevType === PLUSSIGN || prevType === HYPHENMINUS)) {
|
||||
if (offset + 1 < sourceLength && isNumber(source.charCodeAt(offset + 1))) {
|
||||
type = NUMBER;
|
||||
offset = findNumberEnd(source, offset + 2, false);
|
||||
tokenCount--; // rewrite prev token
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// <!--
|
||||
if (code === EXCLAMATIONMARK && prevType === LESSTHANSIGN) {
|
||||
if (offset + 2 < sourceLength &&
|
||||
source.charCodeAt(offset + 1) === HYPHENMINUS &&
|
||||
source.charCodeAt(offset + 2) === HYPHENMINUS) {
|
||||
type = CDO;
|
||||
offset = offset + 3;
|
||||
tokenCount--; // rewrite prev token
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// -->
|
||||
if (code === HYPHENMINUS && prevType === HYPHENMINUS) {
|
||||
if (offset + 1 < sourceLength && source.charCodeAt(offset + 1) === GREATERTHANSIGN) {
|
||||
type = CDC;
|
||||
offset = offset + 2;
|
||||
tokenCount--; // rewrite prev token
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// ident(
|
||||
if (code === LEFTPARENTHESIS && prevType === IDENTIFIER) {
|
||||
offset = offset + 1;
|
||||
tokenCount--; // rewrite prev token
|
||||
balance[tokenCount] = balance[tokenCount + 1];
|
||||
balanceStart--;
|
||||
|
||||
// 4 char length identifier and equal to `url(` (case insensitive)
|
||||
if (offset - anchor === 4 && cmpStr(source, anchor, offset, 'url(')) {
|
||||
// special case for url() because it can contain any symbols sequence with few exceptions
|
||||
anchor = findWhiteSpaceEnd(source, offset);
|
||||
code = source.charCodeAt(anchor);
|
||||
if (code !== LEFTPARENTHESIS &&
|
||||
code !== RIGHTPARENTHESIS &&
|
||||
code !== QUOTATIONMARK &&
|
||||
code !== APOSTROPHE) {
|
||||
// url(
|
||||
offsetAndType[tokenCount++] = (URL << TYPE_SHIFT) | offset;
|
||||
balance[tokenCount] = sourceLength;
|
||||
|
||||
// ws*
|
||||
if (anchor !== offset) {
|
||||
offsetAndType[tokenCount++] = (WHITESPACE << TYPE_SHIFT) | anchor;
|
||||
balance[tokenCount] = sourceLength;
|
||||
}
|
||||
|
||||
// raw
|
||||
type = RAW;
|
||||
offset = findUrlRawEnd(source, anchor);
|
||||
} else {
|
||||
type = URL;
|
||||
}
|
||||
} else {
|
||||
type = FUNCTION;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
type = code;
|
||||
offset = offset + 1;
|
||||
break;
|
||||
|
||||
case NUMBER:
|
||||
offset = findNumberEnd(source, offset + 1, prevType !== FULLSTOP);
|
||||
|
||||
// merge number with a preceding dot, dash or plus
|
||||
if (prevType === FULLSTOP ||
|
||||
prevType === HYPHENMINUS ||
|
||||
prevType === PLUSSIGN) {
|
||||
tokenCount--; // rewrite prev token
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case STRING:
|
||||
offset = findStringEnd(source, offset + 1, code);
|
||||
break;
|
||||
|
||||
default:
|
||||
anchor = offset;
|
||||
offset = findIdentifierEnd(source, offset);
|
||||
|
||||
// merge identifier with a preceding dash
|
||||
if (prevType === HYPHENMINUS) {
|
||||
// rewrite prev token
|
||||
tokenCount--;
|
||||
// restore prev prev token type
|
||||
// for case @-prefix-ident
|
||||
prevType = tokenCount === 0 ? 0 : offsetAndType[tokenCount - 1] >> TYPE_SHIFT;
|
||||
}
|
||||
|
||||
if (prevType === COMMERCIALAT) {
|
||||
// rewrite prev token and change type to <at-keyword-token>
|
||||
tokenCount--;
|
||||
type = ATRULE;
|
||||
}
|
||||
}
|
||||
|
||||
offsetAndType[tokenCount++] = (type << TYPE_SHIFT) | offset;
|
||||
prevType = type;
|
||||
}
|
||||
|
||||
// finalize arrays
|
||||
offsetAndType[tokenCount] = offset;
|
||||
balance[tokenCount] = sourceLength;
|
||||
balance[sourceLength] = sourceLength; // prevents false positive balance match with any token
|
||||
while (balanceStart !== 0) {
|
||||
balancePrev = balanceStart & OFFSET_MASK;
|
||||
balanceStart = balance[balancePrev];
|
||||
balance[balancePrev] = sourceLength;
|
||||
}
|
||||
|
||||
tokenizer.offsetAndType = offsetAndType;
|
||||
tokenizer.tokenCount = tokenCount;
|
||||
tokenizer.balance = balance;
|
||||
}
|
||||
|
||||
//
|
||||
// tokenizer
|
||||
//
|
||||
|
||||
var Tokenizer = function(source, startOffset, startLine, startColumn) {
|
||||
this.offsetAndType = null;
|
||||
this.balance = null;
|
||||
this.lines = null;
|
||||
this.columns = null;
|
||||
|
||||
this.setSource(source, startOffset, startLine, startColumn);
|
||||
};
|
||||
|
||||
Tokenizer.prototype = {
|
||||
setSource: function(source, startOffset, startLine, startColumn) {
|
||||
var safeSource = String(source || '');
|
||||
var start = firstCharOffset(safeSource);
|
||||
|
||||
this.source = safeSource;
|
||||
this.firstCharOffset = start;
|
||||
this.startOffset = typeof startOffset === 'undefined' ? 0 : startOffset;
|
||||
this.startLine = typeof startLine === 'undefined' ? 1 : startLine;
|
||||
this.startColumn = typeof startColumn === 'undefined' ? 1 : startColumn;
|
||||
this.linesAnsColumnsComputed = false;
|
||||
|
||||
this.eof = false;
|
||||
this.currentToken = -1;
|
||||
this.tokenType = 0;
|
||||
this.tokenStart = start;
|
||||
this.tokenEnd = start;
|
||||
|
||||
tokenLayout(this, safeSource, start);
|
||||
this.next();
|
||||
},
|
||||
|
||||
lookupType: function(offset) {
|
||||
offset += this.currentToken;
|
||||
|
||||
if (offset < this.tokenCount) {
|
||||
return this.offsetAndType[offset] >> TYPE_SHIFT;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
},
|
||||
lookupNonWSType: function(offset) {
|
||||
offset += this.currentToken;
|
||||
|
||||
for (var type; offset < this.tokenCount; offset++) {
|
||||
type = this.offsetAndType[offset] >> TYPE_SHIFT;
|
||||
|
||||
if (type !== WHITESPACE) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
},
|
||||
lookupValue: function(offset, referenceStr) {
|
||||
offset += this.currentToken;
|
||||
|
||||
if (offset < this.tokenCount) {
|
||||
return cmpStr(
|
||||
this.source,
|
||||
this.offsetAndType[offset - 1] & OFFSET_MASK,
|
||||
this.offsetAndType[offset] & OFFSET_MASK,
|
||||
referenceStr
|
||||
);
|
||||
}
|
||||
|
||||
return false;
|
||||
},
|
||||
getTokenStart: function(tokenNum) {
|
||||
if (tokenNum === this.currentToken) {
|
||||
return this.tokenStart;
|
||||
}
|
||||
|
||||
if (tokenNum > 0) {
|
||||
return tokenNum < this.tokenCount
|
||||
? this.offsetAndType[tokenNum - 1] & OFFSET_MASK
|
||||
: this.offsetAndType[this.tokenCount] & OFFSET_MASK;
|
||||
}
|
||||
|
||||
return this.firstCharOffset;
|
||||
},
|
||||
getOffsetExcludeWS: function() {
|
||||
if (this.currentToken > 0) {
|
||||
if ((this.offsetAndType[this.currentToken - 1] >> TYPE_SHIFT) === WHITESPACE) {
|
||||
return this.currentToken > 1
|
||||
? this.offsetAndType[this.currentToken - 2] & OFFSET_MASK
|
||||
: this.firstCharOffset;
|
||||
}
|
||||
}
|
||||
return this.tokenStart;
|
||||
},
|
||||
getRawLength: function(startToken, endTokenType1, endTokenType2, includeTokenType2) {
|
||||
var cursor = startToken;
|
||||
var balanceEnd;
|
||||
|
||||
loop:
|
||||
for (; cursor < this.tokenCount; cursor++) {
|
||||
balanceEnd = this.balance[cursor];
|
||||
|
||||
// belance end points to offset before start
|
||||
if (balanceEnd < startToken) {
|
||||
break loop;
|
||||
}
|
||||
|
||||
// check token is stop type
|
||||
switch (this.offsetAndType[cursor] >> TYPE_SHIFT) {
|
||||
case endTokenType1:
|
||||
break loop;
|
||||
|
||||
case endTokenType2:
|
||||
if (includeTokenType2) {
|
||||
cursor++;
|
||||
}
|
||||
break loop;
|
||||
|
||||
default:
|
||||
// fast forward to the end of balanced block
|
||||
if (this.balance[balanceEnd] === cursor) {
|
||||
cursor = balanceEnd;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return cursor - this.currentToken;
|
||||
},
|
||||
|
||||
getTokenValue: function() {
|
||||
return this.source.substring(this.tokenStart, this.tokenEnd);
|
||||
},
|
||||
substrToCursor: function(start) {
|
||||
return this.source.substring(start, this.tokenStart);
|
||||
},
|
||||
|
||||
skipWS: function() {
|
||||
for (var i = this.currentToken, 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.currentToken + tokenCount;
|
||||
|
||||
if (next < this.tokenCount) {
|
||||
this.currentToken = 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.currentToken = this.tokenCount;
|
||||
this.next();
|
||||
}
|
||||
},
|
||||
next: function() {
|
||||
var next = this.currentToken + 1;
|
||||
|
||||
if (next < this.tokenCount) {
|
||||
this.currentToken = next;
|
||||
this.tokenStart = this.tokenEnd;
|
||||
next = this.offsetAndType[next];
|
||||
this.tokenType = next >> TYPE_SHIFT;
|
||||
this.tokenEnd = next & OFFSET_MASK;
|
||||
} else {
|
||||
this.currentToken = this.tokenCount;
|
||||
this.eof = true;
|
||||
this.tokenType = NULL;
|
||||
this.tokenStart = this.tokenEnd = this.source.length;
|
||||
}
|
||||
},
|
||||
|
||||
eat: function(tokenType) {
|
||||
if (this.tokenType !== tokenType) {
|
||||
var offset = this.tokenStart;
|
||||
var message = NAME[tokenType] + ' is expected';
|
||||
|
||||
// tweak message and offset
|
||||
if (tokenType === IDENTIFIER) {
|
||||
// when identifier is expected but there is a function or url
|
||||
if (this.tokenType === FUNCTION || this.tokenType === URL) {
|
||||
offset = this.tokenEnd - 1;
|
||||
message += ' but function found';
|
||||
}
|
||||
} else {
|
||||
// when test type is part of another token show error for current position + 1
|
||||
// e.g. eat(HYPHENMINUS) will fail on "-foo", but pointing on "-" is odd
|
||||
if (this.source.charCodeAt(this.tokenStart) === tokenType) {
|
||||
offset = offset + 1;
|
||||
}
|
||||
}
|
||||
|
||||
this.error(message, offset);
|
||||
}
|
||||
|
||||
this.next();
|
||||
},
|
||||
eatNonWS: function(tokenType) {
|
||||
this.skipWS();
|
||||
this.eat(tokenType);
|
||||
},
|
||||
|
||||
consume: function(tokenType) {
|
||||
var value = this.getTokenValue();
|
||||
|
||||
this.eat(tokenType);
|
||||
|
||||
return value;
|
||||
},
|
||||
consumeFunctionName: function() {
|
||||
var name = this.source.substring(this.tokenStart, this.tokenEnd - 1);
|
||||
|
||||
this.eat(FUNCTION);
|
||||
|
||||
return name;
|
||||
},
|
||||
consumeNonWS: function(tokenType) {
|
||||
this.skipWS();
|
||||
|
||||
return this.consume(tokenType);
|
||||
},
|
||||
|
||||
expectIdentifier: function(name) {
|
||||
if (this.tokenType !== IDENTIFIER || cmpStr(this.source, this.tokenStart, this.tokenEnd, name) === false) {
|
||||
this.error('Identifier `' + name + '` is expected');
|
||||
}
|
||||
|
||||
this.next();
|
||||
},
|
||||
|
||||
getLocation: function(offset, filename) {
|
||||
if (!this.linesAnsColumnsComputed) {
|
||||
computeLinesAndColumns(this, this.source);
|
||||
}
|
||||
|
||||
return {
|
||||
source: filename,
|
||||
offset: this.startOffset + offset,
|
||||
line: this.lines[offset],
|
||||
column: this.columns[offset]
|
||||
};
|
||||
},
|
||||
|
||||
getLocationRange: function(start, end, filename) {
|
||||
if (!this.linesAnsColumnsComputed) {
|
||||
computeLinesAndColumns(this, this.source);
|
||||
}
|
||||
|
||||
return {
|
||||
source: filename,
|
||||
start: {
|
||||
offset: this.startOffset + start,
|
||||
line: this.lines[start],
|
||||
column: this.columns[start]
|
||||
},
|
||||
end: {
|
||||
offset: this.startOffset + end,
|
||||
line: this.lines[end],
|
||||
column: this.columns[end]
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
error: function(message, offset) {
|
||||
var location = typeof offset !== 'undefined' && offset < this.source.length
|
||||
? this.getLocation(offset)
|
||||
: this.eof
|
||||
? findLastNonSpaceLocation(this)
|
||||
: this.getLocation(this.tokenStart);
|
||||
|
||||
throw new CssSyntaxError(
|
||||
message || 'Unexpected input',
|
||||
this.source,
|
||||
location.offset,
|
||||
location.line,
|
||||
location.column
|
||||
);
|
||||
},
|
||||
|
||||
dump: function() {
|
||||
var offset = 0;
|
||||
|
||||
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[item >> TYPE_SHIFT],
|
||||
chunk: this.source.substring(start, end),
|
||||
balance: this.balance[idx]
|
||||
};
|
||||
}, this);
|
||||
}
|
||||
};
|
||||
|
||||
// extend with error class
|
||||
Tokenizer.CssSyntaxError = CssSyntaxError;
|
||||
|
||||
// extend tokenizer with constants
|
||||
Object.keys(constants).forEach(function(key) {
|
||||
Tokenizer[key] = constants[key];
|
||||
});
|
||||
|
||||
// extend tokenizer with static methods from utils
|
||||
Object.keys(utils).forEach(function(key) {
|
||||
Tokenizer[key] = utils[key];
|
||||
});
|
||||
|
||||
// warm up tokenizer to elimitate code branches that never execute
|
||||
// fix soft deoptimizations (insufficient type feedback)
|
||||
new Tokenizer('\n\r\r\n\f<!---->//""\'\'/*\r\n\f*/1a;.\\31\t\+2{url(a);func();+1.2e3 -.4e-5 .6e+7}').getLocation();
|
||||
|
||||
module.exports = Tokenizer;
|
||||
171
build/node_modules/css-tree/lib/tokenizer/const.js
generated
vendored
Normal file
171
build/node_modules/css-tree/lib/tokenizer/const.js
generated
vendored
Normal file
@@ -0,0 +1,171 @@
|
||||
'use strict';
|
||||
|
||||
// token types (note: value shouldn't intersect with used char codes)
|
||||
var WHITESPACE = 1;
|
||||
var IDENTIFIER = 2;
|
||||
var NUMBER = 3;
|
||||
var STRING = 4;
|
||||
var COMMENT = 5;
|
||||
var PUNCTUATOR = 6;
|
||||
var CDO = 7;
|
||||
var CDC = 8;
|
||||
var ATRULE = 14;
|
||||
var FUNCTION = 15;
|
||||
var URL = 16;
|
||||
var RAW = 17;
|
||||
|
||||
var TAB = 9;
|
||||
var N = 10;
|
||||
var F = 12;
|
||||
var R = 13;
|
||||
var SPACE = 32;
|
||||
|
||||
var TYPE = {
|
||||
WhiteSpace: WHITESPACE,
|
||||
Identifier: IDENTIFIER,
|
||||
Number: NUMBER,
|
||||
String: STRING,
|
||||
Comment: COMMENT,
|
||||
Punctuator: PUNCTUATOR,
|
||||
CDO: CDO,
|
||||
CDC: CDC,
|
||||
Atrule: ATRULE,
|
||||
Function: FUNCTION,
|
||||
Url: URL,
|
||||
Raw: RAW,
|
||||
|
||||
ExclamationMark: 33, // !
|
||||
QuotationMark: 34, // "
|
||||
NumberSign: 35, // #
|
||||
DollarSign: 36, // $
|
||||
PercentSign: 37, // %
|
||||
Ampersand: 38, // &
|
||||
Apostrophe: 39, // '
|
||||
LeftParenthesis: 40, // (
|
||||
RightParenthesis: 41, // )
|
||||
Asterisk: 42, // *
|
||||
PlusSign: 43, // +
|
||||
Comma: 44, // ,
|
||||
HyphenMinus: 45, // -
|
||||
FullStop: 46, // .
|
||||
Solidus: 47, // /
|
||||
Colon: 58, // :
|
||||
Semicolon: 59, // ;
|
||||
LessThanSign: 60, // <
|
||||
EqualsSign: 61, // =
|
||||
GreaterThanSign: 62, // >
|
||||
QuestionMark: 63, // ?
|
||||
CommercialAt: 64, // @
|
||||
LeftSquareBracket: 91, // [
|
||||
Backslash: 92, // \
|
||||
RightSquareBracket: 93, // ]
|
||||
CircumflexAccent: 94, // ^
|
||||
LowLine: 95, // _
|
||||
GraveAccent: 96, // `
|
||||
LeftCurlyBracket: 123, // {
|
||||
VerticalLine: 124, // |
|
||||
RightCurlyBracket: 125, // }
|
||||
Tilde: 126 // ~
|
||||
};
|
||||
|
||||
var NAME = Object.keys(TYPE).reduce(function(result, key) {
|
||||
result[TYPE[key]] = key;
|
||||
return result;
|
||||
}, {});
|
||||
|
||||
// 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 a maps for 0..127 codes only
|
||||
var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported
|
||||
var SYMBOL_TYPE = new SafeUint32Array(0x80);
|
||||
var PUNCTUATION = new SafeUint32Array(0x80);
|
||||
var STOP_URL_RAW = new SafeUint32Array(0x80);
|
||||
|
||||
for (var i = 0; i < SYMBOL_TYPE.length; i++) {
|
||||
SYMBOL_TYPE[i] = IDENTIFIER;
|
||||
}
|
||||
|
||||
// fill categories
|
||||
[
|
||||
TYPE.ExclamationMark, // !
|
||||
TYPE.QuotationMark, // "
|
||||
TYPE.NumberSign, // #
|
||||
TYPE.DollarSign, // $
|
||||
TYPE.PercentSign, // %
|
||||
TYPE.Ampersand, // &
|
||||
TYPE.Apostrophe, // '
|
||||
TYPE.LeftParenthesis, // (
|
||||
TYPE.RightParenthesis, // )
|
||||
TYPE.Asterisk, // *
|
||||
TYPE.PlusSign, // +
|
||||
TYPE.Comma, // ,
|
||||
TYPE.HyphenMinus, // -
|
||||
TYPE.FullStop, // .
|
||||
TYPE.Solidus, // /
|
||||
TYPE.Colon, // :
|
||||
TYPE.Semicolon, // ;
|
||||
TYPE.LessThanSign, // <
|
||||
TYPE.EqualsSign, // =
|
||||
TYPE.GreaterThanSign, // >
|
||||
TYPE.QuestionMark, // ?
|
||||
TYPE.CommercialAt, // @
|
||||
TYPE.LeftSquareBracket, // [
|
||||
// TYPE.Backslash, // \
|
||||
TYPE.RightSquareBracket, // ]
|
||||
TYPE.CircumflexAccent, // ^
|
||||
// TYPE.LowLine, // _
|
||||
TYPE.GraveAccent, // `
|
||||
TYPE.LeftCurlyBracket, // {
|
||||
TYPE.VerticalLine, // |
|
||||
TYPE.RightCurlyBracket, // }
|
||||
TYPE.Tilde // ~
|
||||
].forEach(function(key) {
|
||||
SYMBOL_TYPE[Number(key)] = PUNCTUATOR;
|
||||
PUNCTUATION[Number(key)] = PUNCTUATOR;
|
||||
});
|
||||
|
||||
for (var i = 48; i <= 57; i++) {
|
||||
SYMBOL_TYPE[i] = NUMBER;
|
||||
}
|
||||
|
||||
SYMBOL_TYPE[SPACE] = WHITESPACE;
|
||||
SYMBOL_TYPE[TAB] = WHITESPACE;
|
||||
SYMBOL_TYPE[N] = WHITESPACE;
|
||||
SYMBOL_TYPE[R] = WHITESPACE;
|
||||
SYMBOL_TYPE[F] = WHITESPACE;
|
||||
|
||||
SYMBOL_TYPE[TYPE.Apostrophe] = STRING;
|
||||
SYMBOL_TYPE[TYPE.QuotationMark] = STRING;
|
||||
|
||||
STOP_URL_RAW[SPACE] = 1;
|
||||
STOP_URL_RAW[TAB] = 1;
|
||||
STOP_URL_RAW[N] = 1;
|
||||
STOP_URL_RAW[R] = 1;
|
||||
STOP_URL_RAW[F] = 1;
|
||||
STOP_URL_RAW[TYPE.Apostrophe] = 1;
|
||||
STOP_URL_RAW[TYPE.QuotationMark] = 1;
|
||||
STOP_URL_RAW[TYPE.LeftParenthesis] = 1;
|
||||
STOP_URL_RAW[TYPE.RightParenthesis] = 1;
|
||||
|
||||
// whitespace is punctuation ...
|
||||
PUNCTUATION[SPACE] = PUNCTUATOR;
|
||||
PUNCTUATION[TAB] = PUNCTUATOR;
|
||||
PUNCTUATION[N] = PUNCTUATOR;
|
||||
PUNCTUATION[R] = PUNCTUATOR;
|
||||
PUNCTUATION[F] = PUNCTUATOR;
|
||||
// ... hyper minus is not
|
||||
PUNCTUATION[TYPE.HyphenMinus] = 0;
|
||||
|
||||
module.exports = {
|
||||
TYPE: TYPE,
|
||||
NAME: NAME,
|
||||
|
||||
SYMBOL_TYPE: SYMBOL_TYPE,
|
||||
PUNCTUATION: PUNCTUATION,
|
||||
STOP_URL_RAW: STOP_URL_RAW
|
||||
};
|
||||
84
build/node_modules/css-tree/lib/tokenizer/error.js
generated
vendored
Normal file
84
build/node_modules/css-tree/lib/tokenizer/error.js
generated
vendored
Normal file
@@ -0,0 +1,84 @@
|
||||
'use strict';
|
||||
|
||||
var createCustomError = require('../utils/createCustomError');
|
||||
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 CssSyntaxError = function(message, source, offset, line, column) {
|
||||
var error = createCustomError('CssSyntaxError', 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;
|
||||
};
|
||||
|
||||
module.exports = CssSyntaxError;
|
||||
1
build/node_modules/css-tree/lib/tokenizer/index.js
generated
vendored
Normal file
1
build/node_modules/css-tree/lib/tokenizer/index.js
generated
vendored
Normal file
@@ -0,0 +1 @@
|
||||
module.exports = require('./Tokenizer');
|
||||
259
build/node_modules/css-tree/lib/tokenizer/utils.js
generated
vendored
Normal file
259
build/node_modules/css-tree/lib/tokenizer/utils.js
generated
vendored
Normal file
@@ -0,0 +1,259 @@
|
||||
'use strict';
|
||||
|
||||
var constants = require('./const');
|
||||
var PUNCTUATION = constants.PUNCTUATION;
|
||||
var STOP_URL_RAW = constants.STOP_URL_RAW;
|
||||
var TYPE = constants.TYPE;
|
||||
var FULLSTOP = TYPE.FullStop;
|
||||
var PLUSSIGN = TYPE.PlusSign;
|
||||
var HYPHENMINUS = TYPE.HyphenMinus;
|
||||
var PUNCTUATOR = TYPE.Punctuator;
|
||||
var TAB = 9;
|
||||
var N = 10;
|
||||
var F = 12;
|
||||
var R = 13;
|
||||
var SPACE = 32;
|
||||
var BACK_SLASH = 92;
|
||||
var E = 101; // 'e'.charCodeAt(0)
|
||||
|
||||
function firstCharOffset(source) {
|
||||
// detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
|
||||
if (source.charCodeAt(0) === 0xFEFF || // UTF-16BE
|
||||
source.charCodeAt(0) === 0xFFFE) { // UTF-16LE
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function isHex(code) {
|
||||
return (code >= 48 && code <= 57) || // 0 .. 9
|
||||
(code >= 65 && code <= 70) || // A .. F
|
||||
(code >= 97 && code <= 102); // a .. f
|
||||
}
|
||||
|
||||
function isNumber(code) {
|
||||
return code >= 48 && code <= 57;
|
||||
}
|
||||
|
||||
function isNewline(source, offset, code) {
|
||||
if (code === N || code === F || code === R) {
|
||||
if (code === R && offset + 1 < source.length && source.charCodeAt(offset + 1) === N) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
function cmpChar(testStr, offset, referenceCode) {
|
||||
var code = testStr.charCodeAt(offset);
|
||||
|
||||
// code.toLowerCase()
|
||||
if (code >= 65 && code <= 90) {
|
||||
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 refCode = referenceStr.charCodeAt(i - start);
|
||||
|
||||
// testStr[i].toLowerCase()
|
||||
if (testCode >= 65 && testCode <= 90) {
|
||||
testCode = testCode | 32;
|
||||
}
|
||||
|
||||
if (testCode !== refCode) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function endsWith(testStr, referenceStr) {
|
||||
return cmpStr(testStr, testStr.length - referenceStr.length, testStr.length, referenceStr);
|
||||
}
|
||||
|
||||
function findLastNonSpaceLocation(scanner) {
|
||||
for (var i = scanner.source.length - 1; i >= 0; i--) {
|
||||
var code = scanner.source.charCodeAt(i);
|
||||
|
||||
if (code !== SPACE && code !== TAB && code !== R && code !== N && code !== F) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return scanner.getLocation(i + 1);
|
||||
}
|
||||
|
||||
function findWhiteSpaceEnd(source, offset) {
|
||||
for (; offset < source.length; offset++) {
|
||||
var code = source.charCodeAt(offset);
|
||||
|
||||
if (code !== SPACE && code !== TAB && code !== R && code !== N && code !== F) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
function findCommentEnd(source, offset) {
|
||||
var commentEnd = source.indexOf('*/', offset);
|
||||
|
||||
if (commentEnd === -1) {
|
||||
return source.length;
|
||||
}
|
||||
|
||||
return commentEnd + 2;
|
||||
}
|
||||
|
||||
function findStringEnd(source, offset, quote) {
|
||||
for (; offset < source.length; offset++) {
|
||||
var code = source.charCodeAt(offset);
|
||||
|
||||
// TODO: bad string
|
||||
if (code === BACK_SLASH) {
|
||||
offset++;
|
||||
} else if (code === quote) {
|
||||
offset++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
function findDecimalNumberEnd(source, offset) {
|
||||
for (; offset < source.length; offset++) {
|
||||
var code = source.charCodeAt(offset);
|
||||
|
||||
if (code < 48 || code > 57) { // not a 0 .. 9
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
function findNumberEnd(source, offset, allowFraction) {
|
||||
var code;
|
||||
|
||||
offset = findDecimalNumberEnd(source, offset);
|
||||
|
||||
// fraction: .\d+
|
||||
if (allowFraction && offset + 1 < source.length && source.charCodeAt(offset) === FULLSTOP) {
|
||||
code = source.charCodeAt(offset + 1);
|
||||
|
||||
if (isNumber(code)) {
|
||||
offset = findDecimalNumberEnd(source, offset + 1);
|
||||
}
|
||||
}
|
||||
|
||||
// exponent: e[+-]\d+
|
||||
if (offset + 1 < source.length) {
|
||||
if ((source.charCodeAt(offset) | 32) === E) { // case insensitive check for `e`
|
||||
code = source.charCodeAt(offset + 1);
|
||||
|
||||
if (code === PLUSSIGN || code === HYPHENMINUS) {
|
||||
if (offset + 2 < source.length) {
|
||||
code = source.charCodeAt(offset + 2);
|
||||
}
|
||||
}
|
||||
|
||||
if (isNumber(code)) {
|
||||
offset = findDecimalNumberEnd(source, offset + 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
// skip escaped unicode sequence that can ends with space
|
||||
// [0-9a-f]{1,6}(\r\n|[ \n\r\t\f])?
|
||||
function findEscaseEnd(source, offset) {
|
||||
for (var i = 0; i < 7 && offset + i < source.length; i++) {
|
||||
var code = source.charCodeAt(offset + i);
|
||||
|
||||
if (i !== 6 && isHex(code)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i > 0) {
|
||||
offset += i - 1 + isNewline(source, offset + i, code);
|
||||
if (code === SPACE || code === TAB) {
|
||||
offset++;
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
function findIdentifierEnd(source, offset) {
|
||||
for (; offset < source.length; offset++) {
|
||||
var code = source.charCodeAt(offset);
|
||||
|
||||
if (code === BACK_SLASH) {
|
||||
offset = findEscaseEnd(source, offset + 1);
|
||||
} else if (code < 0x80 && PUNCTUATION[code] === PUNCTUATOR) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
function findUrlRawEnd(source, offset) {
|
||||
for (; offset < source.length; offset++) {
|
||||
var code = source.charCodeAt(offset);
|
||||
|
||||
if (code === BACK_SLASH) {
|
||||
offset = findEscaseEnd(source, offset + 1);
|
||||
} else if (code < 0x80 && STOP_URL_RAW[code] === 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return offset;
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
firstCharOffset: firstCharOffset,
|
||||
|
||||
isHex: isHex,
|
||||
isNumber: isNumber,
|
||||
isNewline: isNewline,
|
||||
|
||||
cmpChar: cmpChar,
|
||||
cmpStr: cmpStr,
|
||||
endsWith: endsWith,
|
||||
|
||||
findLastNonSpaceLocation: findLastNonSpaceLocation,
|
||||
findWhiteSpaceEnd: findWhiteSpaceEnd,
|
||||
findCommentEnd: findCommentEnd,
|
||||
findStringEnd: findStringEnd,
|
||||
findDecimalNumberEnd: findDecimalNumberEnd,
|
||||
findNumberEnd: findNumberEnd,
|
||||
findEscaseEnd: findEscaseEnd,
|
||||
findIdentifierEnd: findIdentifierEnd,
|
||||
findUrlRawEnd: findUrlRawEnd
|
||||
};
|
||||
Reference in New Issue
Block a user