Fix code quality violations and exclude Manifest from checks

Document application modes (development/debug/production)
Add global file drop handler, order column normalization, SPA hash fix
Serve CDN assets via /_vendor/ URLs instead of merging into bundles
Add production minification with license preservation
Improve JSON formatting for debugging and production optimization
Add CDN asset caching with CSS URL inlining for production builds
Add three-mode system (development, debug, production)
Update Manifest CLAUDE.md to reflect helper class architecture
Refactor Manifest.php into helper classes for better organization
Pre-manifest-refactor checkpoint: Add app_mode documentation

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
root
2026-01-14 10:38:22 +00:00
parent bb9046af1b
commit d523f0f600
2355 changed files with 231384 additions and 32223 deletions

View File

@@ -0,0 +1,87 @@
import { adoptBuffer } from './adopt-buffer.js';
import { isBOM } from './char-code-definitions.js';
const N = 10;
const F = 12;
const R = 13;
function computeLinesAndColumns(host) {
const source = host.source;
const sourceLength = source.length;
const startOffset = source.length > 0 ? isBOM(source.charCodeAt(0)) : 0;
const lines = adoptBuffer(host.lines, sourceLength);
const columns = adoptBuffer(host.columns, sourceLength);
let line = host.startLine;
let column = host.startColumn;
for (let i = startOffset; i < sourceLength; i++) {
const 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[sourceLength] = line;
columns[sourceLength] = column;
host.lines = lines;
host.columns = columns;
host.computed = true;
}
export class OffsetToLocation {
constructor(source, startOffset, startLine, startColumn) {
this.setSource(source, startOffset, startLine, startColumn);
this.lines = null;
this.columns = null;
}
setSource(source = '', startOffset = 0, startLine = 1, startColumn = 1) {
this.source = source;
this.startOffset = startOffset;
this.startLine = startLine;
this.startColumn = startColumn;
this.computed = false;
}
getLocation(offset, filename) {
if (!this.computed) {
computeLinesAndColumns(this);
}
return {
source: filename,
offset: this.startOffset + offset,
line: this.lines[offset],
column: this.columns[offset]
};
}
getLocationRange(start, end, filename) {
if (!this.computed) {
computeLinesAndColumns(this);
}
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]
}
};
}
};

316
node_modules/css-tree/lib/tokenizer/TokenStream.js generated vendored Normal file
View File

@@ -0,0 +1,316 @@
import { adoptBuffer } from './adopt-buffer.js';
import { cmpStr } from './utils.js';
import tokenNames from './names.js';
import {
WhiteSpace,
Comment,
Delim,
EOF,
Function as FunctionToken,
LeftParenthesis,
RightParenthesis,
LeftSquareBracket,
RightSquareBracket,
LeftCurlyBracket,
RightCurlyBracket
} from './types.js';
const OFFSET_MASK = 0x00FFFFFF;
const TYPE_SHIFT = 24;
const balancePair = new Uint8Array(32); // 32b of memory ought to be enough for anyone (any number of tokens)
balancePair[FunctionToken] = RightParenthesis;
balancePair[LeftParenthesis] = RightParenthesis;
balancePair[LeftSquareBracket] = RightSquareBracket;
balancePair[LeftCurlyBracket] = RightCurlyBracket;
function isBlockOpenerToken(tokenType) {
return balancePair[tokenType] !== 0;
}
export class TokenStream {
constructor(source, tokenize) {
this.setSource(source, tokenize);
}
reset() {
this.eof = false;
this.tokenIndex = -1;
this.tokenType = 0;
this.tokenStart = this.firstCharOffset;
this.tokenEnd = this.firstCharOffset;
}
setSource(source = '', tokenize = () => {}) {
source = String(source || '');
const sourceLength = source.length;
const offsetAndType = adoptBuffer(this.offsetAndType, source.length + 1); // +1 because of eof-token
const balance = adoptBuffer(this.balance, source.length + 1);
let tokenCount = 0;
let firstCharOffset = -1;
let balanceCloseType = 0;
let balanceStart = source.length;
// capture buffers
this.offsetAndType = null;
this.balance = null;
balance.fill(0);
tokenize(source, (type, start, end) => {
const index = tokenCount++;
// type & offset
offsetAndType[index] = (type << TYPE_SHIFT) | end;
if (firstCharOffset === -1) {
firstCharOffset = start;
}
// balance
balance[index] = balanceStart;
if (type === balanceCloseType) {
const prevBalanceStart = balance[balanceStart];
// set reference to balance end for a block opener
balance[balanceStart] = index;
// pop state
balanceStart = prevBalanceStart;
balanceCloseType = balancePair[offsetAndType[prevBalanceStart] >> TYPE_SHIFT];
} else if (isBlockOpenerToken(type)) { // check for FunctionToken, <(-token>, <[-token> and <{-token>
// push state
balanceStart = index;
balanceCloseType = balancePair[type];
}
});
// finalize buffers
offsetAndType[tokenCount] = (EOF << TYPE_SHIFT) | sourceLength; // <EOF-token>
balance[tokenCount] = tokenCount; // prevents false positive balance match with any token
// reverse references from balance start to end
// tokens
// token: a ( [ b c ] d e ) {
// index: 0 1 2 3 4 5 6 7 8 9
// before
// balance: 0 8 5 2 2 2 1 1 1 0
// - > > < < < < < < -
// after
// balance: 9 8 5 5 5 2 8 8 1 9
// > > > > > < > > < >
for (let i = 0; i < tokenCount; i++) {
const balanceStart = balance[i];
if (balanceStart <= i) {
const balanceEnd = balance[balanceStart];
if (balanceEnd !== i) {
balance[i] = balanceEnd;
}
} else if (balanceStart > tokenCount) {
balance[i] = tokenCount;
}
}
// balance[0] = tokenCount;
this.source = source;
this.firstCharOffset = firstCharOffset === -1 ? 0 : firstCharOffset;
this.tokenCount = tokenCount;
this.offsetAndType = offsetAndType;
this.balance = balance;
this.reset();
this.next();
}
lookupType(offset) {
offset += this.tokenIndex;
if (offset < this.tokenCount) {
return this.offsetAndType[offset] >> TYPE_SHIFT;
}
return EOF;
}
lookupTypeNonSC(idx) {
for (let offset = this.tokenIndex; offset < this.tokenCount; offset++) {
const tokenType = this.offsetAndType[offset] >> TYPE_SHIFT;
if (tokenType !== WhiteSpace && tokenType !== Comment) {
if (idx-- === 0) {
return tokenType;
}
}
}
return EOF;
}
lookupOffset(offset) {
offset += this.tokenIndex;
if (offset < this.tokenCount) {
return this.offsetAndType[offset - 1] & OFFSET_MASK;
}
return this.source.length;
}
lookupOffsetNonSC(idx) {
for (let offset = this.tokenIndex; offset < this.tokenCount; offset++) {
const tokenType = this.offsetAndType[offset] >> TYPE_SHIFT;
if (tokenType !== WhiteSpace && tokenType !== Comment) {
if (idx-- === 0) {
return offset - this.tokenIndex;
}
}
}
return EOF;
}
lookupValue(offset, referenceStr) {
offset += this.tokenIndex;
if (offset < this.tokenCount) {
return cmpStr(
this.source,
this.offsetAndType[offset - 1] & OFFSET_MASK,
this.offsetAndType[offset] & OFFSET_MASK,
referenceStr
);
}
return false;
}
getTokenStart(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;
}
substrToCursor(start) {
return this.source.substring(start, this.tokenStart);
}
isBalanceEdge(pos) {
return this.balance[this.tokenIndex] < pos;
// return this.balance[this.balance[pos]] !== this.tokenIndex;
}
isDelim(code, offset) {
if (offset) {
return (
this.lookupType(offset) === Delim &&
this.source.charCodeAt(this.lookupOffset(offset)) === code
);
}
return (
this.tokenType === Delim &&
this.source.charCodeAt(this.tokenStart) === code
);
}
skip(tokenCount) {
let 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() {
let 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.eof = true;
this.tokenIndex = this.tokenCount;
this.tokenType = EOF;
this.tokenStart = this.tokenEnd = this.source.length;
}
}
skipSC() {
while (this.tokenType === WhiteSpace || this.tokenType === Comment) {
this.next();
}
}
skipUntilBalanced(startToken, stopConsume) {
let cursor = startToken;
let balanceEnd = 0;
let offset = 0;
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;
}
offset = cursor > 0 ? this.offsetAndType[cursor - 1] & OFFSET_MASK : this.firstCharOffset;
// check stop condition
switch (stopConsume(this.source.charCodeAt(offset))) {
case 1: // just stop
break loop;
case 2: // stop & included
cursor++;
break loop;
default:
// fast forward to the end of balanced block for an open block tokens
if (isBlockOpenerToken(this.offsetAndType[cursor] >> TYPE_SHIFT)) {
cursor = balanceEnd;
}
}
}
this.skip(cursor - this.tokenIndex);
}
forEachToken(fn) {
for (let i = 0, offset = this.firstCharOffset; i < this.tokenCount; i++) {
const start = offset;
const item = this.offsetAndType[i];
const end = item & OFFSET_MASK;
const type = item >> TYPE_SHIFT;
offset = end;
fn(type, start, end, i);
}
}
dump() {
const tokens = new Array(this.tokenCount);
this.forEachToken((type, start, end, index) => {
tokens[index] = {
idx: index,
type: tokenNames[type],
chunk: this.source.substring(start, end),
balance: this.balance[index]
};
});
return tokens;
}
};

9
node_modules/css-tree/lib/tokenizer/adopt-buffer.js generated vendored Normal file
View File

@@ -0,0 +1,9 @@
const MIN_SIZE = 16 * 1024;
export function adoptBuffer(buffer = null, size) {
if (buffer === null || buffer.length < size) {
return new Uint32Array(Math.max(size + 1024, MIN_SIZE));
}
return buffer;
};

View File

@@ -1,18 +1,18 @@
var EOF = 0;
const 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) {
export 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) {
export function isHexDigit(code) {
return (
isDigit(code) || // 0 .. 9
(code >= 0x0041 && code <= 0x0046) || // A .. F
@@ -22,44 +22,49 @@ function isHexDigit(code) {
// uppercase letter
// A code point between U+0041 LATIN CAPITAL LETTER A (A) and U+005A LATIN CAPITAL LETTER Z (Z).
function isUppercaseLetter(code) {
export 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) {
export function isLowercaseLetter(code) {
return code >= 0x0061 && code <= 0x007A;
}
// letter
// An uppercase letter or a lowercase letter.
function isLetter(code) {
export 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) {
//
// 2024-09-02: The latest spec narrows the range for non-ASCII characters (see https://github.com/csstree/csstree/issues/188).
// However, all modern browsers support a wider range, and strictly following the latest spec could result
// in some CSS being parsed incorrectly, even though it works in the browser. Therefore, this function adheres
// to the previous, broader definition of non-ASCII characters.
export 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) {
export 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) {
export 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) {
export function isNonPrintable(code) {
return (
(code >= 0x0000 && code <= 0x0008) ||
(code === 0x000B) ||
@@ -72,18 +77,18 @@ function isNonPrintable(code) {
// 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) {
export function isNewline(code) {
return code === 0x000A || code === 0x000D || code === 0x000C;
}
// whitespace
// A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE.
function isWhiteSpace(code) {
export 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) {
export function isValidEscape(first, second) {
// If the first code point is not U+005C REVERSE SOLIDUS (\), return false.
if (first !== 0x005C) {
return false;
@@ -99,7 +104,7 @@ function isValidEscape(first, second) {
}
// § 4.3.9. Check if three code points would start an identifier
function isIdentifierStart(first, second, third) {
export function isIdentifierStart(first, second, third) {
// Look at the first code point:
// U+002D HYPHEN-MINUS
@@ -131,7 +136,7 @@ function isIdentifierStart(first, second, third) {
}
// § 4.3.10. Check if three code points would start a number
function isNumberStart(first, second, third) {
export function isNumberStart(first, second, third) {
// Look at the first code point:
// U+002B PLUS SIGN (+)
@@ -170,7 +175,7 @@ function isNumberStart(first, second, third) {
//
// detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
function isBOM(code) {
export function isBOM(code) {
// UTF-16BE
if (code === 0xFEFF) {
return 1;
@@ -185,65 +190,23 @@ function isBOM(code) {
}
// 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;
// Only ASCII code points has a special meaning, that's why we define a maps for 0..127 codes only
const CATEGORY = new Array(0x80);
export const EofCategory = 0x80;
export const WhiteSpaceCategory = 0x82;
export const DigitCategory = 0x83;
export const NameStartCategory = 0x84;
export const NonPrintableCategory = 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;
}
for (let i = 0; i < CATEGORY.length; i++) {
CATEGORY[i] =
isWhiteSpace(i) && WhiteSpaceCategory ||
isDigit(i) && DigitCategory ||
isNameStart(i) && NameStartCategory ||
isNonPrintable(i) && NonPrintableCategory ||
i || EofCategory;
}
function charCodeCategory(code) {
return code < 0x80 ? CATEGORY[code] : charCodeCategory.NameStart;
};
module.exports = {
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
};
export function charCodeCategory(code) {
return code < 0x80 ? CATEGORY[code] : NameStartCategory;
}

View File

@@ -1,40 +0,0 @@
// 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;
}, {});
module.exports = {
TYPE: TYPE,
NAME: NAME
};

View File

@@ -1,31 +1,28 @@
var TokenStream = require('../common/TokenStream');
var adoptBuffer = require('../common/adopt-buffer');
import * as TYPE from './types.js';
import {
isNewline,
isName,
isValidEscape,
isNumberStart,
isIdentifierStart,
isBOM,
charCodeCategory,
WhiteSpaceCategory,
DigitCategory,
NameStartCategory,
NonPrintableCategory
} from './char-code-definitions.js';
import {
cmpStr,
getNewlineLength,
findWhiteSpaceEnd,
consumeEscaped,
consumeName,
consumeNumber,
consumeBadUrlRemnants
} from './utils.js';
var constants = require('./const');
var TYPE = constants.TYPE;
var charCodeDefinitions = require('./char-code-definitions');
var isNewline = charCodeDefinitions.isNewline;
var isName = charCodeDefinitions.isName;
var isValidEscape = charCodeDefinitions.isValidEscape;
var isNumberStart = charCodeDefinitions.isNumberStart;
var isIdentifierStart = charCodeDefinitions.isIdentifierStart;
var charCodeCategory = charCodeDefinitions.charCodeCategory;
var isBOM = charCodeDefinitions.isBOM;
var utils = require('./utils');
var cmpStr = utils.cmpStr;
var getNewlineLength = utils.getNewlineLength;
var findWhiteSpaceEnd = utils.findWhiteSpaceEnd;
var consumeEscaped = utils.consumeEscaped;
var consumeName = utils.consumeName;
var consumeNumber = utils.consumeNumber;
var consumeBadUrlRemnants = utils.consumeBadUrlRemnants;
var OFFSET_MASK = 0x00FFFFFF;
var TYPE_SHIFT = 24;
function tokenize(source, stream) {
export function tokenize(source, onToken) {
function getCharCode(offset) {
return offset < sourceLength ? source.charCodeAt(offset) : 0;
}
@@ -111,7 +108,7 @@ function tokenize(source, stream) {
// Repeatedly consume the next input code point from the stream:
for (; offset < source.length; offset++) {
var code = source.charCodeAt(offset);
const code = source.charCodeAt(offset);
switch (charCodeCategory(code)) {
// ending code point
@@ -120,13 +117,13 @@ function tokenize(source, stream) {
offset++;
return;
// EOF
case charCodeCategory.Eof:
// EOF
// case EofCategory:
// This is a parse error. Return the <string-token>.
return;
// return;
// newline
case charCodeCategory.WhiteSpace:
case WhiteSpaceCategory:
if (isNewline(code)) {
// This is a parse error. Reconsume the current input code point,
// create a <bad-string-token>, and return it.
@@ -143,7 +140,7 @@ function tokenize(source, stream) {
break;
}
var nextCode = getCharCode(offset + 1);
const nextCode = getCharCode(offset + 1);
// Otherwise, if the next input code point is a newline, consume it.
if (isNewline(nextCode)) {
@@ -176,7 +173,7 @@ function tokenize(source, stream) {
// Repeatedly consume the next input code point from the stream:
for (; offset < source.length; offset++) {
var code = source.charCodeAt(offset);
const code = source.charCodeAt(offset);
switch (charCodeCategory(code)) {
// U+0029 RIGHT PARENTHESIS ())
@@ -185,13 +182,13 @@ function tokenize(source, stream) {
offset++;
return;
// EOF
case charCodeCategory.Eof:
// EOF
// case EofCategory:
// This is a parse error. Return the <url-token>.
return;
// return;
// whitespace
case charCodeCategory.WhiteSpace:
case WhiteSpaceCategory:
// Consume as much whitespace as possible.
offset = findWhiteSpaceEnd(source, offset);
@@ -218,7 +215,7 @@ function tokenize(source, stream) {
case 0x0022:
case 0x0027:
case 0x0028:
case charCodeCategory.NonPrintable:
case NonPrintableCategory:
// This is a parse error. Consume the remnants of a bad url,
// create a <bad-url-token>, and return it.
offset = consumeBadUrlRemnants(source, offset);
@@ -246,34 +243,22 @@ function tokenize(source, stream) {
}
}
if (!stream) {
stream = new TokenStream();
}
// ensure source is a string
source = String(source || '');
var sourceLength = source.length;
var offsetAndType = adoptBuffer(stream.offsetAndType, sourceLength + 1); // +1 because of eof-token
var balance = adoptBuffer(stream.balance, sourceLength + 1);
var tokenCount = 0;
var start = isBOM(getCharCode(0));
var offset = start;
var balanceCloseType = 0;
var balanceStart = 0;
var balancePrev = 0;
const sourceLength = source.length;
let start = isBOM(getCharCode(0));
let offset = start;
let type;
// https://drafts.csswg.org/css-syntax-3/#consume-token
// § 4.3.1. Consume a token
while (offset < sourceLength) {
var code = source.charCodeAt(offset);
var type = 0;
balance[tokenCount] = sourceLength;
const code = source.charCodeAt(offset);
switch (charCodeCategory(code)) {
// whitespace
case charCodeCategory.WhiteSpace:
case WhiteSpaceCategory:
// Consume as much whitespace as possible. Return a <whitespace-token>.
type = TYPE.WhiteSpace;
offset = findWhiteSpaceEnd(source, offset + 1);
@@ -395,10 +380,8 @@ function tokenize(source, stream) {
// ... consume them and all following code points up to and including the first U+002A ASTERISK (*)
// followed by a U+002F SOLIDUS (/), or up to an EOF code point.
type = TYPE.Comment;
offset = source.indexOf('*/', offset + 2) + 2;
if (offset === 1) {
offset = source.length;
}
offset = source.indexOf('*/', offset + 2);
offset = offset === -1 ? source.length : offset + 2;
} else {
type = TYPE.Delim;
offset++;
@@ -493,21 +476,21 @@ function tokenize(source, stream) {
break;
// digit
case charCodeCategory.Digit:
case DigitCategory:
// Reconsume the current input code point, consume a numeric token, and return it.
consumeNumericToken();
break;
// name-start code point
case charCodeCategory.NameStart:
case NameStartCategory:
// Reconsume the current input code point, consume an ident-like token, and return it.
consumeIdentLikeToken();
break;
// EOF
case charCodeCategory.Eof:
// EOF
// case EofCategory:
// Return an <EOF-token>.
break;
// break;
// anything else
default:
@@ -516,76 +499,15 @@ function tokenize(source, stream) {
offset++;
}
switch (type) {
case balanceCloseType:
balancePrev = balanceStart & OFFSET_MASK;
balanceStart = balance[balancePrev];
balanceCloseType = balanceStart >> TYPE_SHIFT;
balance[tokenCount] = balancePrev;
balance[balancePrev++] = tokenCount;
for (; balancePrev < tokenCount; balancePrev++) {
if (balance[balancePrev] === sourceLength) {
balance[balancePrev] = tokenCount;
}
}
break;
case TYPE.LeftParenthesis:
case TYPE.Function:
balance[tokenCount] = balanceStart;
balanceCloseType = TYPE.RightParenthesis;
balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount;
break;
case TYPE.LeftSquareBracket:
balance[tokenCount] = balanceStart;
balanceCloseType = TYPE.RightSquareBracket;
balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount;
break;
case TYPE.LeftCurlyBracket:
balance[tokenCount] = balanceStart;
balanceCloseType = TYPE.RightCurlyBracket;
balanceStart = (balanceCloseType << TYPE_SHIFT) | tokenCount;
break;
}
offsetAndType[tokenCount++] = (type << TYPE_SHIFT) | offset;
// put token to stream
onToken(type, start, start = offset);
}
// finalize buffers
offsetAndType[tokenCount] = (TYPE.EOF << TYPE_SHIFT) | offset; // <EOF-token>
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;
}
// update stream
stream.source = source;
stream.firstCharOffset = start;
stream.offsetAndType = offsetAndType;
stream.tokenCount = tokenCount;
stream.balance = balance;
stream.reset();
stream.next();
return stream;
}
// extend tokenizer with constants
Object.keys(constants).forEach(function(key) {
tokenize[key] = constants[key];
});
// extend tokenizer with static methods from utils
Object.keys(charCodeDefinitions).forEach(function(key) {
tokenize[key] = charCodeDefinitions[key];
});
Object.keys(utils).forEach(function(key) {
tokenize[key] = utils[key];
});
module.exports = tokenize;
export * from './types.js';
export * as tokenTypes from './types.js';
export { default as tokenNames } from './names.js';
export * from './char-code-definitions.js';
export * from './utils.js';
export * from './OffsetToLocation.js';
export * from './TokenStream.js';

28
node_modules/css-tree/lib/tokenizer/names.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
export default [
'EOF-token',
'ident-token',
'function-token',
'at-keyword-token',
'hash-token',
'string-token',
'bad-string-token',
'url-token',
'bad-url-token',
'delim-token',
'number-token',
'percentage-token',
'dimension-token',
'whitespace-token',
'CDO-token',
'CDC-token',
'colon-token',
'semicolon-token',
'comma-token',
'[-token',
']-token',
'(-token',
')-token',
'{-token',
'}-token',
'comment-token'
];

28
node_modules/css-tree/lib/tokenizer/types.js generated vendored Normal file
View File

@@ -0,0 +1,28 @@
// CSS Syntax Module Level 3
// https://www.w3.org/TR/css-syntax-3/
export const EOF = 0; // <EOF-token>
export const Ident = 1; // <ident-token>
export const Function = 2; // <function-token>
export const AtKeyword = 3; // <at-keyword-token>
export const Hash = 4; // <hash-token>
export const String = 5; // <string-token>
export const BadString = 6; // <bad-string-token>
export const Url = 7; // <url-token>
export const BadUrl = 8; // <bad-url-token>
export const Delim = 9; // <delim-token>
export const Number = 10; // <number-token>
export const Percentage = 11; // <percentage-token>
export const Dimension = 12; // <dimension-token>
export const WhiteSpace = 13; // <whitespace-token>
export const CDO = 14; // <CDO-token>
export const CDC = 15; // <CDC-token>
export const Colon = 16; // <colon-token> :
export const Semicolon = 17; // <semicolon-token> ;
export const Comma = 18; // <comma-token> ,
export const LeftSquareBracket = 19; // <[-token>
export const RightSquareBracket = 20; // <]-token>
export const LeftParenthesis = 21; // <(-token>
export const RightParenthesis = 22; // <)-token>
export const LeftCurlyBracket = 23; // <{-token>
export const RightCurlyBracket = 24; // <}-token>
export const Comment = 25;

View File

@@ -1,16 +1,17 @@
var charCodeDef = require('./char-code-definitions');
var isDigit = charCodeDef.isDigit;
var isHexDigit = charCodeDef.isHexDigit;
var isUppercaseLetter = charCodeDef.isUppercaseLetter;
var isName = charCodeDef.isName;
var isWhiteSpace = charCodeDef.isWhiteSpace;
var isValidEscape = charCodeDef.isValidEscape;
import {
isDigit,
isHexDigit,
isUppercaseLetter,
isName,
isWhiteSpace,
isValidEscape
} from './char-code-definitions.js';
function getCharCode(source, offset) {
return offset < source.length ? source.charCodeAt(offset) : 0;
}
function getNewlineLength(source, offset, code) {
export function getNewlineLength(source, offset, code) {
if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) {
return 2;
}
@@ -18,8 +19,8 @@ function getNewlineLength(source, offset, code) {
return 1;
}
function cmpChar(testStr, offset, referenceCode) {
var code = testStr.charCodeAt(offset);
export function cmpChar(testStr, offset, referenceCode) {
let code = testStr.charCodeAt(offset);
// code.toLowerCase() for A..Z
if (isUppercaseLetter(code)) {
@@ -29,7 +30,7 @@ function cmpChar(testStr, offset, referenceCode) {
return code === referenceCode;
}
function cmpStr(testStr, start, end, referenceStr) {
export function cmpStr(testStr, start, end, referenceStr) {
if (end - start !== referenceStr.length) {
return false;
}
@@ -38,9 +39,9 @@ function cmpStr(testStr, start, end, referenceStr) {
return false;
}
for (var i = start; i < end; i++) {
var testCode = testStr.charCodeAt(i);
var referenceCode = referenceStr.charCodeAt(i - start);
for (let i = start; i < end; i++) {
const referenceCode = referenceStr.charCodeAt(i - start);
let testCode = testStr.charCodeAt(i);
// testCode.toLowerCase() for A..Z
if (isUppercaseLetter(testCode)) {
@@ -55,7 +56,7 @@ function cmpStr(testStr, start, end, referenceStr) {
return true;
}
function findWhiteSpaceStart(source, offset) {
export function findWhiteSpaceStart(source, offset) {
for (; offset >= 0; offset--) {
if (!isWhiteSpace(source.charCodeAt(offset))) {
break;
@@ -65,7 +66,7 @@ function findWhiteSpaceStart(source, offset) {
return offset + 1;
}
function findWhiteSpaceEnd(source, offset) {
export function findWhiteSpaceEnd(source, offset) {
for (; offset < source.length; offset++) {
if (!isWhiteSpace(source.charCodeAt(offset))) {
break;
@@ -75,7 +76,7 @@ function findWhiteSpaceEnd(source, offset) {
return offset;
}
function findDecimalNumberEnd(source, offset) {
export function findDecimalNumberEnd(source, offset) {
for (; offset < source.length; offset++) {
if (!isDigit(source.charCodeAt(offset))) {
break;
@@ -86,7 +87,7 @@ function findDecimalNumberEnd(source, offset) {
}
// § 4.3.7. Consume an escaped code point
function consumeEscaped(source, offset) {
export 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;
@@ -95,14 +96,14 @@ function consumeEscaped(source, offset) {
if (isHexDigit(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++) {
for (const maxOffset = Math.min(source.length, offset + 5); offset < maxOffset; offset++) {
if (!isHexDigit(getCharCode(source, offset))) {
break;
}
}
// If the next input code point is whitespace, consume it as well.
var code = getCharCode(source, offset);
const code = getCharCode(source, offset);
if (isWhiteSpace(code)) {
offset += getNewlineLength(source, offset, code);
}
@@ -115,11 +116,11 @@ function consumeEscaped(source, offset) {
// 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) {
export 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);
const code = source.charCodeAt(offset);
// name code point
if (isName(code)) {
@@ -143,8 +144,8 @@ function consumeName(source, offset) {
}
// §4.3.12. Consume a number
function consumeNumber(source, offset) {
var code = source.charCodeAt(offset);
export function consumeNumber(source, offset) {
let 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.
@@ -162,7 +163,7 @@ function consumeNumber(source, offset) {
if (code === 0x002E && isDigit(source.charCodeAt(offset + 1))) {
// 4.1 Consume them.
// 4.2 Append them to repr.
code = source.charCodeAt(offset += 2);
offset += 2;
// 4.3 Set type to "number".
// TODO
@@ -175,7 +176,7 @@ function consumeNumber(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;
let sign = 0;
code = source.charCodeAt(offset + 1);
// ... optionally followed by U+002D HYPHEN-MINUS (-) or U+002B PLUS SIGN (+) ...
@@ -203,10 +204,10 @@ function consumeNumber(source, 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) {
export function consumeBadUrlRemnants(source, offset) {
// Repeatedly consume the next input code point from the stream:
for (; offset < source.length; offset++) {
var code = source.charCodeAt(offset);
const code = source.charCodeAt(offset);
// U+0029 RIGHT PARENTHESIS ())
// EOF
@@ -228,16 +229,26 @@ function consumeBadUrlRemnants(source, offset) {
return offset;
}
module.exports = {
consumeEscaped: consumeEscaped,
consumeName: consumeName,
consumeNumber: consumeNumber,
consumeBadUrlRemnants: consumeBadUrlRemnants,
// § 4.3.7. Consume an escaped code point
// Note: This algorithm assumes that escaped is valid without leading U+005C REVERSE SOLIDUS (\)
export function decodeEscaped(escaped) {
// Single char escaped that's not a hex digit
if (escaped.length === 1 && !isHexDigit(escaped.charCodeAt(0))) {
return escaped[0];
}
cmpChar: cmpChar,
cmpStr: cmpStr,
// Interpret the hex digits as a hexadecimal number.
let code = parseInt(escaped, 16);
getNewlineLength: getNewlineLength,
findWhiteSpaceStart: findWhiteSpaceStart,
findWhiteSpaceEnd: findWhiteSpaceEnd
};
if (
(code === 0) || // If this number is zero,
(code >= 0xD800 && code <= 0xDFFF) || // or is for a surrogate,
(code > 0x10FFFF) // or is greater than the maximum allowed code point
) {
// ... return U+FFFD REPLACEMENT CHARACTER
code = 0xFFFD;
}
// Otherwise, return the code point with that value.
return String.fromCodePoint(code);
}