Socket
Socket
Sign inDemoInstall

css-tree

Package Overview
Dependencies
2
Maintainers
2
Versions
55
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 1.1.3 to 2.0.0

cjs/convertor/create.cjs

4

data/patch.json

@@ -637,6 +637,2 @@ {

},
"page-size": {
"comment": "https://www.w3.org/TR/css-page-3/#typedef-page-size-page-size",
"syntax": "A5 | A4 | A3 | B5 | B4 | JIS-B5 | JIS-B4 | letter | legal | ledger"
},
"ratio": {

@@ -643,0 +639,0 @@ "comment": "missed, https://drafts.csswg.org/mediaqueries-4/#typedef-ratio",

@@ -1,4 +0,4 @@

var List = require('../common/List');
import { List } from '../utils/List.js';
module.exports = function createConvertors(walk) {
export function createConvertor(walk) {
return {

@@ -5,0 +5,0 @@ fromPlainObject: function(ast) {

@@ -1,3 +0,4 @@

var createConvertor = require('./create');
import { createConvertor } from './create.js';
import walker from '../walker/index.js';
module.exports = createConvertor(require('../walker'));
export default createConvertor(walker);

@@ -6,15 +6,17 @@ function noop(value) {

function generateMultiplier(multiplier) {
if (multiplier.min === 0 && multiplier.max === 0) {
const { min, max, comma } = multiplier;
if (min === 0 && max === 0) {
return '*';
}
if (multiplier.min === 0 && multiplier.max === 1) {
if (min === 0 && max === 1) {
return '?';
}
if (multiplier.min === 1 && multiplier.max === 0) {
return multiplier.comma ? '#' : '+';
if (min === 1 && max === 0) {
return comma ? '#' : '+';
}
if (multiplier.min === 1 && multiplier.max === 1) {
if (min === 1 && max === 1) {
return '';

@@ -24,6 +26,6 @@ }

return (
(multiplier.comma ? '#' : '') +
(multiplier.min === multiplier.max
? '{' + multiplier.min + '}'
: '{' + multiplier.min + ',' + (multiplier.max !== 0 ? multiplier.max : '') + '}'
(comma ? '#' : '') +
(min === max
? '{' + min + '}'
: '{' + min + ',' + (max !== 0 ? max : '') + '}'
)

@@ -50,9 +52,9 @@ );

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);
const combinator = node.combinator === ' ' || compact ? node.combinator : ' ' + node.combinator + ' ';
const result = node.terms
.map(term => internalGenerate(term, decorate, forceBraces, compact))
.join(combinator);
if (node.explicit || forceBraces) {
result = (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
return (compact || result[0] === ',' ? '[' : '[ ') + result + (compact ? ']' : ' ]');
}

@@ -63,4 +65,4 @@

function generate(node, decorate, forceBraces, compact) {
var result;
function internalGenerate(node, decorate, forceBraces, compact) {
let result;

@@ -77,3 +79,3 @@ switch (node.type) {

return (
generate(node.term, decorate, forceBraces, compact) +
internalGenerate(node.term, decorate, forceBraces, compact) +
decorate(generateMultiplier(node), node)

@@ -118,6 +120,6 @@ );

module.exports = function(node, options) {
var decorate = noop;
var forceBraces = false;
var compact = false;
export function generate(node, options) {
let decorate = noop;
let forceBraces = false;
let compact = false;

@@ -134,3 +136,3 @@ if (typeof options === 'function') {

return generate(node, decorate, forceBraces, compact);
return internalGenerate(node, decorate, forceBraces, compact);
};

@@ -1,6 +0,4 @@

module.exports = {
SyntaxError: require('./SyntaxError'),
parse: require('./parse'),
generate: require('./generate'),
walk: require('./walk')
};
export { SyntaxError } from './SyntaxError.js';
export { generate } from './generate.js';
export { parse } from './parse.js';
export { walk } from './walk.js';

@@ -1,31 +0,32 @@

var Tokenizer = require('./tokenizer');
var TAB = 9;
var N = 10;
var F = 12;
var R = 13;
var SPACE = 32;
var EXCLAMATIONMARK = 33; // !
var NUMBERSIGN = 35; // #
var AMPERSAND = 38; // &
var APOSTROPHE = 39; // '
var LEFTPARENTHESIS = 40; // (
var RIGHTPARENTHESIS = 41; // )
var ASTERISK = 42; // *
var PLUSSIGN = 43; // +
var COMMA = 44; // ,
var HYPERMINUS = 45; // -
var LESSTHANSIGN = 60; // <
var GREATERTHANSIGN = 62; // >
var QUESTIONMARK = 63; // ?
var COMMERCIALAT = 64; // @
var LEFTSQUAREBRACKET = 91; // [
var RIGHTSQUAREBRACKET = 93; // ]
var LEFTCURLYBRACKET = 123; // {
var VERTICALLINE = 124; // |
var RIGHTCURLYBRACKET = 125; // }
var INFINITY = 8734; // ∞
var NAME_CHAR = createCharMap(function(ch) {
return /[a-zA-Z0-9\-]/.test(ch);
});
var COMBINATOR_PRECEDENCE = {
import { Tokenizer } from './tokenizer.js';
const TAB = 9;
const N = 10;
const F = 12;
const R = 13;
const SPACE = 32;
const EXCLAMATIONMARK = 33; // !
const NUMBERSIGN = 35; // #
const AMPERSAND = 38; // &
const APOSTROPHE = 39; // '
const LEFTPARENTHESIS = 40; // (
const RIGHTPARENTHESIS = 41; // )
const ASTERISK = 42; // *
const PLUSSIGN = 43; // +
const COMMA = 44; // ,
const HYPERMINUS = 45; // -
const LESSTHANSIGN = 60; // <
const GREATERTHANSIGN = 62; // >
const QUESTIONMARK = 63; // ?
const COMMERCIALAT = 64; // @
const LEFTSQUAREBRACKET = 91; // [
const RIGHTSQUAREBRACKET = 93; // ]
const LEFTCURLYBRACKET = 123; // {
const VERTICALLINE = 124; // |
const RIGHTCURLYBRACKET = 125; // }
const INFINITY = 8734; // ∞
const NAME_CHAR = new Uint8Array(128).map((_, idx) =>
/[a-zA-Z0-9\-]/.test(String.fromCharCode(idx)) ? 1 : 0
);
const COMBINATOR_PRECEDENCE = {
' ': 1,

@@ -37,10 +38,2 @@ '&&': 2,

function createCharMap(fn) {
var array = typeof Uint32Array === 'function' ? new Uint32Array(128) : new Array(128);
for (var i = 0; i < 128; i++) {
array[i] = fn(String.fromCharCode(i)) ? 1 : 0;
}
return array;
}
function scanSpaces(tokenizer) {

@@ -53,6 +46,6 @@ return tokenizer.substringToPos(

function scanWord(tokenizer) {
var end = tokenizer.pos;
let end = tokenizer.pos;
for (; end < tokenizer.str.length; end++) {
var code = tokenizer.str.charCodeAt(end);
const code = tokenizer.str.charCodeAt(end);
if (code >= 128 || NAME_CHAR[code] === 0) {

@@ -71,6 +64,6 @@ break;

function scanNumber(tokenizer) {
var end = tokenizer.pos;
let end = tokenizer.pos;
for (; end < tokenizer.str.length; end++) {
var code = tokenizer.str.charCodeAt(end);
const code = tokenizer.str.charCodeAt(end);
if (code < 48 || code > 57) {

@@ -89,3 +82,3 @@ break;

function scanString(tokenizer) {
var end = tokenizer.str.indexOf('\'', tokenizer.pos + 1);
const end = tokenizer.str.indexOf('\'', tokenizer.pos + 1);

@@ -101,4 +94,4 @@ if (end === -1) {

function readMultiplierRange(tokenizer) {
var min = null;
var max = null;
let min = null;
let max = null;

@@ -127,4 +120,4 @@ tokenizer.eat(LEFTCURLYBRACKET);

function readMultiplier(tokenizer) {
var range = null;
var comma = false;
let range = null;
let comma = false;

@@ -188,3 +181,3 @@ switch (tokenizer.charCode()) {

type: 'Multiplier',
comma: comma,
comma,
min: range.min,

@@ -197,3 +190,3 @@ max: range.max,

function maybeMultiplied(tokenizer, node) {
var multiplier = readMultiplier(tokenizer);
const multiplier = readMultiplier(tokenizer);

@@ -209,3 +202,3 @@ if (multiplier !== null) {

function maybeToken(tokenizer) {
var ch = tokenizer.peek();
const ch = tokenizer.peek();

@@ -223,3 +216,3 @@ if (ch === '') {

function readProperty(tokenizer) {
var name;
let name;

@@ -236,3 +229,3 @@ tokenizer.eat(LESSTHANSIGN);

type: 'Property',
name: name
name
});

@@ -250,5 +243,5 @@ }

// use null for Infinity to make AST format JSON serializable/deserializable
var min = null; // -Infinity
var max = null; // Infinity
var sign = 1;
let min = null; // -Infinity
let max = null; // Infinity
let sign = 1;

@@ -295,4 +288,4 @@ tokenizer.eat(LEFTSQUAREBRACKET);

type: 'Range',
min: min,
max: max
min,
max
};

@@ -302,4 +295,4 @@ }

function readType(tokenizer) {
var name;
var opts = null;
let name;
let opts = null;

@@ -324,4 +317,4 @@ tokenizer.eat(LESSTHANSIGN);

type: 'Type',
name: name,
opts: opts
name,
opts
});

@@ -331,6 +324,4 @@ }

function readKeywordOrFunction(tokenizer) {
var name;
const name = scanWord(tokenizer);
name = scanWord(tokenizer);
if (tokenizer.charCode() === LEFTPARENTHESIS) {

@@ -341,3 +332,3 @@ tokenizer.pos++;

type: 'Function',
name: name
name
};

@@ -348,3 +339,3 @@ }

type: 'Keyword',
name: name
name
});

@@ -357,4 +348,4 @@ }

type: 'Group',
terms: terms,
combinator: combinator,
terms,
combinator,
disallowEmpty: false,

@@ -365,10 +356,16 @@ explicit: false

combinators = Object.keys(combinators).sort(function(a, b) {
return COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b];
});
let combinator;
combinators = Object.keys(combinators)
.sort((a, b) => COMBINATOR_PRECEDENCE[a] - COMBINATOR_PRECEDENCE[b]);
while (combinators.length > 0) {
var combinator = combinators.shift();
for (var i = 0, subgroupStart = 0; i < terms.length; i++) {
var term = terms[i];
combinator = combinators.shift();
let i = 0;
let subgroupStart = 0;
for (; i < terms.length; i++) {
const term = terms[i];
if (term.type === 'Combinator') {

@@ -408,7 +405,7 @@ if (term.value === combinator) {

function readImplicitGroup(tokenizer) {
var terms = [];
var combinators = {};
var token;
var prevToken = null;
var prevTokenPos = tokenizer.pos;
const terms = [];
const combinators = {};
let token;
let prevToken = null;
let prevTokenPos = tokenizer.pos;

@@ -447,3 +444,3 @@ while (token = peek(tokenizer)) {

type: 'Group',
terms: terms,
terms,
combinator: regroupTerms(terms, combinators) || ' ',

@@ -456,3 +453,3 @@ disallowEmpty: false,

function readGroup(tokenizer) {
var result;
let result;

@@ -474,3 +471,3 @@ tokenizer.eat(LEFTSQUAREBRACKET);

function peek(tokenizer) {
var code = tokenizer.charCode();
let code = tokenizer.charCode();

@@ -498,5 +495,3 @@ if (code < 128 && NAME_CHAR[code] === 1) {

value: tokenizer.substringToPos(
tokenizer.nextCharCode() === VERTICALLINE
? tokenizer.pos + 2
: tokenizer.pos + 1
tokenizer.pos + (tokenizer.nextCharCode() === VERTICALLINE ? 2 : 1)
)

@@ -573,5 +568,5 @@ };

function parse(source) {
var tokenizer = new Tokenizer(source);
var result = readImplicitGroup(tokenizer);
export function parse(source) {
const tokenizer = new Tokenizer(source);
const result = readImplicitGroup(tokenizer);

@@ -584,12 +579,6 @@ if (tokenizer.pos !== source.length) {

if (result.terms.length === 1 && result.terms[0].type === 'Group') {
result = result.terms[0];
return result.terms[0];
}
return result;
}
// warm up parse to elimitate code branches that never execute
// fix soft deoptimizations (insufficient type feedback)
parse('[a&&<b>#|<\'c\'>*||e() f{2} /,(% g#{1,2} h{2,})]!');
module.exports = parse;
};

@@ -1,14 +0,12 @@

var createCustomError = require('../utils/createCustomError');
import { createCustomError } from '../utils/create-custom-error.js';
module.exports = function SyntaxError(message, input, offset) {
var error = createCustomError('SyntaxError', message);
error.input = input;
error.offset = offset;
error.rawMessage = message;
error.message = error.rawMessage + '\n' +
' ' + error.input + '\n' +
'--' + new Array((error.offset || error.input.length) + 1).join('-') + '^';
return error;
export function SyntaxError(message, input, offset) {
return Object.assign(createCustomError('SyntaxError', message), {
input,
offset,
rawMessage: message,
message: message + '\n' +
' ' + input + '\n' +
'--' + new Array((offset || input.length) + 1).join('-') + '^'
});
};

@@ -1,30 +0,29 @@

var SyntaxError = require('./SyntaxError');
import { SyntaxError } from './SyntaxError.js';
var TAB = 9;
var N = 10;
var F = 12;
var R = 13;
var SPACE = 32;
const TAB = 9;
const N = 10;
const F = 12;
const R = 13;
const SPACE = 32;
var Tokenizer = function(str) {
this.str = str;
this.pos = 0;
};
Tokenizer.prototype = {
charCodeAt: function(pos) {
export class Tokenizer {
constructor(str) {
this.str = str;
this.pos = 0;
}
charCodeAt(pos) {
return pos < this.str.length ? this.str.charCodeAt(pos) : 0;
},
charCode: function() {
}
charCode() {
return this.charCodeAt(this.pos);
},
nextCharCode: function() {
}
nextCharCode() {
return this.charCodeAt(this.pos + 1);
},
nextNonWsCode: function(pos) {
}
nextNonWsCode(pos) {
return this.charCodeAt(this.findWsEnd(pos));
},
findWsEnd: function(pos) {
}
findWsEnd(pos) {
for (; pos < this.str.length; pos++) {
var code = this.str.charCodeAt(pos);
const code = this.str.charCodeAt(pos);
if (code !== R && code !== N && code !== F && code !== SPACE && code !== TAB) {

@@ -36,7 +35,7 @@ break;

return pos;
},
substringToPos: function(end) {
}
substringToPos(end) {
return this.str.substring(this.pos, this.pos = end);
},
eat: function(code) {
}
eat(code) {
if (this.charCode() !== code) {

@@ -47,11 +46,9 @@ this.error('Expect `' + String.fromCharCode(code) + '`');

this.pos++;
},
peek: function() {
}
peek() {
return this.pos < this.str.length ? this.str.charAt(this.pos++) : '';
},
error: function(message) {
}
error(message) {
throw new SyntaxError(message, this.str, this.pos);
}
};
module.exports = Tokenizer;

@@ -1,2 +0,2 @@

var noop = function() {};
const noop = function() {};

@@ -7,3 +7,3 @@ function ensureFunction(value) {

module.exports = function(node, options, context) {
export function walk(node, options, context) {
function walk(node) {

@@ -38,4 +38,4 @@ enter.call(context, node);

var enter = noop;
var leave = noop;
let enter = noop;
let leave = noop;

@@ -42,0 +42,0 @@ if (typeof options === 'function') {

@@ -1,12 +0,12 @@

var sourceMap = require('./sourceMap');
var hasOwnProperty = Object.prototype.hasOwnProperty;
import { tokenize, Delim, WhiteSpace } from '../tokenizer/index.js';
import { generateSourceMap } from './sourceMap.js';
import * as tokenBefore from './token-before.js';
const REVERSESOLIDUS = 0x005c; // U+005C REVERSE SOLIDUS (\)
function processChildren(node, delimeter) {
var list = node.children;
var prev = null;
if (typeof delimeter === 'function') {
let prev = null;
if (typeof delimeter !== 'function') {
list.forEach(this.node, this);
} else {
list.forEach(function(node) {
node.children.forEach(node => {
if (prev !== null) {

@@ -18,32 +18,48 @@ delimeter.call(this, prev);

prev = node;
}, this);
});
return;
}
node.children.forEach(this.node, this);
}
module.exports = function createGenerator(config) {
function processNode(node) {
if (hasOwnProperty.call(types, node.type)) {
types[node.type].call(this, node);
} else {
throw new Error('Unknown node type: ' + node.type);
}
}
function processChunk(chunk) {
tokenize(chunk, (type, start, end) => {
this.token(type, chunk.slice(start, end));
});
}
var types = {};
export function createGenerator(config) {
const types = new Map();
if (config.node) {
for (var name in config.node) {
types[name] = config.node[name].generate;
}
for (let name in config.node) {
types.set(name, config.node[name].generate);
}
return function(node, options) {
var buffer = '';
var handlers = {
children: processChildren,
node: processNode,
chunk: function(chunk) {
buffer += chunk;
let buffer = '';
let prevCode = 0;
let handlers = {
node(node) {
if (types.has(node.type)) {
types.get(node.type).call(publicApi, node);
} else {
throw new Error('Unknown node type: ' + node.type);
}
},
result: function() {
tokenBefore: tokenBefore.safe,
token(type, value) {
prevCode = this.tokenBefore(prevCode, type, value);
this.emit(value, type, false);
if (type === Delim && value.charCodeAt(0) === REVERSESOLIDUS) {
this.emit('\n', WhiteSpace, true);
}
},
emit(value) {
buffer += value;
},
result() {
return buffer;

@@ -59,6 +75,17 @@ }

if (options.sourceMap) {
handlers = sourceMap(handlers);
handlers = generateSourceMap(handlers);
}
if (options.mode in tokenBefore) {
handlers.tokenBefore = tokenBefore[options.mode];
}
}
const publicApi = {
node: (node) => handlers.node(node),
children: processChildren,
token: (type, value) => handlers.token(type, value),
tokenize: processChunk
};
handlers.node(node);

@@ -65,0 +92,0 @@

@@ -1,4 +0,4 @@

var createGenerator = require('./create');
var config = require('../syntax/config/parser');
import { createGenerator } from './create.js';
import config from '../syntax/config/generator.js';
module.exports = createGenerator(config);
export default createGenerator(config);

@@ -1,34 +0,31 @@

var SourceMapGenerator = require('source-map/lib/source-map-generator').SourceMapGenerator;
var trackNodes = {
Atrule: true,
Selector: true,
Declaration: true
};
import { SourceMapGenerator } from 'source-map/lib/source-map-generator.js';
module.exports = function generateSourceMap(handlers) {
var map = new SourceMapGenerator();
var line = 1;
var column = 0;
var generated = {
const trackNodes = new Set(['Atrule', 'Selector', 'Declaration']);
export function generateSourceMap(handlers) {
const map = new SourceMapGenerator();
const generated = {
line: 1,
column: 0
};
var original = {
const original = {
line: 0, // should be zero to add first mapping
column: 0
};
var sourceMappingActive = false;
var activatedGenerated = {
const activatedGenerated = {
line: 1,
column: 0
};
var activatedMapping = {
const activatedMapping = {
generated: activatedGenerated
};
let line = 1;
let column = 0;
let sourceMappingActive = false;
var handlersNode = handlers.node;
const origHandlersNode = handlers.node;
handlers.node = function(node) {
if (node.loc && node.loc.start && trackNodes.hasOwnProperty(node.type)) {
var nodeLine = node.loc.start.line;
var nodeColumn = node.loc.start.column - 1;
if (node.loc && node.loc.start && trackNodes.has(node.type)) {
const nodeLine = node.loc.start.line;
const nodeColumn = node.loc.start.column - 1;

@@ -54,4 +51,4 @@ if (original.line !== nodeLine ||

source: node.loc.source,
original: original,
generated: generated
original,
generated
});

@@ -61,5 +58,5 @@ }

handlersNode.call(this, node);
origHandlersNode.call(this, node);
if (sourceMappingActive && trackNodes.hasOwnProperty(node.type)) {
if (sourceMappingActive && trackNodes.has(node.type)) {
activatedGenerated.line = line;

@@ -70,6 +67,6 @@ activatedGenerated.column = column;

var handlersChunk = handlers.chunk;
handlers.chunk = function(chunk) {
for (var i = 0; i < chunk.length; i++) {
if (chunk.charCodeAt(i) === 10) { // \n
const origHandlersEmit = handlers.emit;
handlers.emit = function(value, type, auto) {
for (let i = 0; i < value.length; i++) {
if (value.charCodeAt(i) === 10) { // \n
line++;

@@ -82,6 +79,6 @@ column = 0;

handlersChunk(chunk);
origHandlersEmit(value, type, auto);
};
var handlersResult = handlers.result;
const origHandlersResult = handlers.result;
handlers.result = function() {

@@ -93,4 +90,4 @@ if (sourceMappingActive) {

return {
css: handlersResult(),
map: map
css: origHandlersResult(),
map
};

@@ -97,0 +94,0 @@ };

@@ -1,1 +0,30 @@

module.exports = require('./syntax');
import syntax from './syntax/index.js';
export * from './version.js';
export { default as createSyntax } from './syntax/create.js';
export { List } from './utils/List.js';
export { Lexer } from './lexer/Lexer.js';
export { tokenTypes, tokenNames, TokenStream } from './tokenizer/index.js';
export * as definitionSyntax from './definition-syntax/index.js';
export { clone } from './utils/clone.js';
export * from './utils/names.js';
export * as ident from './utils/ident.js';
export * as string from './utils/string.js';
export * as url from './utils/url.js';
export const {
tokenize,
parse,
generate,
lexer,
createLexer,
walk,
find,
findLast,
findAll,
toPlainObject,
fromPlainObject,
fork
} = syntax;

@@ -1,3 +0,4 @@

const createCustomError = require('../utils/createCustomError');
const generate = require('../definition-syntax/generate');
import { createCustomError } from '../utils/create-custom-error.js';
import { generate } from '../definition-syntax/generate.js';
const defaultLoc = { offset: 0, line: 1, column: 1 };

@@ -83,3 +84,3 @@

const SyntaxReferenceError = function(type, referenceName) {
export const SyntaxReferenceError = function(type, referenceName) {
const error = createCustomError(

@@ -95,3 +96,3 @@ 'SyntaxReferenceError',

const SyntaxMatchError = function(message, syntax, node, matchResult) {
export const SyntaxMatchError = function(message, syntax, node, matchResult) {
const error = createCustomError('SyntaxMatchError', message);

@@ -125,6 +126,1 @@ const {

};
module.exports = {
SyntaxReferenceError,
SyntaxMatchError
};

@@ -1,23 +0,24 @@

var isDigit = require('../tokenizer').isDigit;
var cmpChar = require('../tokenizer').cmpChar;
var TYPE = require('../tokenizer').TYPE;
import {
isDigit,
cmpChar,
Delim,
WhiteSpace,
Comment,
Ident,
Number as NumberToken,
Dimension
} from '../tokenizer/index.js';
var DELIM = TYPE.Delim;
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var IDENT = TYPE.Ident;
var NUMBER = TYPE.Number;
var DIMENSION = TYPE.Dimension;
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
var N = 0x006E; // U+006E LATIN SMALL LETTER N (n)
var DISALLOW_SIGN = true;
var ALLOW_SIGN = false;
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
const N = 0x006E; // U+006E LATIN SMALL LETTER N (n)
const DISALLOW_SIGN = true;
const ALLOW_SIGN = false;
function isDelim(token, code) {
return token !== null && token.type === DELIM && token.value.charCodeAt(0) === code;
return token !== null && token.type === Delim && token.value.charCodeAt(0) === code;
}
function skipSC(token, offset, getNextToken) {
while (token !== null && (token.type === WHITESPACE || token.type === COMMENT)) {
while (token !== null && (token.type === WhiteSpace || token.type === Comment)) {
token = getNextToken(++offset);

@@ -34,3 +35,3 @@ }

var code = token.value.charCodeAt(valueOffset);
const code = token.value.charCodeAt(valueOffset);

@@ -58,4 +59,4 @@ if (code === PLUSSIGN || code === HYPHENMINUS) {

function consumeB(token, offset_, getNextToken) {
var sign = false;
var offset = skipSC(token, offset_, getNextToken);
let sign = false;
let offset = skipSC(token, offset_, getNextToken);

@@ -68,3 +69,3 @@ token = getNextToken(offset);

if (token.type !== NUMBER) {
if (token.type !== NumberToken) {
if (isDelim(token, PLUSSIGN) || isDelim(token, HYPHENMINUS)) {

@@ -75,3 +76,3 @@ sign = true;

if (token === null && token.type !== NUMBER) {
if (token === null || token.type !== NumberToken) {
return 0;

@@ -85,3 +86,3 @@ }

if (!sign) {
var code = token.value.charCodeAt(0);
const code = token.value.charCodeAt(0);
if (code !== PLUSSIGN && code !== HYPHENMINUS) {

@@ -97,5 +98,5 @@ // Number sign is expected

// An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
module.exports = function anPlusB(token, getNextToken) {
export default function anPlusB(token, getNextToken) {
/* eslint-disable brace-style*/
var offset = 0;
let offset = 0;

@@ -107,3 +108,3 @@ if (!token) {

// <integer>
if (token.type === NUMBER) {
if (token.type === NumberToken) {
return checkInteger(token, 0, ALLOW_SIGN, offset); // b

@@ -117,3 +118,3 @@ }

// <dashndashdigit-ident>
else if (token.type === IDENT && token.value.charCodeAt(0) === HYPHENMINUS) {
else if (token.type === Ident && token.value.charCodeAt(0) === HYPHENMINUS) {
// expect 1st char is N

@@ -157,5 +158,5 @@ if (!cmpChar(token.value, 1, N)) {

// '+'? <ndashdigit-ident>
else if (token.type === IDENT || (isDelim(token, PLUSSIGN) && getNextToken(offset + 1).type === IDENT)) {
else if (token.type === Ident || (isDelim(token, PLUSSIGN) && getNextToken(offset + 1).type === Ident)) {
// just ignore a plus
if (token.type !== IDENT) {
if (token.type !== Ident) {
token = getNextToken(++offset);

@@ -201,7 +202,8 @@ }

// <n-dimension> ['+' | '-'] <signless-integer>
else if (token.type === DIMENSION) {
var code = token.value.charCodeAt(0);
var sign = code === PLUSSIGN || code === HYPHENMINUS ? 1 : 0;
else if (token.type === Dimension) {
let code = token.value.charCodeAt(0);
let sign = code === PLUSSIGN || code === HYPHENMINUS ? 1 : 0;
let i = sign;
for (var i = sign; i < token.value.length; i++) {
for (; i < token.value.length; i++) {
if (!isDigit(token.value.charCodeAt(i))) {

@@ -208,0 +210,0 @@ break;

@@ -1,16 +0,17 @@

var isHexDigit = require('../tokenizer').isHexDigit;
var cmpChar = require('../tokenizer').cmpChar;
var TYPE = require('../tokenizer').TYPE;
import {
isHexDigit,
cmpChar,
Ident,
Delim,
Number as NumberToken,
Dimension
} from '../tokenizer/index.js';
var IDENT = TYPE.Ident;
var DELIM = TYPE.Delim;
var NUMBER = TYPE.Number;
var DIMENSION = TYPE.Dimension;
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
var QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
const QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
const U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
function isDelim(token, code) {
return token !== null && token.type === DELIM && token.value.charCodeAt(0) === code;
return token !== null && token.type === Delim && token.value.charCodeAt(0) === code;
}

@@ -23,11 +24,10 @@

function hexSequence(token, offset, allowDash) {
for (var pos = offset, hexlen = 0; pos < token.value.length; pos++) {
var code = token.value.charCodeAt(pos);
let hexlen = 0;
for (let pos = offset; pos < token.value.length; pos++) {
const code = token.value.charCodeAt(pos);
if (code === HYPHENMINUS && allowDash && hexlen !== 0) {
if (hexSequence(token, offset + hexlen + 1, false) > 0) {
return 6; // dissallow following question marks
}
return 0; // dash at the ending of a hex sequence is not allowed
hexSequence(token, offset + hexlen + 1, false);
return 6; // dissallow following question marks
}

@@ -82,7 +82,7 @@

// u '+' '?'+
module.exports = function urange(token, getNextToken) {
var length = 0;
export default function urange(token, getNextToken) {
let length = 0;
// should start with `u` or `U`
if (token === null || token.type !== IDENT || !cmpChar(token.value, 0, U)) {
if (token === null || token.type !== Ident || !cmpChar(token.value, 0, U)) {
return 0;

@@ -104,3 +104,3 @@ }

if (token.type === IDENT) {
if (token.type === Ident) {
// u '+' <ident-token> '?'*

@@ -122,8 +122,4 @@ return withQuestionMarkSequence(hexSequence(token, 0, true), ++length, getNextToken);

// u <number-token> <number-token>
if (token.type === NUMBER) {
if (!startsWith(token, PLUSSIGN)) {
return 0;
}
var consumedHexLength = hexSequence(token, 1, true);
if (token.type === NumberToken) {
const consumedHexLength = hexSequence(token, 1, true);
if (consumedHexLength === 0) {

@@ -139,3 +135,3 @@ return 0;

if (token.type === DIMENSION || token.type === NUMBER) {
if (token.type === Dimension || token.type === NumberToken) {
// u <number-token> <dimension-token>

@@ -155,7 +151,3 @@ // u <number-token> <number-token>

// u <dimension-token> '?'*
if (token.type === DIMENSION) {
if (!startsWith(token, PLUSSIGN)) {
return 0;
}
if (token.type === Dimension) {
return withQuestionMarkSequence(hexSequence(token, 1, true), ++length, getNextToken);

@@ -162,0 +154,0 @@ }

@@ -1,79 +0,59 @@

var tokenizer = require('../tokenizer');
var isIdentifierStart = tokenizer.isIdentifierStart;
var isHexDigit = tokenizer.isHexDigit;
var isDigit = tokenizer.isDigit;
var cmpStr = tokenizer.cmpStr;
var consumeNumber = tokenizer.consumeNumber;
var TYPE = tokenizer.TYPE;
var anPlusB = require('./generic-an-plus-b');
var urange = require('./generic-urange');
import anPlusB from './generic-an-plus-b.js';
import urange from './generic-urange.js';
import {
isIdentifierStart,
isHexDigit,
isDigit,
cmpStr,
consumeNumber,
var cssWideKeywords = ['unset', 'initial', 'inherit'];
var calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc('];
Ident,
Function as FunctionToken,
AtKeyword,
Hash,
String as StringToken,
BadString,
Url,
BadUrl,
Delim,
Number as NumberToken,
Percentage,
Dimension,
WhiteSpace,
CDO,
CDC,
Colon,
Semicolon,
Comma,
LeftSquareBracket,
RightSquareBracket,
LeftParenthesis,
RightParenthesis,
LeftCurlyBracket,
RightCurlyBracket
} from '../tokenizer/index.js';
// https://www.w3.org/TR/css-values-3/#lengths
var LENGTH = {
// absolute length units
'px': true,
'mm': true,
'cm': true,
'in': true,
'pt': true,
'pc': true,
'q': true,
const cssWideKeywords = ['unset', 'initial', 'inherit'];
const calcFunctionNames = ['calc(', '-moz-calc(', '-webkit-calc('];
const balancePair = new Map([
[FunctionToken, RightParenthesis],
[LeftParenthesis, RightParenthesis],
[LeftSquareBracket, RightSquareBracket],
[LeftCurlyBracket, RightCurlyBracket]
]);
// relative length units
'em': true,
'ex': true,
'ch': true,
'rem': true,
// units
const LENGTH = [ // https://www.w3.org/TR/css-values-3/#lengths
'px', 'mm', 'cm', 'in', 'pt', 'pc', 'q', // absolute length units
'em', 'ex', 'ch', 'rem', // relative length units
'vh', 'vw', 'vmin', 'vmax', 'vm' // viewport-percentage lengths
];
const ANGLE = ['deg', 'grad', 'rad', 'turn']; // https://www.w3.org/TR/css-values-3/#angles
const TIME = ['s', 'ms']; // https://www.w3.org/TR/css-values-3/#time
const FREQUENCY = ['hz', 'khz']; // https://www.w3.org/TR/css-values-3/#frequency
const RESOLUTION = ['dpi', 'dpcm', 'dppx', 'x']; // https://www.w3.org/TR/css-values-3/#resolution
const FLEX = ['fr']; // https://drafts.csswg.org/css-grid/#fr-unit
const DECIBEL = ['db']; // https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume
const SEMITONES = ['st']; // https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch
// viewport-percentage lengths
'vh': true,
'vw': true,
'vmin': true,
'vmax': true,
'vm': true
};
var ANGLE = {
'deg': true,
'grad': true,
'rad': true,
'turn': true
};
var TIME = {
's': true,
'ms': true
};
var FREQUENCY = {
'hz': true,
'khz': true
};
// https://www.w3.org/TR/css-values-3/#resolution (https://drafts.csswg.org/css-values/#resolution)
var RESOLUTION = {
'dpi': true,
'dpcm': true,
'dppx': true,
'x': true // https://github.com/w3c/csswg-drafts/issues/461
};
// https://drafts.csswg.org/css-grid/#fr-unit
var FLEX = {
'fr': true
};
// https://www.w3.org/TR/css3-speech/#mixing-props-voice-volume
var DECIBEL = {
'db': true
};
// https://www.w3.org/TR/css3-speech/#voice-props-voice-pitch
var SEMITONES = {
'st': true
};
// safe char code getter

@@ -89,3 +69,3 @@ function charCode(str, index) {

function eqStrAny(actual, expected) {
for (var i = 0; i < expected.length; i++) {
for (let i = 0; i < expected.length; i++) {
if (eqStr(actual, expected[i])) {

@@ -113,3 +93,3 @@ return true;

if (opts && opts.type === 'Range') {
var num = Number(
const num = Number(
numEnd !== undefined && numEnd !== value.length

@@ -137,12 +117,30 @@ ? value.substr(0, numEnd)

function consumeFunction(token, getNextToken) {
var startIdx = token.index;
var length = 0;
let balanceCloseType = 0;
let balanceStash = [];
let length = 0;
// balanced token consuming
scan:
do {
length++;
switch (token.type) {
case RightCurlyBracket:
case RightParenthesis:
case RightSquareBracket:
if (token.type !== balanceCloseType) {
break scan;
}
if (token.balance <= startIdx) {
break;
balanceCloseType = balanceStash.pop();
break;
case FunctionToken:
case LeftParenthesis:
case LeftSquareBracket:
case LeftCurlyBracket:
balanceStash.push(balanceCloseType);
balanceCloseType = balancePair.get(token.type);
break;
}
length++;
} while (token = getNextToken(length));

@@ -162,3 +160,3 @@

if (token.type === TYPE.Function && eqStrAny(token.value, calcFunctionNames)) {
if (token.type === FunctionToken && eqStrAny(token.value, calcFunctionNames)) {
return consumeFunction(token, getNextToken);

@@ -205,7 +203,7 @@ }

function customIdent(token) {
if (token === null || token.type !== TYPE.Ident) {
if (token === null || token.type !== Ident) {
return 0;
}
var name = token.value.toLowerCase();
const name = token.value.toLowerCase();

@@ -238,3 +236,3 @@ // The CSS-wide keywords are not valid <custom-ident>s

// ... defined as any valid identifier
if (token === null || token.type !== TYPE.Ident) {
if (token === null || token.type !== Ident) {
return 0;

@@ -256,7 +254,7 @@ }

function hexColor(token) {
if (token === null || token.type !== TYPE.Hash) {
if (token === null || token.type !== Hash) {
return 0;
}
var length = token.value.length;
const length = token.value.length;

@@ -268,3 +266,3 @@ // valid values (length): #rgb (4), #rgba (5), #rrggbb (7), #rrggbbaa (9)

for (var i = 1; i < length; i++) {
for (let i = 1; i < length; i++) {
if (!isHexDigit(token.value.charCodeAt(i))) {

@@ -279,3 +277,3 @@ return 0;

function idSelector(token) {
if (token === null || token.type !== TYPE.Hash) {
if (token === null || token.type !== Hash) {
return 0;

@@ -298,30 +296,30 @@ }

var length = 0;
var level = 0;
var startIdx = token.index;
let balanceCloseType = 0;
let balanceStash = [];
let length = 0;
// The <declaration-value> production matches any sequence of one or more tokens,
// so long as the sequence ...
// so long as the sequence does not contain ...
scan:
do {
switch (token.type) {
// ... does not contain <bad-string-token>, <bad-url-token>,
case TYPE.BadString:
case TYPE.BadUrl:
// ... <bad-string-token>, <bad-url-token>,
case BadString:
case BadUrl:
break scan;
// ... unmatched <)-token>, <]-token>, or <}-token>,
case TYPE.RightCurlyBracket:
case TYPE.RightParenthesis:
case TYPE.RightSquareBracket:
if (token.balance > token.index || token.balance < startIdx) {
case RightCurlyBracket:
case RightParenthesis:
case RightSquareBracket:
if (token.type !== balanceCloseType) {
break scan;
}
level--;
balanceCloseType = balanceStash.pop();
break;
// ... or top-level <semicolon-token> tokens
case TYPE.Semicolon:
if (level === 0) {
case Semicolon:
if (balanceCloseType === 0) {
break scan;

@@ -333,4 +331,4 @@ }

// ... or <delim-token> tokens with a value of "!"
case TYPE.Delim:
if (token.value === '!' && level === 0) {
case Delim:
if (balanceCloseType === 0 && token.value === '!') {
break scan;

@@ -341,7 +339,8 @@ }

case TYPE.Function:
case TYPE.LeftParenthesis:
case TYPE.LeftSquareBracket:
case TYPE.LeftCurlyBracket:
level++;
case FunctionToken:
case LeftParenthesis:
case LeftSquareBracket:
case LeftCurlyBracket:
balanceStash.push(balanceCloseType);
balanceCloseType = balancePair.get(token.type);
break;

@@ -351,7 +350,2 @@ }

length++;
// until balance closing
if (token.balance <= startIdx) {
break;
}
} while (token = getNextToken(length));

@@ -371,4 +365,5 @@

var startIdx = token.index;
var length = 0;
let balanceCloseType = 0;
let balanceStash = [];
let length = 0;

@@ -381,23 +376,27 @@ // The <any-value> production matches any sequence of one or more tokens,

// ... does not contain <bad-string-token>, <bad-url-token>,
case TYPE.BadString:
case TYPE.BadUrl:
case BadString:
case BadUrl:
break scan;
// ... unmatched <)-token>, <]-token>, or <}-token>,
case TYPE.RightCurlyBracket:
case TYPE.RightParenthesis:
case TYPE.RightSquareBracket:
if (token.balance > token.index || token.balance < startIdx) {
case RightCurlyBracket:
case RightParenthesis:
case RightSquareBracket:
if (token.type !== balanceCloseType) {
break scan;
}
balanceCloseType = balanceStash.pop();
break;
case FunctionToken:
case LeftParenthesis:
case LeftSquareBracket:
case LeftCurlyBracket:
balanceStash.push(balanceCloseType);
balanceCloseType = balancePair.get(token.type);
break;
}
length++;
// until balance closing
if (token.balance <= startIdx) {
break;
}
} while (token = getNextToken(length));

@@ -413,8 +412,12 @@

function dimension(type) {
if (type) {
type = new Set(type);
}
return function(token, getNextToken, opts) {
if (token === null || token.type !== TYPE.Dimension) {
if (token === null || token.type !== Dimension) {
return 0;
}
var numberEnd = consumeNumber(token.value, 0);
const numberEnd = consumeNumber(token.value, 0);

@@ -424,8 +427,8 @@ // check unit

// check for IE postfix hack, i.e. 123px\0 or 123px\9
var reverseSolidusOffset = token.value.indexOf('\\', numberEnd);
var unit = reverseSolidusOffset === -1 || !isPostfixIeHack(token.value, reverseSolidusOffset)
const reverseSolidusOffset = token.value.indexOf('\\', numberEnd);
const unit = reverseSolidusOffset === -1 || !isPostfixIeHack(token.value, reverseSolidusOffset)
? token.value.substr(numberEnd)
: token.value.substring(numberEnd, reverseSolidusOffset);
if (type.hasOwnProperty(unit.toLowerCase()) === false) {
if (type.has(unit.toLowerCase()) === false) {
return 0;

@@ -452,3 +455,3 @@ }

// ... corresponds to the <percentage-token> production
if (token === null || token.type !== TYPE.Percentage) {
if (token === null || token.type !== Percentage) {
return 0;

@@ -481,3 +484,3 @@ }

return function(token, getNextToken, opts) {
if (token !== null && token.type === TYPE.Number) {
if (token !== null && token.type === NumberToken) {
if (Number(token.value) === 0) {

@@ -501,4 +504,4 @@ return 1;

var numberEnd = consumeNumber(token.value, 0);
var isNumber = numberEnd === token.value.length;
const numberEnd = consumeNumber(token.value, 0);
const isNumber = numberEnd === token.value.length;
if (!isNumber && !isPostfixIeHack(token.value, numberEnd)) {

@@ -520,3 +523,3 @@ return 0;

// ... corresponds to a subset of the <number-token> production
if (token === null || token.type !== TYPE.Number) {
if (token === null || token.type !== NumberToken) {
return 0;

@@ -526,3 +529,3 @@ }

// The first digit of an integer may be immediately preceded by `-` or `+` to indicate the integer’s sign.
var i = token.value.charCodeAt(0) === 0x002B || // U+002B PLUS SIGN (+)
let i = token.value.charCodeAt(0) === 0x002B || // U+002B PLUS SIGN (+)
token.value.charCodeAt(0) === 0x002D ? 1 : 0; // U+002D HYPHEN-MINUS (-)

@@ -545,32 +548,32 @@

module.exports = {
export default {
// token types
'ident-token': tokenType(TYPE.Ident),
'function-token': tokenType(TYPE.Function),
'at-keyword-token': tokenType(TYPE.AtKeyword),
'hash-token': tokenType(TYPE.Hash),
'string-token': tokenType(TYPE.String),
'bad-string-token': tokenType(TYPE.BadString),
'url-token': tokenType(TYPE.Url),
'bad-url-token': tokenType(TYPE.BadUrl),
'delim-token': tokenType(TYPE.Delim),
'number-token': tokenType(TYPE.Number),
'percentage-token': tokenType(TYPE.Percentage),
'dimension-token': tokenType(TYPE.Dimension),
'whitespace-token': tokenType(TYPE.WhiteSpace),
'CDO-token': tokenType(TYPE.CDO),
'CDC-token': tokenType(TYPE.CDC),
'colon-token': tokenType(TYPE.Colon),
'semicolon-token': tokenType(TYPE.Semicolon),
'comma-token': tokenType(TYPE.Comma),
'[-token': tokenType(TYPE.LeftSquareBracket),
']-token': tokenType(TYPE.RightSquareBracket),
'(-token': tokenType(TYPE.LeftParenthesis),
')-token': tokenType(TYPE.RightParenthesis),
'{-token': tokenType(TYPE.LeftCurlyBracket),
'}-token': tokenType(TYPE.RightCurlyBracket),
'ident-token': tokenType(Ident),
'function-token': tokenType(FunctionToken),
'at-keyword-token': tokenType(AtKeyword),
'hash-token': tokenType(Hash),
'string-token': tokenType(StringToken),
'bad-string-token': tokenType(BadString),
'url-token': tokenType(Url),
'bad-url-token': tokenType(BadUrl),
'delim-token': tokenType(Delim),
'number-token': tokenType(NumberToken),
'percentage-token': tokenType(Percentage),
'dimension-token': tokenType(Dimension),
'whitespace-token': tokenType(WhiteSpace),
'CDO-token': tokenType(CDO),
'CDC-token': tokenType(CDC),
'colon-token': tokenType(Colon),
'semicolon-token': tokenType(Semicolon),
'comma-token': tokenType(Comma),
'[-token': tokenType(LeftSquareBracket),
']-token': tokenType(RightSquareBracket),
'(-token': tokenType(LeftParenthesis),
')-token': tokenType(RightParenthesis),
'{-token': tokenType(LeftCurlyBracket),
'}-token': tokenType(RightCurlyBracket),
// token type aliases
'string': tokenType(TYPE.String),
'ident': tokenType(TYPE.Ident),
'string': tokenType(StringToken),
'ident': tokenType(Ident),

@@ -577,0 +580,0 @@ // complex types

@@ -1,3 +0,1 @@

module.exports = {
Lexer: require('./Lexer')
};
export { Lexer } from './Lexer.js';

@@ -1,25 +0,23 @@

var SyntaxReferenceError = require('./error').SyntaxReferenceError;
var SyntaxMatchError = require('./error').SyntaxMatchError;
var names = require('../utils/names');
var generic = require('./generic');
var parse = require('../definition-syntax/parse');
var generate = require('../definition-syntax/generate');
var walk = require('../definition-syntax/walk');
var prepareTokens = require('./prepare-tokens');
var buildMatchGraph = require('./match-graph').buildMatchGraph;
var matchAsTree = require('./match').matchAsTree;
var trace = require('./trace');
var search = require('./search');
var getStructureFromConfig = require('./structure').getStructureFromConfig;
var cssWideKeywords = buildMatchGraph('inherit | initial | unset');
var cssWideKeywordsWithExpression = buildMatchGraph('inherit | initial | unset | <-ms-legacy-expression>');
import { SyntaxReferenceError, SyntaxMatchError } from './error.js';
import * as names from '../utils/names.js';
import generic from './generic.js';
import { parse, generate, walk } from '../definition-syntax/index.js';
import prepareTokens from './prepare-tokens.js';
import { buildMatchGraph } from './match-graph.js';
import { matchAsTree } from './match.js';
import * as trace from './trace.js';
import { matchFragments } from './search.js';
import { getStructureFromConfig } from './structure.js';
const cssWideKeywords = buildMatchGraph('inherit | initial | unset');
const cssWideKeywordsWithExpression = buildMatchGraph('inherit | initial | unset | <-ms-legacy-expression>');
function dumpMapSyntax(map, compact, syntaxAsAst) {
var result = {};
const result = {};
for (var name in map) {
for (const name in map) {
if (map[name].syntax) {
result[name] = syntaxAsAst
? map[name].syntax
: generate(map[name].syntax, { compact: compact });
: generate(map[name].syntax, { compact });
}

@@ -49,3 +47,3 @@ }

function valueHasVar(tokens) {
for (var i = 0; i < tokens.length; i++) {
for (let i = 0; i < tokens.length; i++) {
if (tokens[i].value.toLowerCase() === 'var(') {

@@ -59,11 +57,8 @@ return true;

function buildMatchResult(match, error, iterations) {
function buildMatchResult(matched, error, iterations) {
return {
matched: match,
iterations: iterations,
error: error,
getTrace: trace.getTrace,
isType: trace.isType,
isProperty: trace.isProperty,
isKeyword: trace.isKeyword
matched,
iterations,
error,
...trace
};

@@ -73,4 +68,4 @@ }

function matchSyntax(lexer, syntax, value, useCommon) {
var tokens = prepareTokens(value, lexer.syntax);
var result;
const tokens = prepareTokens(value, lexer.syntax);
let result;

@@ -99,51 +94,47 @@ if (valueHasVar(tokens)) {

var Lexer = function(config, syntax, structure) {
this.valueCommonSyntax = cssWideKeywords;
this.syntax = syntax;
this.generic = false;
this.atrules = {};
this.properties = {};
this.types = {};
this.structure = structure || getStructureFromConfig(config);
export class Lexer {
constructor(config, syntax, structure) {
this.valueCommonSyntax = cssWideKeywords;
this.syntax = syntax;
this.generic = false;
this.atrules = Object.create(null);
this.properties = Object.create(null);
this.types = Object.create(null);
this.structure = structure || getStructureFromConfig(config);
if (config) {
if (config.types) {
for (var name in config.types) {
this.addType_(name, config.types[name]);
if (config) {
if (config.types) {
for (const name in config.types) {
this.addType_(name, config.types[name]);
}
}
}
if (config.generic) {
this.generic = true;
for (var name in generic) {
this.addType_(name, generic[name]);
if (config.generic) {
this.generic = true;
for (const name in generic) {
this.addType_(name, generic[name]);
}
}
}
if (config.atrules) {
for (var name in config.atrules) {
this.addAtrule_(name, config.atrules[name]);
if (config.atrules) {
for (const name in config.atrules) {
this.addAtrule_(name, config.atrules[name]);
}
}
}
if (config.properties) {
for (var name in config.properties) {
this.addProperty_(name, config.properties[name]);
if (config.properties) {
for (const name in config.properties) {
this.addProperty_(name, config.properties[name]);
}
}
}
}
};
Lexer.prototype = {
structure: {},
checkStructure: function(ast) {
checkStructure(ast) {
function collectWarning(node, message) {
warns.push({
node: node,
message: message
});
warns.push({ node, message });
}
var structure = this.structure;
var warns = [];
const structure = this.structure;
const warns = [];

@@ -159,13 +150,14 @@ this.syntax.walk(ast, function(node) {

return warns.length ? warns : false;
},
}
createDescriptor: function(syntax, type, name, parent = null) {
var ref = {
type: type,
name: name
createDescriptor(syntax, type, name, parent = null) {
const ref = {
type,
name
};
var descriptor = {
type: type,
name: name,
parent: parent,
const descriptor = {
type,
name,
parent,
serializable: typeof syntax === 'string' || (syntax && typeof syntax.type === 'string'),
syntax: null,

@@ -181,3 +173,3 @@ match: null

Object.defineProperty(descriptor, 'syntax', {
get: function() {
get() {
Object.defineProperty(descriptor, 'syntax', {

@@ -196,3 +188,3 @@ value: parse(syntax)

Object.defineProperty(descriptor, 'match', {
get: function() {
get() {
Object.defineProperty(descriptor, 'match', {

@@ -208,4 +200,4 @@ value: buildMatchGraph(descriptor.syntax, ref)

return descriptor;
},
addAtrule_: function(name, syntax) {
}
addAtrule_(name, syntax) {
if (!syntax) {

@@ -220,10 +212,13 @@ return;

descriptors: syntax.descriptors
? Object.keys(syntax.descriptors).reduce((res, descName) => {
res[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
return res;
}, {})
? Object.keys(syntax.descriptors).reduce(
(map, descName) => {
map[descName] = this.createDescriptor(syntax.descriptors[descName], 'AtruleDescriptor', descName, name);
return map;
},
Object.create(null)
)
: null
};
},
addProperty_: function(name, syntax) {
}
addProperty_(name, syntax) {
if (!syntax) {

@@ -234,4 +229,4 @@ return;

this.properties[name] = this.createDescriptor(syntax, 'Property', name);
},
addType_: function(name, syntax) {
}
addType_(name, syntax) {
if (!syntax) {

@@ -246,11 +241,11 @@ return;

}
},
}
checkAtruleName: function(atruleName) {
checkAtruleName(atruleName) {
if (!this.getAtrule(atruleName)) {
return new SyntaxReferenceError('Unknown at-rule', '@' + atruleName);
}
},
checkAtrulePrelude: function(atruleName, prelude) {
let error = this.checkAtruleName(atruleName);
}
checkAtrulePrelude(atruleName, prelude) {
const error = this.checkAtruleName(atruleName);

@@ -261,3 +256,3 @@ if (error) {

var atrule = this.getAtrule(atruleName);
const atrule = this.getAtrule(atruleName);

@@ -271,5 +266,5 @@ if (!atrule.prelude && prelude) {

}
},
checkAtruleDescriptorName: function(atruleName, descriptorName) {
let error = this.checkAtruleName(atruleName);
}
checkAtruleDescriptorName(atruleName, descriptorName) {
const error = this.checkAtruleName(atruleName);

@@ -280,4 +275,4 @@ if (error) {

var atrule = this.getAtrule(atruleName);
var descriptor = names.keyword(descriptorName);
const atrule = this.getAtrule(atruleName);
const descriptor = names.keyword(descriptorName);

@@ -292,18 +287,11 @@ if (!atrule.descriptors) {

}
},
checkPropertyName: function(propertyName) {
var property = names.property(propertyName);
// don't match syntax for a custom property
if (property.custom) {
return new Error('Lexer matching doesn\'t applicable for custom properties');
}
}
checkPropertyName(propertyName) {
if (!this.getProperty(propertyName)) {
return new SyntaxReferenceError('Unknown property', propertyName);
}
},
}
matchAtrulePrelude: function(atruleName, prelude) {
var error = this.checkAtrulePrelude(atruleName, prelude);
matchAtrulePrelude(atruleName, prelude) {
const error = this.checkAtrulePrelude(atruleName, prelude);

@@ -319,5 +307,5 @@ if (error) {

return matchSyntax(this, this.getAtrule(atruleName).prelude, prelude, false);
},
matchAtruleDescriptor: function(atruleName, descriptorName, value) {
var error = this.checkAtruleDescriptorName(atruleName, descriptorName);
}
matchAtruleDescriptor(atruleName, descriptorName, value) {
const error = this.checkAtruleDescriptorName(atruleName, descriptorName);

@@ -328,8 +316,8 @@ if (error) {

var atrule = this.getAtrule(atruleName);
var descriptor = names.keyword(descriptorName);
const atrule = this.getAtrule(atruleName);
const descriptor = names.keyword(descriptorName);
return matchSyntax(this, atrule.descriptors[descriptor.name] || atrule.descriptors[descriptor.basename], value, false);
},
matchDeclaration: function(node) {
}
matchDeclaration(node) {
if (node.type !== 'Declaration') {

@@ -340,6 +328,11 @@ return buildMatchResult(null, new Error('Not a Declaration node'));

return this.matchProperty(node.property, node.value);
},
matchProperty: function(propertyName, value) {
var error = this.checkPropertyName(propertyName);
}
matchProperty(propertyName, value) {
// don't match syntax for a custom property at the moment
if (names.property(propertyName).custom) {
return buildMatchResult(null, new Error('Lexer matching doesn\'t applicable for custom properties'));
}
const error = this.checkPropertyName(propertyName);
if (error) {

@@ -350,5 +343,5 @@ return buildMatchResult(null, error);

return matchSyntax(this, this.getProperty(propertyName), value, true);
},
matchType: function(typeName, value) {
var typeSyntax = this.getType(typeName);
}
matchType(typeName, value) {
const typeSyntax = this.getType(typeName);

@@ -360,4 +353,4 @@ if (!typeSyntax) {

return matchSyntax(this, typeSyntax, value, false);
},
match: function(syntax, value) {
}
match(syntax, value) {
if (typeof syntax !== 'string' && (!syntax || !syntax.type)) {

@@ -372,26 +365,26 @@ return buildMatchResult(null, new SyntaxReferenceError('Bad syntax'));

return matchSyntax(this, syntax, value, false);
},
}
findValueFragments: function(propertyName, value, type, name) {
return search.matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
},
findDeclarationValueFragments: function(declaration, type, name) {
return search.matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
},
findAllFragments: function(ast, type, name) {
var result = [];
findValueFragments(propertyName, value, type, name) {
return matchFragments(this, value, this.matchProperty(propertyName, value), type, name);
}
findDeclarationValueFragments(declaration, type, name) {
return matchFragments(this, declaration.value, this.matchDeclaration(declaration), type, name);
}
findAllFragments(ast, type, name) {
const result = [];
this.syntax.walk(ast, {
visit: 'Declaration',
enter: function(declaration) {
enter: (declaration) => {
result.push.apply(result, this.findDeclarationValueFragments(declaration, type, name));
}.bind(this)
}
});
return result;
},
}
getAtrule: function(atruleName, fallbackBasename = true) {
var atrule = names.keyword(atruleName);
var atruleEntry = atrule.vendor && fallbackBasename
getAtrule(atruleName, fallbackBasename = true) {
const atrule = names.keyword(atruleName);
const atruleEntry = atrule.vendor && fallbackBasename
? this.atrules[atrule.name] || this.atrules[atrule.basename]

@@ -401,16 +394,16 @@ : this.atrules[atrule.name];

return atruleEntry || null;
},
getAtrulePrelude: function(atruleName, fallbackBasename = true) {
}
getAtrulePrelude(atruleName, fallbackBasename = true) {
const atrule = this.getAtrule(atruleName, fallbackBasename);
return atrule && atrule.prelude || null;
},
getAtruleDescriptor: function(atruleName, name) {
}
getAtruleDescriptor(atruleName, name) {
return this.atrules.hasOwnProperty(atruleName) && this.atrules.declarators
? this.atrules[atruleName].declarators[name] || null
: null;
},
getProperty: function(propertyName, fallbackBasename = true) {
var property = names.property(propertyName);
var propertyEntry = property.vendor && fallbackBasename
}
getProperty(propertyName, fallbackBasename = true) {
const property = names.property(propertyName);
const propertyEntry = property.vendor && fallbackBasename
? this.properties[property.name] || this.properties[property.basename]

@@ -420,14 +413,14 @@ : this.properties[property.name];

return propertyEntry || null;
},
getType: function(name) {
return this.types.hasOwnProperty(name) ? this.types[name] : null;
},
}
getType(name) {
return hasOwnProperty.call(this.types, name) ? this.types[name] : null;
}
validate: function() {
validate() {
function validate(syntax, name, broken, descriptor) {
if (broken.hasOwnProperty(name)) {
return broken[name];
if (broken.has(name)) {
return broken.get(name);
}
broken[name] = false;
broken.set(name, false);
if (descriptor.syntax !== null) {

@@ -439,7 +432,7 @@ walk(descriptor.syntax, function(node) {

var map = node.type === 'Type' ? syntax.types : syntax.properties;
var brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
const map = node.type === 'Type' ? syntax.types : syntax.properties;
const brokenMap = node.type === 'Type' ? brokenTypes : brokenProperties;
if (!map.hasOwnProperty(node.name) || validate(syntax, node.name, brokenMap, map[node.name])) {
broken[name] = true;
if (!hasOwnProperty.call(map, node.name) || validate(syntax, node.name, brokenMap, map[node.name])) {
broken.set(name, true);
}

@@ -450,19 +443,15 @@ }, this);

var brokenTypes = {};
var brokenProperties = {};
let brokenTypes = new Map();
let brokenProperties = new Map();
for (var key in this.types) {
for (const key in this.types) {
validate(this, key, brokenTypes, this.types[key]);
}
for (var key in this.properties) {
for (const key in this.properties) {
validate(this, key, brokenProperties, this.properties[key]);
}
brokenTypes = Object.keys(brokenTypes).filter(function(name) {
return brokenTypes[name];
});
brokenProperties = Object.keys(brokenProperties).filter(function(name) {
return brokenProperties[name];
});
brokenTypes = [...brokenTypes.keys()].filter(name => brokenTypes.get(name));
brokenProperties = [...brokenProperties.keys()].filter(name => brokenProperties.get(name));

@@ -477,4 +466,4 @@ if (brokenTypes.length || brokenProperties.length) {

return null;
},
dump: function(syntaxAsAst, pretty) {
}
dump(syntaxAsAst, pretty) {
return {

@@ -486,8 +475,6 @@ generic: this.generic,

};
},
toString: function() {
}
toString() {
return JSON.stringify(this.dump());
}
};
module.exports = Lexer;

@@ -1,9 +0,10 @@

var parse = require('../definition-syntax/parse');
import { parse } from '../definition-syntax/parse.js';
var MATCH = { type: 'Match' };
var MISMATCH = { type: 'Mismatch' };
var DISALLOW_EMPTY = { type: 'DisallowEmpty' };
var LEFTPARENTHESIS = 40; // (
var RIGHTPARENTHESIS = 41; // )
export const MATCH = { type: 'Match' };
export const MISMATCH = { type: 'Mismatch' };
export const DISALLOW_EMPTY = { type: 'DisallowEmpty' };
const LEFTPARENTHESIS = 40; // (
const RIGHTPARENTHESIS = 41; // )
function createCondition(match, thenBranch, elseBranch) {

@@ -26,3 +27,3 @@ // reduce node count

type: 'If',
match: match,
match,
then: thenBranch,

@@ -52,3 +53,3 @@ else: elseBranch

switch (combinator) {
case ' ':
case ' ': {
// Juxtaposing components means that all of them must occur, in the given order.

@@ -65,6 +66,6 @@ //

// else MISMATCH
var result = MATCH;
let result = MATCH;
for (var i = terms.length - 1; i >= 0; i--) {
var term = terms[i];
for (let i = terms.length - 1; i >= 0; i--) {
const term = terms[i];

@@ -79,4 +80,5 @@ result = createCondition(

return result;
}
case '|':
case '|': {
// A bar (|) separates two or more alternatives: exactly one of them must occur.

@@ -94,7 +96,7 @@ //

var result = MISMATCH;
var map = null;
let result = MISMATCH;
let map = null;
for (var i = terms.length - 1; i >= 0; i--) {
var term = terms[i];
for (let i = terms.length - 1; i >= 0; i--) {
let term = terms[i];

@@ -108,3 +110,3 @@ // reduce sequence of keywords into a Enum

type: 'Enum',
map: map
map
},

@@ -117,3 +119,3 @@ MATCH,

if (map !== null) {
var key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase();
const key = (isFunctionType(term.name) ? term.name.slice(0, -1) : term.name).toLowerCase();
if (key in map === false) {

@@ -137,4 +139,5 @@ map[key] = term;

return result;
}
case '&&':
case '&&': {
// A double ampersand (&&) separates two or more components,

@@ -148,3 +151,3 @@ // all of which must occur, in any order.

type: 'MatchOnce',
terms: terms,
terms,
all: true

@@ -177,7 +180,7 @@ };

// else MISMATCH
var result = MISMATCH;
let result = MISMATCH;
for (var i = terms.length - 1; i >= 0; i--) {
var term = terms[i];
var thenClause;
for (let i = terms.length - 1; i >= 0; i--) {
const term = terms[i];
let thenClause;

@@ -204,4 +207,5 @@ if (terms.length > 1) {

return result;
}
case '||':
case '||': {
// A double bar (||) separates two or more options:

@@ -215,3 +219,3 @@ // one or more of them must occur, in any order.

type: 'MatchOnce',
terms: terms,
terms,
all: false

@@ -244,7 +248,7 @@ };

// else MISMATCH
var result = atLeastOneTermMatched ? MATCH : MISMATCH;
let result = atLeastOneTermMatched ? MATCH : MISMATCH;
for (var i = terms.length - 1; i >= 0; i--) {
var term = terms[i];
var thenClause;
for (let i = terms.length - 1; i >= 0; i--) {
const term = terms[i];
let thenClause;

@@ -271,2 +275,3 @@ if (terms.length > 1) {

return result;
}
}

@@ -276,4 +281,4 @@ }

function buildMultiplierMatchGraph(node) {
var result = MATCH;
var matchTerm = buildMatchGraph(node.term);
let result = MATCH;
let matchTerm = buildMatchGraphInternal(node.term);

@@ -311,3 +316,3 @@ if (node.max === 0) {

// create a match node chain for [min .. max] interval with optional matches
for (var i = node.min || 1; i <= node.max; i++) {
for (let i = node.min || 1; i <= node.max; i++) {
if (node.comma && result !== MATCH) {

@@ -342,3 +347,3 @@ result = createCondition(

// create a match node chain to collect [0 ... min - 1] required matches
for (var i = 0; i < node.min - 1; i++) {
for (let i = 0; i < node.min - 1; i++) {
if (node.comma && result !== MATCH) {

@@ -363,3 +368,3 @@ result = createCondition(

function buildMatchGraph(node) {
function buildMatchGraphInternal(node) {
if (typeof node === 'function') {

@@ -373,6 +378,6 @@ return {

switch (node.type) {
case 'Group':
var result = buildGroupMatchGraph(
case 'Group': {
let result = buildGroupMatchGraph(
node.combinator,
node.terms.map(buildMatchGraph),
node.terms.map(buildMatchGraphInternal),
false

@@ -390,2 +395,3 @@ );

return result;
}

@@ -459,18 +465,13 @@ case 'Multiplier':

module.exports = {
MATCH: MATCH,
MISMATCH: MISMATCH,
DISALLOW_EMPTY: DISALLOW_EMPTY,
buildMatchGraph: function(syntaxTree, ref) {
if (typeof syntaxTree === 'string') {
syntaxTree = parse(syntaxTree);
}
export function buildMatchGraph(syntaxTree, ref) {
if (typeof syntaxTree === 'string') {
syntaxTree = parse(syntaxTree);
}
return {
type: 'MatchGraph',
match: buildMatchGraph(syntaxTree),
syntax: ref || null,
source: syntaxTree
};
}
};
return {
type: 'MatchGraph',
match: buildMatchGraphInternal(syntaxTree),
syntax: ref || null,
source: syntaxTree
};
}

@@ -1,24 +0,21 @@

var hasOwnProperty = Object.prototype.hasOwnProperty;
var matchGraph = require('./match-graph');
var MATCH = matchGraph.MATCH;
var MISMATCH = matchGraph.MISMATCH;
var DISALLOW_EMPTY = matchGraph.DISALLOW_EMPTY;
var TYPE = require('../tokenizer/const').TYPE;
import { MATCH, MISMATCH, DISALLOW_EMPTY } from './match-graph.js';
import * as TYPE from '../tokenizer/types.js';
var STUB = 0;
var TOKEN = 1;
var OPEN_SYNTAX = 2;
var CLOSE_SYNTAX = 3;
const { hasOwnProperty } = Object.prototype;
const STUB = 0;
const TOKEN = 1;
const OPEN_SYNTAX = 2;
const CLOSE_SYNTAX = 3;
var EXIT_REASON_MATCH = 'Match';
var EXIT_REASON_MISMATCH = 'Mismatch';
var EXIT_REASON_ITERATION_LIMIT = 'Maximum iteration number exceeded (please fill an issue on https://github.com/csstree/csstree/issues)';
const EXIT_REASON_MATCH = 'Match';
const EXIT_REASON_MISMATCH = 'Mismatch';
const EXIT_REASON_ITERATION_LIMIT = 'Maximum iteration number exceeded (please fill an issue on https://github.com/csstree/csstree/issues)';
var ITERATION_LIMIT = 15000;
var totalIterationCount = 0;
const ITERATION_LIMIT = 15000;
export let totalIterationCount = 0;
function reverseList(list) {
var prev = null;
var next = null;
var item = list;
let prev = null;
let next = null;
let item = list;

@@ -40,5 +37,5 @@ while (item !== null) {

for (var i = 0; i < testStr.length; i++) {
var testCode = testStr.charCodeAt(i);
var referenceCode = referenceStr.charCodeAt(i);
for (let i = 0; i < testStr.length; i++) {
const referenceCode = referenceStr.charCodeAt(i);
let testCode = testStr.charCodeAt(i);

@@ -105,3 +102,3 @@ // testCode.toLowerCase() for U+0041 LATIN CAPITAL LETTER A (A) .. U+005A LATIN CAPITAL LETTER Z (Z).

function getNextToken(offset) {
var nextIndex = tokenIndex + offset;
const nextIndex = tokenIndex + offset;

@@ -113,8 +110,8 @@ return nextIndex < tokens.length ? tokens[nextIndex] : null;

return {
nextState: nextState,
matchStack: matchStack,
syntaxStack: syntaxStack,
thenStack: thenStack,
tokenIndex: tokenIndex,
prev: prev
nextState,
matchStack,
syntaxStack,
thenStack,
tokenIndex,
prev
};

@@ -125,5 +122,5 @@ }

thenStack = {
nextState: nextState,
matchStack: matchStack,
syntaxStack: syntaxStack,
nextState,
matchStack,
syntaxStack,
prev: thenStack

@@ -141,3 +138,3 @@ };

syntax: state.syntax,
token: token,
token,
prev: matchStack

@@ -184,5 +181,5 @@ };

var syntaxStack = null;
var thenStack = null;
var elseStack = null;
let syntaxStack = null;
let thenStack = null;
let elseStack = null;

@@ -192,11 +189,11 @@ // null – stashing allowed, nothing stashed

// anithing else – fail stashable syntaxes, some syntax stashed
var syntaxStash = null;
let syntaxStash = null;
var iterationCount = 0; // count iterations and prevent infinite loop
var exitReason = null;
let iterationCount = 0; // count iterations and prevent infinite loop
let exitReason = null;
var token = null;
var tokenIndex = -1;
var longestMatch = 0;
var matchStack = {
let token = null;
let tokenIndex = -1;
let longestMatch = 0;
let matchStack = {
type: STUB,

@@ -212,3 +209,3 @@ syntax: null,

// function mapList(list, fn) {
// var result = [];
// const result = [];
// while (list) {

@@ -325,4 +322,4 @@ // result.unshift(fn(list));

case 'MatchOnceBuffer':
var terms = state.syntax.terms;
case 'MatchOnceBuffer': {
const terms = state.syntax.terms;

@@ -348,3 +345,3 @@ if (state.index === terms.length) {

for (; state.index < terms.length; state.index++) {
var matchFlag = 1 << state.index;
const matchFlag = 1 << state.index;

@@ -367,2 +364,3 @@ if ((state.mask & matchFlag) === 0) {

break;
}

@@ -380,3 +378,3 @@ case 'AddMatchOnce':

if (token !== null) {
var name = token.value.toLowerCase();
let name = token.value.toLowerCase();

@@ -397,5 +395,5 @@ // drop \0 and \9 hack from keyword name

case 'Generic':
var opts = syntaxStack !== null ? syntaxStack.opts : null;
var lastTokenIndex = tokenIndex + Math.floor(state.fn(token, getNextToken, opts));
case 'Generic': {
const opts = syntaxStack !== null ? syntaxStack.opts : null;
const lastTokenIndex = tokenIndex + Math.floor(state.fn(token, getNextToken, opts));

@@ -413,7 +411,8 @@ if (!isNaN(lastTokenIndex) && lastTokenIndex > tokenIndex) {

break;
}
case 'Type':
case 'Property':
var syntaxDict = state.type === 'Type' ? 'types' : 'properties';
var dictSyntax = hasOwnProperty.call(syntaxes, syntaxDict) ? syntaxes[syntaxDict][state.name] : null;
case 'Property': {
const syntaxDict = state.type === 'Type' ? 'types' : 'properties';
const dictSyntax = hasOwnProperty.call(syntaxes, syntaxDict) ? syntaxes[syntaxDict][state.name] : null;

@@ -431,3 +430,3 @@ if (!dictSyntax || !dictSyntax.match) {

if (syntaxStash !== false && token !== null && state.type === 'Type') {
var lowPriorityMatching =
const lowPriorityMatching =
// https://drafts.csswg.org/css-values-4/#custom-idents

@@ -456,8 +455,9 @@ // When parsing positionally-ambiguous keywords in a property value, a <custom-ident> production

break;
}
case 'Keyword':
var name = state.name;
case 'Keyword': {
const name = state.name;
if (token !== null) {
var keywordName = token.value;
let keywordName = token.value;

@@ -478,2 +478,3 @@ // drop \0 and \9 hack from keyword name

break;
}

@@ -516,5 +517,6 @@ case 'AtKeyword':

case 'String':
var string = '';
let string = '';
let lastTokenIndex = tokenIndex;
for (var lastTokenIndex = tokenIndex; lastTokenIndex < tokens.length && string.length < state.value.length; lastTokenIndex++) {
for (; lastTokenIndex < tokens.length && string.length < state.value.length; lastTokenIndex++) {
string += tokens[lastTokenIndex].value;

@@ -560,15 +562,15 @@ }

return {
tokens: tokens,
tokens,
reason: exitReason,
iterations: iterationCount,
match: matchStack,
longestMatch: longestMatch
longestMatch
};
}
function matchAsList(tokens, matchGraph, syntaxes) {
var matchResult = internalMatch(tokens, matchGraph, syntaxes || {});
export function matchAsList(tokens, matchGraph, syntaxes) {
const matchResult = internalMatch(tokens, matchGraph, syntaxes || {});
if (matchResult.match !== null) {
var item = reverseList(matchResult.match).prev;
let item = reverseList(matchResult.match).prev;

@@ -579,5 +581,2 @@ matchResult.match = [];

switch (item.type) {
case STUB:
break;
case OPEN_SYNTAX:

@@ -606,4 +605,4 @@ case CLOSE_SYNTAX:

function matchAsTree(tokens, matchGraph, syntaxes) {
var matchResult = internalMatch(tokens, matchGraph, syntaxes || {});
export function matchAsTree(tokens, matchGraph, syntaxes) {
const matchResult = internalMatch(tokens, matchGraph, syntaxes || {});

@@ -614,8 +613,8 @@ if (matchResult.match === null) {

var item = matchResult.match;
var host = matchResult.match = {
let item = matchResult.match;
let host = matchResult.match = {
syntax: matchGraph.syntax || null,
match: []
};
var hostStack = [host];
const hostStack = [host];

@@ -654,9 +653,1 @@ // revert a list and start with 2nd item since 1st is a stub item

}
module.exports = {
matchAsList: matchAsList,
matchAsTree: matchAsTree,
getTotalIterationCount: function() {
return totalIterationCount;
}
};

@@ -1,15 +0,12 @@

var tokenize = require('../tokenizer');
var TokenStream = require('../common/TokenStream');
var tokenStream = new TokenStream();
var astToTokens = {
import { tokenize } from '../tokenizer/index.js';
const astToTokens = {
decorator: function(handlers) {
var curNode = null;
var prev = { len: 0, node: null };
var nodes = [prev];
var buffer = '';
const tokens = [];
let curNode = null;
return {
children: handlers.children,
node: function(node) {
var tmp = curNode;
...handlers,
node(node) {
const tmp = curNode;
curNode = node;

@@ -19,15 +16,11 @@ handlers.node.call(this, node);

},
chunk: function(chunk) {
buffer += chunk;
if (prev.node !== curNode) {
nodes.push({
len: chunk.length,
node: curNode
});
} else {
prev.len += chunk.length;
}
emit(value, type, auto) {
tokens.push({
type,
value,
node: auto ? null : curNode
});
},
result: function() {
return prepareTokens(buffer, nodes);
result() {
return tokens;
}

@@ -38,28 +31,12 @@ };

function prepareTokens(str, nodes) {
var tokens = [];
var nodesOffset = 0;
var nodesIndex = 0;
var currentNode = nodes ? nodes[nodesIndex].node : null;
function stringToTokens(str) {
const tokens = [];
tokenize(str, tokenStream);
while (!tokenStream.eof) {
if (nodes) {
while (nodesIndex < nodes.length && nodesOffset + nodes[nodesIndex].len <= tokenStream.tokenStart) {
nodesOffset += nodes[nodesIndex++].len;
currentNode = nodes[nodesIndex].node;
}
}
tokenize(str, (type, start, end) =>
tokens.push({
type: tokenStream.tokenType,
value: tokenStream.getTokenValue(),
index: tokenStream.tokenIndex, // TODO: remove it, temporary solution
balance: tokenStream.balance[tokenStream.tokenIndex], // TODO: remove it, temporary solution
node: currentNode
});
tokenStream.next();
// console.log({ ...tokens[tokens.length - 1], node: undefined });
}
type,
value: str.slice(start, end),
node: null
})
);

@@ -69,5 +46,5 @@ return tokens;

module.exports = function(value, syntax) {
export default function(value, syntax) {
if (typeof value === 'string') {
return prepareTokens(value, null);
return stringToTokens(value);
}

@@ -74,0 +51,0 @@

@@ -1,2 +0,2 @@

var List = require('../common/List');
import { List } from '../utils/List.js';

@@ -19,3 +19,3 @@ function getFirstMatchNode(matchNode) {

function matchFragments(lexer, ast, match, type, name) {
export function matchFragments(lexer, ast, match, type, name) {
function findFragments(matchNode) {

@@ -25,8 +25,8 @@ if (matchNode.syntax !== null &&

matchNode.syntax.name === name) {
var start = getFirstMatchNode(matchNode);
var end = getLastMatchNode(matchNode);
const start = getFirstMatchNode(matchNode);
const end = getLastMatchNode(matchNode);
lexer.syntax.walk(ast, function(node, item, list) {
if (node === start) {
var nodes = new List();
const nodes = new List();

@@ -45,3 +45,3 @@ do {

parent: list,
nodes: nodes
nodes
});

@@ -57,3 +57,3 @@ }

var fragments = [];
const fragments = [];

@@ -66,5 +66,1 @@ if (match.matched !== null) {

}
module.exports = {
matchFragments: matchFragments
};

@@ -1,4 +0,5 @@

var List = require('../common/List');
var hasOwnProperty = Object.prototype.hasOwnProperty;
import { List } from '../utils/List.js';
const { hasOwnProperty } = Object.prototype;
function isValidNumber(value) {

@@ -29,4 +30,4 @@ // Number.isInteger(value) && value >= 0

for (var key in node) {
var valid = true;
for (let key in node) {
let valid = true;

@@ -58,5 +59,7 @@ if (hasOwnProperty.call(node, key) === false) {

} else if (fields.hasOwnProperty(key)) {
for (var i = 0, valid = false; !valid && i < fields[key].length; i++) {
var fieldType = fields[key][i];
valid = false;
for (let i = 0; !valid && i < fields[key].length; i++) {
const fieldType = fields[key][i];
switch (fieldType) {

@@ -92,3 +95,3 @@ case String:

for (var key in fields) {
for (const key in fields) {
if (hasOwnProperty.call(fields, key) &&

@@ -103,12 +106,12 @@ hasOwnProperty.call(node, key) === false) {

function processStructure(name, nodeType) {
var structure = nodeType.structure;
var fields = {
const structure = nodeType.structure;
const fields = {
type: String,
loc: true
};
var docs = {
const docs = {
type: '"' + name + '"'
};
for (var key in structure) {
for (const key in structure) {
if (hasOwnProperty.call(structure, key) === false) {

@@ -118,9 +121,9 @@ continue;

var docsTypes = [];
var fieldTypes = fields[key] = Array.isArray(structure[key])
const docsTypes = [];
const fieldTypes = fields[key] = Array.isArray(structure[key])
? structure[key].slice()
: [structure[key]];
for (var i = 0; i < fieldTypes.length; i++) {
var fieldType = fieldTypes[i];
for (let i = 0; i < fieldTypes.length; i++) {
const fieldType = fieldTypes[i];
if (fieldType === String || fieldType === Boolean) {

@@ -143,3 +146,3 @@ docsTypes.push(fieldType.name);

return {
docs: docs,
docs,
check: createNodeStructureChecker(name, fields)

@@ -149,22 +152,20 @@ };

module.exports = {
getStructureFromConfig: function(config) {
var structure = {};
export function getStructureFromConfig(config) {
const structure = {};
if (config.node) {
for (var name in config.node) {
if (hasOwnProperty.call(config.node, name)) {
var nodeType = config.node[name];
if (config.node) {
for (const name in config.node) {
if (hasOwnProperty.call(config.node, name)) {
const nodeType = config.node[name];
if (nodeType.structure) {
structure[name] = processStructure(name, nodeType);
} else {
throw new Error('Missed `structure` field in `' + name + '` node type definition');
}
if (nodeType.structure) {
structure[name] = processStructure(name, nodeType);
} else {
throw new Error('Missed `structure` field in `' + name + '` node type definition');
}
}
}
}
return structure;
}
return structure;
};

@@ -1,2 +0,2 @@

function getTrace(node) {
export function getTrace(node) {
function shouldPutToTrace(syntax) {

@@ -17,3 +17,3 @@ if (syntax === null) {

// use for-loop for better perfomance
for (var i = 0; i < matchNode.match.length; i++) {
for (let i = 0; i < matchNode.match.length; i++) {
if (hasMatch(matchNode.match[i])) {

@@ -38,3 +38,3 @@ if (shouldPutToTrace(matchNode.syntax)) {

var result = null;
let result = null;

@@ -48,4 +48,16 @@ if (this.matched !== null) {

export function isType(node, type) {
return testNode(this, node, match => match.type === 'Type' && match.name === type);
}
export function isProperty(node, property) {
return testNode(this, node, match => match.type === 'Property' && match.name === property);
}
export function isKeyword(node) {
return testNode(this, node, match => match.type === 'Keyword');
}
function testNode(match, node, fn) {
var trace = getTrace.call(match, node);
const trace = getTrace.call(match, node);

@@ -58,26 +70,1 @@ if (trace === null) {

}
function isType(node, type) {
return testNode(this, node, function(matchNode) {
return matchNode.type === 'Type' && matchNode.name === type;
});
}
function isProperty(node, property) {
return testNode(this, node, function(matchNode) {
return matchNode.type === 'Property' && matchNode.name === property;
});
}
function isKeyword(node) {
return testNode(this, node, function(matchNode) {
return matchNode.type === 'Keyword';
});
}
module.exports = {
getTrace: getTrace,
isType: isType,
isProperty: isProperty,
isKeyword: isKeyword
};

@@ -1,24 +0,32 @@

var OffsetToLocation = require('../common/OffsetToLocation');
var SyntaxError = require('../common/SyntaxError');
var TokenStream = require('../common/TokenStream');
var List = require('../common/List');
var tokenize = require('../tokenizer');
var constants = require('../tokenizer/const');
var { findWhiteSpaceStart, cmpStr } = require('../tokenizer/utils');
var sequence = require('./sequence');
var noop = function() {};
import { List } from '../utils/List.js';
import { SyntaxError } from './SyntaxError.js';
import {
tokenize,
OffsetToLocation,
TokenStream,
tokenNames,
var TYPE = constants.TYPE;
var NAME = constants.NAME;
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var IDENT = TYPE.Ident;
var FUNCTION = TYPE.Function;
var URL = TYPE.Url;
var HASH = TYPE.Hash;
var PERCENTAGE = TYPE.Percentage;
var NUMBER = TYPE.Number;
var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
var NULL = 0;
consumeNumber,
findWhiteSpaceStart,
cmpChar,
cmpStr,
WhiteSpace,
Comment,
Ident,
Function as FunctionToken,
Url,
Hash,
Percentage,
Number as NumberToken
} from '../tokenizer/index.js';
import { readSequence } from './sequence.js';
const NOOP = () => {};
const EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
const NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
const SEMICOLON = 0x003B; // U+003B SEMICOLON (;)
const LEFTCURLYBRACKET = 0x007B; // U+007B LEFT CURLY BRACKET ({)
const NULL = 0;
function createParseContext(name) {

@@ -30,68 +38,53 @@ return function() {

function processConfig(config) {
var parserConfig = {
context: {},
scope: {},
atrule: {},
pseudo: {}
};
function fetchParseValues(dict) {
const result = Object.create(null);
if (config.parseContext) {
for (var name in config.parseContext) {
switch (typeof config.parseContext[name]) {
case 'function':
parserConfig.context[name] = config.parseContext[name];
break;
for (const name in dict) {
const item = dict[name];
case 'string':
parserConfig.context[name] = createParseContext(config.parseContext[name]);
break;
}
if (item.parse) {
result[name] = item.parse;
}
}
if (config.scope) {
for (var name in config.scope) {
parserConfig.scope[name] = config.scope[name];
}
}
return result;
}
if (config.atrule) {
for (var name in config.atrule) {
var atrule = config.atrule[name];
function processConfig(config) {
const parseConfig = {
context: Object.create(null),
scope: Object.assign(Object.create(null), config.scope),
atrule: fetchParseValues(config.atrule),
pseudo: fetchParseValues(config.pseudo),
node: fetchParseValues(config.node)
};
if (atrule.parse) {
parserConfig.atrule[name] = atrule.parse;
}
}
}
for (const name in config.parseContext) {
switch (typeof config.parseContext[name]) {
case 'function':
parseConfig.context[name] = config.parseContext[name];
break;
if (config.pseudo) {
for (var name in config.pseudo) {
var pseudo = config.pseudo[name];
if (pseudo.parse) {
parserConfig.pseudo[name] = pseudo.parse;
}
case 'string':
parseConfig.context[name] = createParseContext(config.parseContext[name]);
break;
}
}
if (config.node) {
for (var name in config.node) {
parserConfig[name] = config.node[name].parse;
}
}
return parserConfig;
return {
config: parseConfig,
...parseConfig,
...parseConfig.node
};
}
module.exports = function createParser(config) {
var parser = {
scanner: new TokenStream(),
locationMap: new OffsetToLocation(),
export function createParser(config) {
let source = '';
let filename = '<unknown>';
let needPositions = false;
let onParseError = NOOP;
let onParseErrorThrow = false;
filename: '<unknown>',
needPositions: false,
onParseError: noop,
onParseErrorThrow: false,
const locationMap = new OffsetToLocation();
const parser = Object.assign(new TokenStream(), processConfig(config || {}), {
parseAtrulePrelude: true,

@@ -102,19 +95,33 @@ parseRulePrelude: true,

readSequence: sequence,
readSequence,
createList: function() {
consumeUntilBalanceEnd: () => 0,
consumeUntilLeftCurlyBracket(code) {
return code === LEFTCURLYBRACKET ? 1 : 0;
},
consumeUntilLeftCurlyBracketOrSemicolon(code) {
return code === LEFTCURLYBRACKET || code === SEMICOLON ? 1 : 0;
},
consumeUntilExclamationMarkOrSemicolon(code) {
return code === EXCLAMATIONMARK || code === SEMICOLON ? 1 : 0;
},
consumeUntilSemicolonIncluded(code) {
return code === SEMICOLON ? 2 : 0;
},
createList() {
return new List();
},
createSingleNodeList: function(node) {
createSingleNodeList(node) {
return new List().appendData(node);
},
getFirstListNode: function(list) {
return list && list.first();
getFirstListNode(list) {
return list && list.first;
},
getLastListNode: function(list) {
return list.last();
getLastListNode(list) {
return list && list.last;
},
parseWithFallback: function(consumer, fallback) {
var startToken = this.scanner.tokenIndex;
parseWithFallback(consumer, fallback) {
const startToken = this.tokenIndex;

@@ -124,11 +131,11 @@ try {

} catch (e) {
if (this.onParseErrorThrow) {
if (onParseErrorThrow) {
throw e;
}
var fallbackNode = fallback.call(this, startToken);
const fallbackNode = fallback.call(this, startToken);
this.onParseErrorThrow = true;
this.onParseError(e, fallbackNode);
this.onParseErrorThrow = false;
onParseErrorThrow = true;
onParseError(e, fallbackNode);
onParseErrorThrow = false;

@@ -139,6 +146,8 @@ return fallbackNode;

lookupNonWSType: function(offset) {
lookupNonWSType(offset) {
let type;
do {
var type = this.scanner.lookupType(offset++);
if (type !== WHITESPACE) {
type = this.lookupType(offset++);
if (type !== WhiteSpace) {
return type;

@@ -151,13 +160,53 @@ }

eat: function(tokenType) {
if (this.scanner.tokenType !== tokenType) {
var offset = this.scanner.tokenStart;
var message = NAME[tokenType] + ' is expected';
charCodeAt(offset) {
return offset >= 0 && offset < source.length ? source.charCodeAt(offset) : 0;
},
substring(offsetStart, offsetEnd) {
return source.substring(offsetStart, offsetEnd);
},
substrToCursor(start) {
return this.source.substring(start, this.tokenStart);
},
cmpChar(offset, charCode) {
return cmpChar(source, offset, charCode);
},
cmpStr(offsetStart, offsetEnd, str) {
return cmpStr(source, offsetStart, offsetEnd, str);
},
consume(tokenType) {
const start = this.tokenStart;
this.eat(tokenType);
return this.substrToCursor(start);
},
consumeFunctionName() {
const name = source.substring(this.tokenStart, this.tokenEnd - 1);
this.eat(FunctionToken);
return name;
},
consumeNumber(type) {
const number = source.substring(this.tokenStart, consumeNumber(source, this.tokenStart));
this.eat(type);
return number;
},
eat(tokenType) {
if (this.tokenType !== tokenType) {
const tokenName = tokenNames[tokenType].slice(0, -6).replace(/-/g, ' ').replace(/^./, m => m.toUpperCase());
let message = `${/[[\](){}]/.test(tokenName) ? `"${tokenName}"` : tokenName} is expected`;
let offset = this.tokenStart;
// tweak message and offset
switch (tokenType) {
case IDENT:
case Ident:
// when identifier is expected but there is a function or url
if (this.scanner.tokenType === FUNCTION || this.scanner.tokenType === URL) {
offset = this.scanner.tokenEnd - 1;
if (this.tokenType === FunctionToken || this.tokenType === Url) {
offset = this.tokenEnd - 1;
message = 'Identifier is expected but function found';

@@ -169,5 +218,5 @@ } else {

case HASH:
if (this.scanner.isDelim(NUMBERSIGN)) {
this.scanner.next();
case Hash:
if (this.isDelim(NUMBERSIGN)) {
this.next();
offset++;

@@ -178,15 +227,8 @@ message = 'Name is expected';

case PERCENTAGE:
if (this.scanner.tokenType === NUMBER) {
offset = this.scanner.tokenEnd;
case Percentage:
if (this.tokenType === NumberToken) {
offset = this.tokenEnd;
message = 'Percent sign is expected';
}
break;
default:
// 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.scanner.source.charCodeAt(this.scanner.tokenStart) === tokenType) {
offset = offset + 1;
}
}

@@ -197,26 +239,25 @@

this.scanner.next();
this.next();
},
eatIdent(name) {
if (this.tokenType !== Ident || this.lookupValue(0, name) === false) {
this.error(`Identifier "${name}" is expected`);
}
consume: function(tokenType) {
var value = this.scanner.getTokenValue();
this.eat(tokenType);
return value;
this.next();
},
consumeFunctionName: function() {
var name = this.scanner.source.substring(this.scanner.tokenStart, this.scanner.tokenEnd - 1);
eatDelim(code) {
if (!this.isDelim(code)) {
this.error(`Delim "${String.fromCharCode(code)}" is expected`);
}
this.eat(FUNCTION);
return name;
this.next();
},
getLocation: function(start, end) {
if (this.needPositions) {
return this.locationMap.getLocationRange(
getLocation(start, end) {
if (needPositions) {
return locationMap.getLocationRange(
start,
end,
this.filename
filename
);

@@ -227,10 +268,10 @@ }

},
getLocationFromList: function(list) {
if (this.needPositions) {
var head = this.getFirstListNode(list);
var tail = this.getLastListNode(list);
return this.locationMap.getLocationRange(
head !== null ? head.loc.start.offset - this.locationMap.startOffset : this.scanner.tokenStart,
tail !== null ? tail.loc.end.offset - this.locationMap.startOffset : this.scanner.tokenStart,
this.filename
getLocationFromList(list) {
if (needPositions) {
const head = this.getFirstListNode(list);
const tail = this.getLastListNode(list);
return locationMap.getLocationRange(
head !== null ? head.loc.start.offset - locationMap.startOffset : this.tokenStart,
tail !== null ? tail.loc.end.offset - locationMap.startOffset : this.tokenStart,
filename
);

@@ -242,12 +283,12 @@ }

error: function(message, offset) {
var location = typeof offset !== 'undefined' && offset < this.scanner.source.length
? this.locationMap.getLocation(offset)
: this.scanner.eof
? this.locationMap.getLocation(findWhiteSpaceStart(this.scanner.source, this.scanner.source.length - 1))
: this.locationMap.getLocation(this.scanner.tokenStart);
error(message, offset) {
const location = typeof offset !== 'undefined' && offset < source.length
? locationMap.getLocation(offset)
: this.eof
? locationMap.getLocation(findWhiteSpaceStart(source, source.length - 1))
: locationMap.getLocation(this.tokenStart);
throw new SyntaxError(
message || 'Unexpected input',
this.scanner.source,
source,
location.offset,

@@ -258,18 +299,10 @@ location.line,

}
};
});
config = processConfig(config || {});
for (var key in config) {
parser[key] = config[key];
}
return function(source, options) {
const parse = function(source_, options) {
source = source_;
options = options || {};
var context = options.context || 'default';
var onComment = options.onComment;
var ast;
tokenize(source, parser.scanner);
parser.locationMap.setSource(
parser.setSource(source, tokenize);
locationMap.setSource(
source,

@@ -281,6 +314,7 @@ options.offset,

parser.filename = options.filename || '<unknown>';
parser.needPositions = Boolean(options.positions);
parser.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop;
parser.onParseErrorThrow = false;
filename = options.filename || '<unknown>';
needPositions = Boolean(options.positions);
onParseError = typeof options.onParseError === 'function' ? options.onParseError : NOOP;
onParseErrorThrow = false;
parser.parseAtrulePrelude = 'parseAtrulePrelude' in options ? Boolean(options.parseAtrulePrelude) : true;

@@ -291,3 +325,5 @@ parser.parseRulePrelude = 'parseRulePrelude' in options ? Boolean(options.parseRulePrelude) : true;

if (!parser.context.hasOwnProperty(context)) {
const { context = 'default', onComment } = options;
if (context in parser.context === false) {
throw new Error('Unknown context `' + context + '`');

@@ -297,4 +333,4 @@ }

if (typeof onComment === 'function') {
parser.scanner.forEachToken((type, start, end) => {
if (type === COMMENT) {
parser.forEachToken((type, start, end) => {
if (type === Comment) {
const loc = parser.getLocation(start, end);

@@ -310,5 +346,5 @@ const value = cmpStr(source, end - 2, end, '*/')

ast = parser.context[context].call(parser, options);
const ast = parser.context[context].call(parser, options);
if (!parser.scanner.eof) {
if (!parser.eof) {
parser.error();

@@ -319,2 +355,7 @@ }

};
return Object.assign(parse, {
SyntaxError,
config: parser.config
});
};

@@ -1,4 +0,4 @@

var createParser = require('./create');
var config = require('../syntax/config/parser');
import { createParser } from './create.js';
import config from '../syntax/config/parser.js';
module.exports = createParser(config);
export default createParser(config);

@@ -1,33 +0,23 @@

var TYPE = require('../tokenizer').TYPE;
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
import { WhiteSpace, Comment } from '../tokenizer/index.js';
module.exports = function readSequence(recognizer) {
var children = this.createList();
var child = null;
var context = {
recognizer: recognizer,
space: null,
ignoreWS: false,
ignoreWSAfter: false
export function readSequence(recognizer) {
const children = this.createList();
let space = false;
const context = {
recognizer
};
this.scanner.skipSC();
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case COMMENT:
this.scanner.next();
while (!this.eof) {
switch (this.tokenType) {
case Comment:
this.next();
continue;
case WHITESPACE:
if (context.ignoreWS) {
this.scanner.next();
} else {
context.space = this.WhiteSpace();
}
case WhiteSpace:
space = true;
this.next();
continue;
}
child = recognizer.getNode.call(this, context);
let child = recognizer.getNode.call(this, context);

@@ -38,15 +28,14 @@ if (child === undefined) {

if (context.space !== null) {
children.push(context.space);
context.space = null;
if (space) {
if (recognizer.onWhiteSpace) {
recognizer.onWhiteSpace.call(this, child, children, context);
}
space = false;
}
children.push(child);
}
if (context.ignoreWSAfter) {
context.ignoreWSAfter = false;
context.ignoreWS = true;
} else {
context.ignoreWS = false;
}
if (space && recognizer.onWhiteSpace) {
recognizer.onWhiteSpace.call(this, null, children, context);
}

@@ -53,0 +42,0 @@

@@ -1,5 +0,5 @@

module.exports = {
export default {
parse: {
prelude: null,
block: function() {
block() {
return this.Block(true);

@@ -6,0 +6,0 @@ }

@@ -1,23 +0,23 @@

var TYPE = require('../../tokenizer').TYPE;
import {
String as StringToken,
Ident,
Url,
Function as FunctionToken,
LeftParenthesis
} from '../../tokenizer/index.js';
var STRING = TYPE.String;
var IDENT = TYPE.Ident;
var URL = TYPE.Url;
var FUNCTION = TYPE.Function;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
module.exports = {
export default {
parse: {
prelude: function() {
var children = this.createList();
prelude() {
const children = this.createList();
this.scanner.skipSC();
this.skipSC();
switch (this.scanner.tokenType) {
case STRING:
switch (this.tokenType) {
case StringToken:
children.push(this.String());
break;
case URL:
case FUNCTION:
case Url:
case FunctionToken:
children.push(this.Url());

@@ -30,5 +30,4 @@ break;

if (this.lookupNonWSType(0) === IDENT ||
this.lookupNonWSType(0) === LEFTPARENTHESIS) {
children.push(this.WhiteSpace());
if (this.lookupNonWSType(0) === Ident ||
this.lookupNonWSType(0) === LeftParenthesis) {
children.push(this.MediaQueryList());

@@ -35,0 +34,0 @@ }

@@ -1,7 +0,13 @@

module.exports = {
'font-face': require('./font-face'),
'import': require('./import'),
'media': require('./media'),
'page': require('./page'),
'supports': require('./supports')
import fontFace from './font-face.js';
import importAtrule from './import.js';
import media from './media.js';
import page from './page.js';
import supports from './supports.js';
export default {
'font-face': fontFace,
'import': importAtrule,
media,
page,
supports
};

@@ -1,4 +0,4 @@

module.exports = {
export default {
parse: {
prelude: function() {
prelude() {
return this.createSingleNodeList(

@@ -8,3 +8,3 @@ this.MediaQueryList()

},
block: function() {
block() {
return this.Block(false);

@@ -11,0 +11,0 @@ }

@@ -1,4 +0,4 @@

module.exports = {
export default {
parse: {
prelude: function() {
prelude() {
return this.createSingleNodeList(

@@ -8,3 +8,3 @@ this.SelectorList()

},
block: function() {
block() {
return this.Block(true);

@@ -11,0 +11,0 @@ }

@@ -1,13 +0,13 @@

var TYPE = require('../../tokenizer').TYPE;
import {
WhiteSpace,
Comment,
Ident,
Function,
Colon,
LeftParenthesis
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var IDENT = TYPE.Ident;
var FUNCTION = TYPE.Function;
var COLON = TYPE.Colon;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
function consumeRaw() {
return this.createSingleNodeList(
this.Raw(this.scanner.tokenIndex, null, false)
this.Raw(this.tokenIndex, null, false)
);

@@ -17,6 +17,6 @@ }

function parentheses() {
this.scanner.skipSC();
this.skipSC();
if (this.scanner.tokenType === IDENT &&
this.lookupNonWSType(1) === COLON) {
if (this.tokenType === Ident &&
this.lookupNonWSType(1) === Colon) {
return this.createSingleNodeList(

@@ -31,28 +31,24 @@ this.Declaration()

function readSequence() {
var children = this.createList();
var space = null;
var child;
const children = this.createList();
let child;
this.scanner.skipSC();
this.skipSC();
scan:
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case WHITESPACE:
space = this.WhiteSpace();
while (!this.eof) {
switch (this.tokenType) {
case Comment:
case WhiteSpace:
this.next();
continue;
case COMMENT:
this.scanner.next();
continue;
case FUNCTION:
case Function:
child = this.Function(consumeRaw, this.scope.AtrulePrelude);
break;
case IDENT:
case Ident:
child = this.Identifier();
break;
case LEFTPARENTHESIS:
case LeftParenthesis:
child = this.Parentheses(parentheses, this.scope.AtrulePrelude);

@@ -65,7 +61,2 @@ break;

if (space !== null) {
children.push(space);
space = null;
}
children.push(child);

@@ -77,6 +68,6 @@ }

module.exports = {
export default {
parse: {
prelude: function() {
var children = readSequence.call(this);
prelude() {
const children = readSequence.call(this);

@@ -89,3 +80,3 @@ if (this.getFirstListNode(children) === null) {

},
block: function() {
block() {
return this.Block(false);

@@ -92,0 +83,0 @@ }

@@ -1,9 +0,8 @@

var data = require('../../../data');
import definitions from '../../data.js';
import * as node from '../node/index.js';
module.exports = {
export default {
generic: true,
types: data.types,
atrules: data.atrules,
properties: data.properties,
node: require('../node')
...definitions,
node
};

@@ -1,2 +0,2 @@

const hasOwnProperty = Object.prototype.hasOwnProperty;
const { hasOwnProperty } = Object.prototype;
const shape = {

@@ -23,3 +23,3 @@ generic: true,

return isObject(value)
? Object.assign({}, value)
? { ...value }
: value;

@@ -61,3 +61,3 @@ }

const result = Object.assign({}, a);
const result = { ...a };
for (let key in b) {

@@ -142,2 +142,2 @@ if (hasOwnProperty.call(b, key)) {

module.exports = (dest, src) => mix(dest, src, shape);
export default (dest, src) => mix(dest, src, shape);

@@ -1,2 +0,7 @@

module.exports = {
import * as scope from '../scope/index.js';
import atrule from '../atrule/index.js';
import pseudo from '../pseudo/index.js';
import * as node from '../node/index.js';
export default {
parseContext: {

@@ -21,6 +26,6 @@ default: 'StyleSheet',

},
scope: require('../scope'),
atrule: require('../atrule'),
pseudo: require('../pseudo'),
node: require('../node')
scope,
atrule,
pseudo,
node
};

@@ -1,3 +0,5 @@

module.exports = {
node: require('../node')
import * as node from '../node/index.js';
export default {
node
};

@@ -1,43 +0,24 @@

var List = require('../common/List');
var SyntaxError = require('../common/SyntaxError');
var TokenStream = require('../common/TokenStream');
var Lexer = require('../lexer/Lexer');
var definitionSyntax = require('../definition-syntax');
var tokenize = require('../tokenizer');
var createParser = require('../parser/create');
var createGenerator = require('../generator/create');
var createConvertor = require('../convertor/create');
var createWalker = require('../walker/create');
var clone = require('../utils/clone');
var names = require('../utils/names');
var mix = require('./config/mix');
import { tokenize } from '../tokenizer/index.js';
import { createParser } from '../parser/create.js';
import { createGenerator } from '../generator/create.js';
import { createConvertor } from '../convertor/create.js';
import { createWalker } from '../walker/create.js';
import { Lexer } from '../lexer/Lexer.js';
import mix from './config/mix.js';
function createSyntax(config) {
var parse = createParser(config);
var walk = createWalker(config);
var generate = createGenerator(config);
var convert = createConvertor(walk);
const parse = createParser(config);
const walk = createWalker(config);
const generate = createGenerator(config);
const { fromPlainObject, toPlainObject } = createConvertor(walk);
var syntax = {
List: List,
SyntaxError: SyntaxError,
TokenStream: TokenStream,
Lexer: Lexer,
vendorPrefix: names.vendorPrefix,
keyword: names.keyword,
property: names.property,
isCustomProperty: names.isCustomProperty,
definitionSyntax: definitionSyntax,
const syntax = {
lexer: null,
createLexer: function(config) {
return new Lexer(config, syntax, syntax.lexer.structure);
},
createLexer: config => new Lexer(config, syntax, syntax.lexer.structure),
tokenize: tokenize,
parse: parse,
walk: walk,
generate: generate,
tokenize,
parse,
generate,
walk,
find: walk.find,

@@ -47,11 +28,7 @@ findLast: walk.findLast,

clone: clone,
fromPlainObject: convert.fromPlainObject,
toPlainObject: convert.toPlainObject,
fromPlainObject,
toPlainObject,
createSyntax: function(config) {
return createSyntax(mix({}, config));
},
fork: function(extension) {
var base = mix({}, config); // copy of config
const base = mix({}, config); // copy of config
return createSyntax(

@@ -76,4 +53,2 @@ typeof extension === 'function'

exports.create = function(config) {
return createSyntax(mix({}, config));
};
export default config => createSyntax(mix({}, config));
// legacy IE function
// expression( <any-value> )
module.exports = function() {
export default function() {
return this.createSingleNodeList(
this.Raw(this.scanner.tokenIndex, null, false)
this.Raw(this.tokenIndex, null, false)
);
};
}

@@ -1,12 +0,8 @@

var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('../node/Raw').mode;
import { Comma, WhiteSpace } from '../../tokenizer/index.js';
var COMMA = TYPE.Comma;
var WHITESPACE = TYPE.WhiteSpace;
// var( <ident> , <value>? )
module.exports = function() {
var children = this.createList();
export default function() {
const children = this.createList();
this.scanner.skipSC();
this.skipSC();

@@ -16,15 +12,15 @@ // NOTE: Don't check more than a first argument is an ident, rest checks are for lexer

this.scanner.skipSC();
this.skipSC();
if (this.scanner.tokenType === COMMA) {
if (this.tokenType === Comma) {
children.push(this.Operator());
const startIndex = this.scanner.tokenIndex;
const startIndex = this.tokenIndex;
const value = this.parseCustomProperty
? this.Value(null)
: this.Raw(this.scanner.tokenIndex, rawMode.exclamationMarkOrSemicolon, false);
: this.Raw(this.tokenIndex, this.consumeUntilExclamationMarkOrSemicolon, false);
if (value.type === 'Value' && value.children.isEmpty()) {
for (let offset = startIndex - this.scanner.tokenIndex; offset <= 0; offset++) {
if (this.scanner.lookupType(offset) === WHITESPACE) {
if (value.type === 'Value' && value.children.isEmpty) {
for (let offset = startIndex - this.tokenIndex; offset <= 0; offset++) {
if (this.lookupType(offset) === WhiteSpace) {
value.children.appendData({

@@ -31,0 +27,0 @@ type: 'WhiteSpace',

@@ -1,21 +0,10 @@

function merge() {
var dest = {};
import createSyntax from './create.js';
import lexerConfig from './config/lexer.js';
import parserConfig from './config/parser.js';
import walkerConfig from './config/walker.js';
for (var i = 0; i < arguments.length; i++) {
var src = arguments[i];
for (var key in src) {
dest[key] = src[key];
}
}
return dest;
}
module.exports = require('./create').create(
merge(
require('./config/lexer'),
require('./config/parser'),
require('./config/walker')
)
);
module.exports.version = require('../../package.json').version;
export default createSyntax({
...lexerConfig,
...parserConfig,
...walkerConfig
});

@@ -1,19 +0,19 @@

var cmpChar = require('../../tokenizer').cmpChar;
var isDigit = require('../../tokenizer').isDigit;
var TYPE = require('../../tokenizer').TYPE;
import {
isDigit,
WhiteSpace,
Comment,
Ident,
Number,
Dimension
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var IDENT = TYPE.Ident;
var NUMBER = TYPE.Number;
var DIMENSION = TYPE.Dimension;
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
var N = 0x006E; // U+006E LATIN SMALL LETTER N (n)
var DISALLOW_SIGN = true;
var ALLOW_SIGN = false;
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
const N = 0x006E; // U+006E LATIN SMALL LETTER N (n)
const DISALLOW_SIGN = true;
const ALLOW_SIGN = false;
function checkInteger(offset, disallowSign) {
var pos = this.scanner.tokenStart + offset;
var code = this.scanner.source.charCodeAt(pos);
let pos = this.tokenStart + offset;
const code = this.charCodeAt(pos);

@@ -27,4 +27,4 @@ if (code === PLUSSIGN || code === HYPHENMINUS) {

for (; pos < this.scanner.tokenEnd; pos++) {
if (!isDigit(this.scanner.source.charCodeAt(pos))) {
for (; pos < this.tokenEnd; pos++) {
if (!isDigit(this.charCodeAt(pos))) {
this.error('Integer is expected', pos);

@@ -40,4 +40,4 @@ }

function expectCharCode(offset, code) {
if (!cmpChar(this.scanner.source, this.scanner.tokenStart + offset, code)) {
var msg = '';
if (!this.cmpChar(this.tokenStart + offset, code)) {
let msg = '';

@@ -53,3 +53,3 @@ switch (code) {

this.error(msg, this.scanner.tokenStart + offset);
this.error(msg, this.tokenStart + offset);
}

@@ -61,21 +61,21 @@ }

function consumeB() {
var offset = 0;
var sign = 0;
var type = this.scanner.tokenType;
let offset = 0;
let sign = 0;
let type = this.tokenType;
while (type === WHITESPACE || type === COMMENT) {
type = this.scanner.lookupType(++offset);
while (type === WhiteSpace || type === Comment) {
type = this.lookupType(++offset);
}
if (type !== NUMBER) {
if (this.scanner.isDelim(PLUSSIGN, offset) ||
this.scanner.isDelim(HYPHENMINUS, offset)) {
sign = this.scanner.isDelim(PLUSSIGN, offset) ? PLUSSIGN : HYPHENMINUS;
if (type !== Number) {
if (this.isDelim(PLUSSIGN, offset) ||
this.isDelim(HYPHENMINUS, offset)) {
sign = this.isDelim(PLUSSIGN, offset) ? PLUSSIGN : HYPHENMINUS;
do {
type = this.scanner.lookupType(++offset);
} while (type === WHITESPACE || type === COMMENT);
type = this.lookupType(++offset);
} while (type === WhiteSpace || type === Comment);
if (type !== NUMBER) {
this.scanner.skip(offset);
if (type !== Number) {
this.skip(offset);
checkTokenIsInteger.call(this, DISALLOW_SIGN);

@@ -89,7 +89,7 @@ }

if (offset > 0) {
this.scanner.skip(offset);
this.skip(offset);
}
if (sign === 0) {
type = this.scanner.source.charCodeAt(this.scanner.tokenStart);
type = this.charCodeAt(this.tokenStart);
if (type !== PLUSSIGN && type !== HYPHENMINUS) {

@@ -101,203 +101,198 @@ this.error('Number sign is expected');

checkTokenIsInteger.call(this, sign !== 0);
return sign === HYPHENMINUS ? '-' + this.consume(NUMBER) : this.consume(NUMBER);
return sign === HYPHENMINUS ? '-' + this.consume(Number) : this.consume(Number);
}
// An+B microsyntax https://www.w3.org/TR/css-syntax-3/#anb
module.exports = {
name: 'AnPlusB',
structure: {
a: [String, null],
b: [String, null]
},
parse: function() {
/* eslint-disable brace-style*/
var start = this.scanner.tokenStart;
var a = null;
var b = null;
export const name = 'AnPlusB';
export const structure = {
a: [String, null],
b: [String, null]
};
// <integer>
if (this.scanner.tokenType === NUMBER) {
checkTokenIsInteger.call(this, ALLOW_SIGN);
b = this.consume(NUMBER);
}
export function parse() {
/* eslint-disable brace-style*/
const start = this.tokenStart;
let a = null;
let b = null;
// -n
// -n <signed-integer>
// -n ['+' | '-'] <signless-integer>
// -n- <signless-integer>
// <dashndashdigit-ident>
else if (this.scanner.tokenType === IDENT && cmpChar(this.scanner.source, this.scanner.tokenStart, HYPHENMINUS)) {
a = '-1';
// <integer>
if (this.tokenType === Number) {
checkTokenIsInteger.call(this, ALLOW_SIGN);
b = this.consume(Number);
}
expectCharCode.call(this, 1, N);
// -n
// -n <signed-integer>
// -n ['+' | '-'] <signless-integer>
// -n- <signless-integer>
// <dashndashdigit-ident>
else if (this.tokenType === Ident && this.cmpChar(this.tokenStart, HYPHENMINUS)) {
a = '-1';
switch (this.scanner.getTokenLength()) {
// -n
// -n <signed-integer>
// -n ['+' | '-'] <signless-integer>
case 2:
this.scanner.next();
b = consumeB.call(this);
break;
expectCharCode.call(this, 1, N);
// -n- <signless-integer>
case 3:
expectCharCode.call(this, 2, HYPHENMINUS);
switch (this.tokenEnd - this.tokenStart) {
// -n
// -n <signed-integer>
// -n ['+' | '-'] <signless-integer>
case 2:
this.next();
b = consumeB.call(this);
break;
this.scanner.next();
this.scanner.skipSC();
// -n- <signless-integer>
case 3:
expectCharCode.call(this, 2, HYPHENMINUS);
checkTokenIsInteger.call(this, DISALLOW_SIGN);
this.next();
this.skipSC();
b = '-' + this.consume(NUMBER);
break;
checkTokenIsInteger.call(this, DISALLOW_SIGN);
// <dashndashdigit-ident>
default:
expectCharCode.call(this, 2, HYPHENMINUS);
checkInteger.call(this, 3, DISALLOW_SIGN);
this.scanner.next();
b = '-' + this.consume(Number);
break;
b = this.scanner.substrToCursor(start + 2);
}
// <dashndashdigit-ident>
default:
expectCharCode.call(this, 2, HYPHENMINUS);
checkInteger.call(this, 3, DISALLOW_SIGN);
this.next();
b = this.substrToCursor(start + 2);
}
}
// '+'? n
// '+'? n <signed-integer>
// '+'? n ['+' | '-'] <signless-integer>
// '+'? n- <signless-integer>
// '+'? <ndashdigit-ident>
else if (this.scanner.tokenType === IDENT || (this.scanner.isDelim(PLUSSIGN) && this.scanner.lookupType(1) === IDENT)) {
var sign = 0;
a = '1';
// '+'? n
// '+'? n <signed-integer>
// '+'? n ['+' | '-'] <signless-integer>
// '+'? n- <signless-integer>
// '+'? <ndashdigit-ident>
else if (this.tokenType === Ident || (this.isDelim(PLUSSIGN) && this.lookupType(1) === Ident)) {
let sign = 0;
a = '1';
// just ignore a plus
if (this.scanner.isDelim(PLUSSIGN)) {
sign = 1;
this.scanner.next();
}
// just ignore a plus
if (this.isDelim(PLUSSIGN)) {
sign = 1;
this.next();
}
expectCharCode.call(this, 0, N);
expectCharCode.call(this, 0, N);
switch (this.scanner.getTokenLength()) {
// '+'? n
// '+'? n <signed-integer>
// '+'? n ['+' | '-'] <signless-integer>
case 1:
this.scanner.next();
b = consumeB.call(this);
break;
switch (this.tokenEnd - this.tokenStart) {
// '+'? n
// '+'? n <signed-integer>
// '+'? n ['+' | '-'] <signless-integer>
case 1:
this.next();
b = consumeB.call(this);
break;
// '+'? n- <signless-integer>
case 2:
expectCharCode.call(this, 1, HYPHENMINUS);
// '+'? n- <signless-integer>
case 2:
expectCharCode.call(this, 1, HYPHENMINUS);
this.scanner.next();
this.scanner.skipSC();
this.next();
this.skipSC();
checkTokenIsInteger.call(this, DISALLOW_SIGN);
checkTokenIsInteger.call(this, DISALLOW_SIGN);
b = '-' + this.consume(NUMBER);
break;
b = '-' + this.consume(Number);
break;
// '+'? <ndashdigit-ident>
default:
expectCharCode.call(this, 1, HYPHENMINUS);
checkInteger.call(this, 2, DISALLOW_SIGN);
this.scanner.next();
// '+'? <ndashdigit-ident>
default:
expectCharCode.call(this, 1, HYPHENMINUS);
checkInteger.call(this, 2, DISALLOW_SIGN);
this.next();
b = this.scanner.substrToCursor(start + sign + 1);
b = this.substrToCursor(start + sign + 1);
}
}
// <ndashdigit-dimension>
// <ndash-dimension> <signless-integer>
// <n-dimension>
// <n-dimension> <signed-integer>
// <n-dimension> ['+' | '-'] <signless-integer>
else if (this.tokenType === Dimension) {
const code = this.charCodeAt(this.tokenStart);
const sign = code === PLUSSIGN || code === HYPHENMINUS;
let i = this.tokenStart + sign;
for (; i < this.tokenEnd; i++) {
if (!isDigit(this.charCodeAt(i))) {
break;
}
}
// <ndashdigit-dimension>
// <ndash-dimension> <signless-integer>
if (i === this.tokenStart + sign) {
this.error('Integer is expected', this.tokenStart + sign);
}
expectCharCode.call(this, i - this.tokenStart, N);
a = this.substring(start, i);
// <n-dimension>
// <n-dimension> <signed-integer>
// <n-dimension> ['+' | '-'] <signless-integer>
else if (this.scanner.tokenType === DIMENSION) {
var code = this.scanner.source.charCodeAt(this.scanner.tokenStart);
var sign = code === PLUSSIGN || code === HYPHENMINUS;
if (i + 1 === this.tokenEnd) {
this.next();
b = consumeB.call(this);
} else {
expectCharCode.call(this, i - this.tokenStart + 1, HYPHENMINUS);
for (var i = this.scanner.tokenStart + sign; i < this.scanner.tokenEnd; i++) {
if (!isDigit(this.scanner.source.charCodeAt(i))) {
break;
}
// <ndash-dimension> <signless-integer>
if (i + 2 === this.tokenEnd) {
this.next();
this.skipSC();
checkTokenIsInteger.call(this, DISALLOW_SIGN);
b = '-' + this.consume(Number);
}
if (i === this.scanner.tokenStart + sign) {
this.error('Integer is expected', this.scanner.tokenStart + sign);
// <ndashdigit-dimension>
else {
checkInteger.call(this, i - this.tokenStart + 2, DISALLOW_SIGN);
this.next();
b = this.substrToCursor(i + 1);
}
expectCharCode.call(this, i - this.scanner.tokenStart, N);
a = this.scanner.source.substring(start, i);
// <n-dimension>
// <n-dimension> <signed-integer>
// <n-dimension> ['+' | '-'] <signless-integer>
if (i + 1 === this.scanner.tokenEnd) {
this.scanner.next();
b = consumeB.call(this);
} else {
expectCharCode.call(this, i - this.scanner.tokenStart + 1, HYPHENMINUS);
// <ndash-dimension> <signless-integer>
if (i + 2 === this.scanner.tokenEnd) {
this.scanner.next();
this.scanner.skipSC();
checkTokenIsInteger.call(this, DISALLOW_SIGN);
b = '-' + this.consume(NUMBER);
}
// <ndashdigit-dimension>
else {
checkInteger.call(this, i - this.scanner.tokenStart + 2, DISALLOW_SIGN);
this.scanner.next();
b = this.scanner.substrToCursor(i + 1);
}
}
} else {
this.error();
}
} else {
this.error();
}
if (a !== null && a.charCodeAt(0) === PLUSSIGN) {
a = a.substr(1);
}
if (a !== null && a.charCodeAt(0) === PLUSSIGN) {
a = a.substr(1);
}
if (b !== null && b.charCodeAt(0) === PLUSSIGN) {
b = b.substr(1);
}
if (b !== null && b.charCodeAt(0) === PLUSSIGN) {
b = b.substr(1);
}
return {
type: 'AnPlusB',
loc: this.getLocation(start, this.scanner.tokenStart),
a: a,
b: b
};
},
generate: function(node) {
var a = node.a !== null && node.a !== undefined;
var b = node.b !== null && node.b !== undefined;
return {
type: 'AnPlusB',
loc: this.getLocation(start, this.tokenStart),
a,
b
};
}
if (a) {
this.chunk(
node.a === '+1' ? '+n' : // eslint-disable-line operator-linebreak, indent
node.a === '1' ? 'n' : // eslint-disable-line operator-linebreak, indent
node.a === '-1' ? '-n' : // eslint-disable-line operator-linebreak, indent
node.a + 'n' // eslint-disable-line operator-linebreak, indent
);
export function generate(node) {
if (node.a) {
const a =
node.a === '+1' && 'n' ||
node.a === '1' && 'n' ||
node.a === '-1' && '-n' ||
node.a + 'n';
if (b) {
b = String(node.b);
if (b.charAt(0) === '-' || b.charAt(0) === '+') {
this.chunk(b.charAt(0));
this.chunk(b.substr(1));
} else {
this.chunk('+');
this.chunk(b);
}
}
if (node.b) {
const b = node.b[0] === '-' || node.b[0] === '+'
? node.b
: '+' + node.b;
this.tokenize(a + b);
} else {
this.chunk(String(node.b));
this.tokenize(a);
}
} else {
this.tokenize(node.b);
}
};
}

@@ -1,21 +0,20 @@

var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('./Raw').mode;
import {
AtKeyword,
Semicolon,
LeftCurlyBracket,
RightCurlyBracket
} from '../../tokenizer/index.js';
var ATKEYWORD = TYPE.AtKeyword;
var SEMICOLON = TYPE.Semicolon;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
var RIGHTCURLYBRACKET = TYPE.RightCurlyBracket;
function consumeRaw(startToken) {
return this.Raw(startToken, rawMode.leftCurlyBracketOrSemicolon, true);
return this.Raw(startToken, this.consumeUntilLeftCurlyBracketOrSemicolon, true);
}
function isDeclarationBlockAtrule() {
for (var offset = 1, type; type = this.scanner.lookupType(offset); offset++) {
if (type === RIGHTCURLYBRACKET) {
for (let offset = 1, type; type = this.lookupType(offset); offset++) {
if (type === RightCurlyBracket) {
return true;
}
if (type === LEFTCURLYBRACKET ||
type === ATKEYWORD) {
if (type === LeftCurlyBracket ||
type === AtKeyword) {
return false;

@@ -28,81 +27,75 @@ }

module.exports = {
name: 'Atrule',
structure: {
name: String,
prelude: ['AtrulePrelude', 'Raw', null],
block: ['Block', null]
},
parse: function() {
var start = this.scanner.tokenStart;
var name;
var nameLowerCase;
var prelude = null;
var block = null;
this.eat(ATKEYWORD);
export const name = 'Atrule';
export const walkContext = 'atrule';
export const structure = {
name: String,
prelude: ['AtrulePrelude', 'Raw', null],
block: ['Block', null]
};
name = this.scanner.substrToCursor(start + 1);
nameLowerCase = name.toLowerCase();
this.scanner.skipSC();
export function parse() {
const start = this.tokenStart;
let name;
let nameLowerCase;
let prelude = null;
let block = null;
// parse prelude
if (this.scanner.eof === false &&
this.scanner.tokenType !== LEFTCURLYBRACKET &&
this.scanner.tokenType !== SEMICOLON) {
if (this.parseAtrulePrelude) {
prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw);
this.eat(AtKeyword);
// turn empty AtrulePrelude into null
if (prelude.type === 'AtrulePrelude' && prelude.children.head === null) {
prelude = null;
}
} else {
prelude = consumeRaw.call(this, this.scanner.tokenIndex);
}
name = this.substrToCursor(start + 1);
nameLowerCase = name.toLowerCase();
this.skipSC();
this.scanner.skipSC();
// parse prelude
if (this.eof === false &&
this.tokenType !== LeftCurlyBracket &&
this.tokenType !== Semicolon) {
if (this.parseAtrulePrelude) {
prelude = this.parseWithFallback(this.AtrulePrelude.bind(this, name), consumeRaw);
} else {
prelude = consumeRaw.call(this, this.tokenIndex);
}
switch (this.scanner.tokenType) {
case SEMICOLON:
this.scanner.next();
break;
this.skipSC();
}
case LEFTCURLYBRACKET:
if (this.atrule.hasOwnProperty(nameLowerCase) &&
typeof this.atrule[nameLowerCase].block === 'function') {
block = this.atrule[nameLowerCase].block.call(this);
} else {
// TODO: should consume block content as Raw?
block = this.Block(isDeclarationBlockAtrule.call(this));
}
switch (this.tokenType) {
case Semicolon:
this.next();
break;
break;
}
case LeftCurlyBracket:
if (hasOwnProperty.call(this.atrule, nameLowerCase) &&
typeof this.atrule[nameLowerCase].block === 'function') {
block = this.atrule[nameLowerCase].block.call(this);
} else {
// TODO: should consume block content as Raw?
block = this.Block(isDeclarationBlockAtrule.call(this));
}
return {
type: 'Atrule',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
prelude: prelude,
block: block
};
},
generate: function(node) {
this.chunk('@');
this.chunk(node.name);
break;
}
if (node.prelude !== null) {
this.chunk(' ');
this.node(node.prelude);
}
return {
type: 'Atrule',
loc: this.getLocation(start, this.tokenStart),
name,
prelude,
block
};
}
if (node.block) {
this.node(node.block);
} else {
this.chunk(';');
}
},
walkContext: 'atrule'
};
export function generate(node) {
this.token(AtKeyword, '@' + node.name);
if (node.prelude !== null) {
this.node(node.prelude);
}
if (node.block) {
this.node(node.block);
} else {
this.token(Semicolon, ';');
}
}

@@ -1,51 +0,47 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Semicolon,
LeftCurlyBracket
} from '../../tokenizer/index.js';
var SEMICOLON = TYPE.Semicolon;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
export const name = 'AtrulePrelude';
export const walkContext = 'atrulePrelude';
export const structure = {
children: [[]]
};
module.exports = {
name: 'AtrulePrelude',
structure: {
children: [[]]
},
parse: function(name) {
var children = null;
export function parse(name) {
let children = null;
if (name !== null) {
name = name.toLowerCase();
}
if (name !== null) {
name = name.toLowerCase();
}
this.scanner.skipSC();
this.skipSC();
if (this.atrule.hasOwnProperty(name) &&
typeof this.atrule[name].prelude === 'function') {
// custom consumer
children = this.atrule[name].prelude.call(this);
} else {
// default consumer
children = this.readSequence(this.scope.AtrulePrelude);
}
if (hasOwnProperty.call(this.atrule, name) &&
typeof this.atrule[name].prelude === 'function') {
// custom consumer
children = this.atrule[name].prelude.call(this);
} else {
// default consumer
children = this.readSequence(this.scope.AtrulePrelude);
}
this.scanner.skipSC();
this.skipSC();
if (this.scanner.eof !== true &&
this.scanner.tokenType !== LEFTCURLYBRACKET &&
this.scanner.tokenType !== SEMICOLON) {
this.error('Semicolon or block is expected');
}
if (this.eof !== true &&
this.tokenType !== LeftCurlyBracket &&
this.tokenType !== Semicolon) {
this.error('Semicolon or block is expected');
}
if (children === null) {
children = this.createList();
}
return {
type: 'AtrulePrelude',
loc: this.getLocationFromList(children),
children
};
}
return {
type: 'AtrulePrelude',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node);
},
walkContext: 'atrulePrelude'
};
export function generate(node) {
this.children(node);
}

@@ -1,38 +0,40 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Ident,
String as StringToken,
Delim,
Colon,
LeftSquareBracket,
RightSquareBracket
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var STRING = TYPE.String;
var COLON = TYPE.Colon;
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;
var RIGHTSQUAREBRACKET = TYPE.RightSquareBracket;
var DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=)
var CIRCUMFLEXACCENT = 0x005E; // U+005E (^)
var VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
var TILDE = 0x007E; // U+007E TILDE (~)
const DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const EQUALSSIGN = 0x003D; // U+003D EQUALS SIGN (=)
const CIRCUMFLEXACCENT = 0x005E; // U+005E (^)
const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
const TILDE = 0x007E; // U+007E TILDE (~)
function getAttributeName() {
if (this.scanner.eof) {
if (this.eof) {
this.error('Unexpected end of input');
}
var start = this.scanner.tokenStart;
var expectIdent = false;
var checkColon = true;
const start = this.tokenStart;
let expectIdent = false;
let checkColon = true;
if (this.scanner.isDelim(ASTERISK)) {
if (this.isDelim(ASTERISK)) {
expectIdent = true;
checkColon = false;
this.scanner.next();
} else if (!this.scanner.isDelim(VERTICALLINE)) {
this.eat(IDENT);
this.next();
} else if (!this.isDelim(VERTICALLINE)) {
this.eat(Ident);
}
if (this.scanner.isDelim(VERTICALLINE)) {
if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 1) !== EQUALSSIGN) {
this.scanner.next();
this.eat(IDENT);
if (this.isDelim(VERTICALLINE)) {
if (this.charCodeAt(this.tokenStart + 1) !== EQUALSSIGN) {
this.next();
this.eat(Ident);
} else if (expectIdent) {
this.error('Identifier is expected', this.scanner.tokenEnd);
this.error('Identifier is expected', this.tokenEnd);
}

@@ -43,5 +45,5 @@ } else if (expectIdent) {

if (checkColon && this.scanner.tokenType === COLON) {
this.scanner.next();
this.eat(IDENT);
if (checkColon && this.tokenType === Colon) {
this.next();
this.eat(Ident);
}

@@ -51,4 +53,4 @@

type: 'Identifier',
loc: this.getLocation(start, this.scanner.tokenStart),
name: this.scanner.substrToCursor(start)
loc: this.getLocation(start, this.tokenStart),
name: this.substrToCursor(start)
};

@@ -58,4 +60,4 @@ }

function getOperator() {
var start = this.scanner.tokenStart;
var code = this.scanner.source.charCodeAt(start);
const start = this.tokenStart;
const code = this.charCodeAt(start);

@@ -72,13 +74,13 @@ if (code !== EQUALSSIGN && // =

this.scanner.next();
this.next();
if (code !== EQUALSSIGN) {
if (!this.scanner.isDelim(EQUALSSIGN)) {
if (!this.isDelim(EQUALSSIGN)) {
this.error('Equal sign is expected');
}
this.scanner.next();
this.next();
}
return this.scanner.substrToCursor(start);
return this.substrToCursor(start);
}

@@ -88,83 +90,71 @@

// '[' <wq-name> <attr-matcher> [ <string-token> | <ident-token> ] <attr-modifier>? ']'
module.exports = {
name: 'AttributeSelector',
structure: {
name: 'Identifier',
matcher: [String, null],
value: ['String', 'Identifier', null],
flags: [String, null]
},
parse: function() {
var start = this.scanner.tokenStart;
var name;
var matcher = null;
var value = null;
var flags = null;
export const name = 'AttributeSelector';
export const structure = {
name: 'Identifier',
matcher: [String, null],
value: ['String', 'Identifier', null],
flags: [String, null]
};
this.eat(LEFTSQUAREBRACKET);
this.scanner.skipSC();
export function parse() {
const start = this.tokenStart;
let name;
let matcher = null;
let value = null;
let flags = null;
name = getAttributeName.call(this);
this.scanner.skipSC();
this.eat(LeftSquareBracket);
this.skipSC();
if (this.scanner.tokenType !== RIGHTSQUAREBRACKET) {
// avoid case `[name i]`
if (this.scanner.tokenType !== IDENT) {
matcher = getOperator.call(this);
name = getAttributeName.call(this);
this.skipSC();
this.scanner.skipSC();
if (this.tokenType !== RightSquareBracket) {
// avoid case `[name i]`
if (this.tokenType !== Ident) {
matcher = getOperator.call(this);
value = this.scanner.tokenType === STRING
? this.String()
: this.Identifier();
this.skipSC();
this.scanner.skipSC();
}
value = this.tokenType === StringToken
? this.String()
: this.Identifier();
// attribute flags
if (this.scanner.tokenType === IDENT) {
flags = this.scanner.getTokenValue();
this.scanner.next();
this.scanner.skipSC();
}
this.skipSC();
}
this.eat(RIGHTSQUAREBRACKET);
// attribute flags
if (this.tokenType === Ident) {
flags = this.consume(Ident);
return {
type: 'AttributeSelector',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
matcher: matcher,
value: value,
flags: flags
};
},
generate: function(node) {
var flagsPrefix = ' ';
this.skipSC();
}
}
this.chunk('[');
this.node(node.name);
this.eat(RightSquareBracket);
if (node.matcher !== null) {
this.chunk(node.matcher);
return {
type: 'AttributeSelector',
loc: this.getLocation(start, this.tokenStart),
name,
matcher,
value,
flags
};
}
if (node.value !== null) {
this.node(node.value);
export function generate(node) {
this.token(Delim, '[');
this.node(node.name);
// space between string and flags is not required
if (node.value.type === 'String') {
flagsPrefix = '';
}
}
}
if (node.matcher !== null) {
this.tokenize(node.matcher);
this.node(node.value);
}
if (node.flags !== null) {
this.chunk(flagsPrefix);
this.chunk(node.flags);
}
if (node.flags !== null) {
this.token(Ident, node.flags);
}
this.chunk(']');
}
};
this.token(Delim, ']');
}

@@ -1,11 +0,10 @@

var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('./Raw').mode;
import {
WhiteSpace,
Comment,
Semicolon,
AtKeyword,
LeftCurlyBracket,
RightCurlyBracket
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var SEMICOLON = TYPE.Semicolon;
var ATKEYWORD = TYPE.AtKeyword;
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
var RIGHTCURLYBRACKET = TYPE.RightCurlyBracket;
function consumeRaw(startToken) {

@@ -18,13 +17,13 @@ return this.Raw(startToken, null, true);

function consumeRawDeclaration(startToken) {
return this.Raw(startToken, rawMode.semicolonIncluded, true);
return this.Raw(startToken, this.consumeUntilSemicolonIncluded, true);
}
function consumeDeclaration() {
if (this.scanner.tokenType === SEMICOLON) {
return consumeRawDeclaration.call(this, this.scanner.tokenIndex);
if (this.tokenType === Semicolon) {
return consumeRawDeclaration.call(this, this.tokenIndex);
}
var node = this.parseWithFallback(this.Declaration, consumeRawDeclaration);
const node = this.parseWithFallback(this.Declaration, consumeRawDeclaration);
if (this.scanner.tokenType === SEMICOLON) {
this.scanner.next();
if (this.tokenType === Semicolon) {
this.next();
}

@@ -35,59 +34,58 @@

module.exports = {
name: 'Block',
structure: {
children: [[
'Atrule',
'Rule',
'Declaration'
]]
},
parse: function(isDeclaration) {
var consumer = isDeclaration ? consumeDeclaration : consumeRule;
export const name = 'Block';
export const walkContext = 'block';
export const structure = {
children: [[
'Atrule',
'Rule',
'Declaration'
]]
};
var start = this.scanner.tokenStart;
var children = this.createList();
export function parse(isDeclaration) {
const consumer = isDeclaration ? consumeDeclaration : consumeRule;
const start = this.tokenStart;
let children = this.createList();
this.eat(LEFTCURLYBRACKET);
this.eat(LeftCurlyBracket);
scan:
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case RIGHTCURLYBRACKET:
break scan;
scan:
while (!this.eof) {
switch (this.tokenType) {
case RightCurlyBracket:
break scan;
case WHITESPACE:
case COMMENT:
this.scanner.next();
break;
case WhiteSpace:
case Comment:
this.next();
break;
case ATKEYWORD:
children.push(this.parseWithFallback(this.Atrule, consumeRaw));
break;
case AtKeyword:
children.push(this.parseWithFallback(this.Atrule, consumeRaw));
break;
default:
children.push(consumer.call(this));
}
default:
children.push(consumer.call(this));
}
}
if (!this.scanner.eof) {
this.eat(RIGHTCURLYBRACKET);
if (!this.eof) {
this.eat(RightCurlyBracket);
}
return {
type: 'Block',
loc: this.getLocation(start, this.tokenStart),
children
};
}
export function generate(node) {
this.token(LeftCurlyBracket, '{');
this.children(node, prev => {
if (prev.type === 'Declaration') {
this.token(Semicolon, ';');
}
return {
type: 'Block',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
},
generate: function(node) {
this.chunk('{');
this.children(node, function(prev) {
if (prev.type === 'Declaration') {
this.chunk(';');
}
});
this.chunk('}');
},
walkContext: 'block'
};
});
this.token(RightCurlyBracket, '}');
}

@@ -1,34 +0,35 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Delim,
LeftSquareBracket,
RightSquareBracket
} from '../../tokenizer/index.js';
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;
var RIGHTSQUAREBRACKET = TYPE.RightSquareBracket;
export const name = 'Brackets';
export const structure = {
children: [[]]
};
module.exports = {
name: 'Brackets',
structure: {
children: [[]]
},
parse: function(readSequence, recognizer) {
var start = this.scanner.tokenStart;
var children = null;
export function parse(readSequence, recognizer) {
const start = this.tokenStart;
let children = null;
this.eat(LEFTSQUAREBRACKET);
this.eat(LeftSquareBracket);
children = readSequence.call(this, recognizer);
children = readSequence.call(this, recognizer);
if (!this.scanner.eof) {
this.eat(RIGHTSQUAREBRACKET);
}
if (!this.eof) {
this.eat(RightSquareBracket);
}
return {
type: 'Brackets',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
},
generate: function(node) {
this.chunk('[');
this.children(node);
this.chunk(']');
}
};
return {
type: 'Brackets',
loc: this.getLocation(start, this.tokenStart),
children
};
}
export function generate(node) {
this.token(Delim, '[');
this.children(node);
this.token(Delim, ']');
}

@@ -1,19 +0,19 @@

var CDC = require('../../tokenizer').TYPE.CDC;
import { CDC } from '../../tokenizer/index.js';
module.exports = {
name: 'CDC',
structure: [],
parse: function() {
var start = this.scanner.tokenStart;
export const name = 'CDC';
export const structure = [];
this.eat(CDC); // -->
export function parse() {
const start = this.tokenStart;
return {
type: 'CDC',
loc: this.getLocation(start, this.scanner.tokenStart)
};
},
generate: function() {
this.chunk('-->');
}
};
this.eat(CDC); // -->
return {
type: 'CDC',
loc: this.getLocation(start, this.tokenStart)
};
}
export function generate() {
this.token(CDC, '-->');
}

@@ -1,19 +0,19 @@

var CDO = require('../../tokenizer').TYPE.CDO;
import { CDO } from '../../tokenizer/index.js';
module.exports = {
name: 'CDO',
structure: [],
parse: function() {
var start = this.scanner.tokenStart;
export const name = 'CDO';
export const structure = [];
this.eat(CDO); // <!--
export function parse() {
const start = this.tokenStart;
return {
type: 'CDO',
loc: this.getLocation(start, this.scanner.tokenStart)
};
},
generate: function() {
this.chunk('<!--');
}
};
this.eat(CDO); // <!--
return {
type: 'CDO',
loc: this.getLocation(start, this.tokenStart)
};
}
export function generate() {
this.token(CDO, '<!--');
}

@@ -1,29 +0,24 @@

var TYPE = require('../../tokenizer').TYPE;
import { Delim, Ident } from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var FULLSTOP = 0x002E; // U+002E FULL STOP (.)
const FULLSTOP = 0x002E; // U+002E FULL STOP (.)
// '.' ident
module.exports = {
name: 'ClassSelector',
structure: {
name: String
},
parse: function() {
if (!this.scanner.isDelim(FULLSTOP)) {
this.error('Full stop is expected');
}
export const name = 'ClassSelector';
export const structure = {
name: String
};
this.scanner.next();
export function parse() {
this.eatDelim(FULLSTOP);
return {
type: 'ClassSelector',
loc: this.getLocation(this.scanner.tokenStart - 1, this.scanner.tokenEnd),
name: this.consume(IDENT)
};
},
generate: function(node) {
this.chunk('.');
this.chunk(node.name);
}
};
return {
type: 'ClassSelector',
loc: this.getLocation(this.tokenStart - 1, this.tokenEnd),
name: this.consume(Ident)
};
}
export function generate(node) {
this.token(Delim, '.');
this.token(Ident, node.name);
}

@@ -1,55 +0,54 @@

var TYPE = require('../../tokenizer').TYPE;
import { WhiteSpace, Delim } from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
var GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
var TILDE = 0x007E; // U+007E TILDE (~)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
const TILDE = 0x007E; // U+007E TILDE (~)
export const name = 'Combinator';
export const structure = {
name: String
};
// + | > | ~ | /deep/
module.exports = {
name: 'Combinator',
structure: {
name: String
},
parse: function() {
var start = this.scanner.tokenStart;
var code = this.scanner.source.charCodeAt(this.scanner.tokenStart);
export function parse() {
const start = this.tokenStart;
let name;
switch (code) {
case GREATERTHANSIGN:
case PLUSSIGN:
case TILDE:
this.scanner.next();
break;
switch (this.tokenType) {
case WhiteSpace:
name = ' ';
break;
case SOLIDUS:
this.scanner.next();
case Delim:
switch (this.charCodeAt(this.tokenStart)) {
case GREATERTHANSIGN:
case PLUSSIGN:
case TILDE:
this.next();
break;
if (this.scanner.tokenType !== IDENT || this.scanner.lookupValue(0, 'deep') === false) {
this.error('Identifier `deep` is expected');
}
case SOLIDUS:
this.next();
this.eatIdent('deep');
this.eatDelim(SOLIDUS);
break;
this.scanner.next();
default:
this.error('Combinator is expected');
}
if (!this.scanner.isDelim(SOLIDUS)) {
this.error('Solidus is expected');
}
name = this.substrToCursor(start);
break;
}
this.scanner.next();
break;
return {
type: 'Combinator',
loc: this.getLocation(start, this.tokenStart),
name
};
}
default:
this.error('Combinator is expected');
}
return {
type: 'Combinator',
loc: this.getLocation(start, this.scanner.tokenStart),
name: this.scanner.substrToCursor(start)
};
},
generate: function(node) {
this.chunk(node.name);
}
};
export function generate(node) {
this.tokenize(node.name);
}

@@ -1,36 +0,33 @@

var TYPE = require('../../tokenizer').TYPE;
import { Comment } from '../../tokenizer/index.js';
var COMMENT = TYPE.Comment;
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
// '/*' .* '*/'
module.exports = {
name: 'Comment',
structure: {
value: String
},
parse: function() {
var start = this.scanner.tokenStart;
var end = this.scanner.tokenEnd;
this.eat(COMMENT);
export const name = 'Comment';
export const structure = {
value: String
};
if ((end - start + 2) >= 2 &&
this.scanner.source.charCodeAt(end - 2) === ASTERISK &&
this.scanner.source.charCodeAt(end - 1) === SOLIDUS) {
end -= 2;
}
export function parse() {
const start = this.tokenStart;
let end = this.tokenEnd;
return {
type: 'Comment',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.source.substring(start + 2, end)
};
},
generate: function(node) {
this.chunk('/*');
this.chunk(node.value);
this.chunk('*/');
this.eat(Comment);
if ((end - start + 2) >= 2 &&
this.charCodeAt(end - 2) === ASTERISK &&
this.charCodeAt(end - 1) === SOLIDUS) {
end -= 2;
}
};
return {
type: 'Comment',
loc: this.getLocation(start, this.tokenStart),
value: this.substring(start + 2, end)
};
}
export function generate(node) {
this.token(Comment, '/*' + node.value + '*/');
}

@@ -1,36 +0,36 @@

var isCustomProperty = require('../../utils/names').isCustomProperty;
var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('./Raw').mode;
import { isCustomProperty } from '../../utils/names.js';
import {
Ident,
Hash,
Colon,
Semicolon,
Delim,
WhiteSpace
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var HASH = TYPE.Hash;
var COLON = TYPE.Colon;
var SEMICOLON = TYPE.Semicolon;
var DELIM = TYPE.Delim;
var WHITESPACE = TYPE.WhiteSpace;
var EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
var DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
var AMPERSAND = 0x0026; // U+0026 ANPERSAND (&)
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
const NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
const DOLLARSIGN = 0x0024; // U+0024 DOLLAR SIGN ($)
const AMPERSAND = 0x0026; // U+0026 AMPERSAND (&)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
function consumeValueRaw(startToken) {
return this.Raw(startToken, rawMode.exclamationMarkOrSemicolon, true);
return this.Raw(startToken, this.consumeUntilExclamationMarkOrSemicolon, true);
}
function consumeCustomPropertyRaw(startToken) {
return this.Raw(startToken, rawMode.exclamationMarkOrSemicolon, false);
return this.Raw(startToken, this.consumeUntilExclamationMarkOrSemicolon, false);
}
function consumeValue() {
var startValueToken = this.scanner.tokenIndex;
var value = this.Value();
const startValueToken = this.tokenIndex;
const value = this.Value();
if (value.type !== 'Raw' &&
this.scanner.eof === false &&
this.scanner.tokenType !== SEMICOLON &&
this.scanner.isDelim(EXCLAMATIONMARK) === false &&
this.scanner.isBalanceEdge(startValueToken) === false) {
this.eof === false &&
this.tokenType !== Semicolon &&
this.isDelim(EXCLAMATIONMARK) === false &&
this.isBalanceEdge(startValueToken) === false) {
this.error();

@@ -42,88 +42,88 @@ }

module.exports = {
name: 'Declaration',
structure: {
important: [Boolean, String],
property: String,
value: ['Value', 'Raw']
},
parse: function() {
var start = this.scanner.tokenStart;
var startToken = this.scanner.tokenIndex;
var property = readProperty.call(this);
var customProperty = isCustomProperty(property);
var parseValue = customProperty ? this.parseCustomProperty : this.parseValue;
var consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw;
var important = false;
var value;
export const name = 'Declaration';
export const walkContext = 'declaration';
export const structure = {
important: [Boolean, String],
property: String,
value: ['Value', 'Raw']
};
this.scanner.skipSC();
this.eat(COLON);
export function parse() {
const start = this.tokenStart;
const startToken = this.tokenIndex;
const property = readProperty.call(this);
const customProperty = isCustomProperty(property);
const parseValue = customProperty ? this.parseCustomProperty : this.parseValue;
const consumeRaw = customProperty ? consumeCustomPropertyRaw : consumeValueRaw;
let important = false;
let value;
const valueStart = this.scanner.tokenIndex;
this.skipSC();
this.eat(Colon);
if (!customProperty) {
this.scanner.skipSC();
}
const valueStart = this.tokenIndex;
if (parseValue) {
value = this.parseWithFallback(consumeValue, consumeRaw);
} else {
value = consumeRaw.call(this, this.scanner.tokenIndex);
}
if (!customProperty) {
this.skipSC();
}
if (customProperty && value.type === 'Value' && value.children.isEmpty()) {
for (let offset = valueStart - this.scanner.tokenIndex; offset <= 0; offset++) {
if (this.scanner.lookupType(offset) === WHITESPACE) {
value.children.appendData({
type: 'WhiteSpace',
loc: null,
value: ' '
});
break;
}
if (parseValue) {
value = this.parseWithFallback(consumeValue, consumeRaw);
} else {
value = consumeRaw.call(this, this.tokenIndex);
}
if (customProperty && value.type === 'Value' && value.children.isEmpty) {
for (let offset = valueStart - this.tokenIndex; offset <= 0; offset++) {
if (this.lookupType(offset) === WhiteSpace) {
value.children.appendData({
type: 'WhiteSpace',
loc: null,
value: ' '
});
break;
}
}
}
if (this.scanner.isDelim(EXCLAMATIONMARK)) {
important = getImportant.call(this);
this.scanner.skipSC();
}
if (this.isDelim(EXCLAMATIONMARK)) {
important = getImportant.call(this);
this.skipSC();
}
// Do not include semicolon to range per spec
// https://drafts.csswg.org/css-syntax/#declaration-diagram
// Do not include semicolon to range per spec
// https://drafts.csswg.org/css-syntax/#declaration-diagram
if (this.scanner.eof === false &&
this.scanner.tokenType !== SEMICOLON &&
this.scanner.isBalanceEdge(startToken) === false) {
this.error();
}
if (this.eof === false &&
this.tokenType !== Semicolon &&
this.isBalanceEdge(startToken) === false) {
this.error();
}
return {
type: 'Declaration',
loc: this.getLocation(start, this.scanner.tokenStart),
important: important,
property: property,
value: value
};
},
generate: function(node) {
this.chunk(node.property);
this.chunk(':');
this.node(node.value);
return {
type: 'Declaration',
loc: this.getLocation(start, this.tokenStart),
important,
property,
value
};
}
if (node.important) {
this.chunk(node.important === true ? '!important' : '!' + node.important);
}
},
walkContext: 'declaration'
};
export function generate(node) {
this.token(Ident, node.property);
this.token(Colon, ':');
this.node(node.value);
if (node.important) {
this.token(Delim, '!');
this.token(Ident, node.important === true ? 'important' : node.important);
}
}
function readProperty() {
var start = this.scanner.tokenStart;
var prefix = 0;
const start = this.tokenStart;
// hacks
if (this.scanner.tokenType === DELIM) {
switch (this.scanner.source.charCodeAt(this.scanner.tokenStart)) {
if (this.tokenType === Delim) {
switch (this.charCodeAt(this.tokenStart)) {
case ASTERISK:

@@ -134,3 +134,3 @@ case DOLLARSIGN:

case AMPERSAND:
this.scanner.next();
this.next();
break;

@@ -140,5 +140,5 @@

case SOLIDUS:
this.scanner.next();
if (this.scanner.isDelim(SOLIDUS)) {
this.scanner.next();
this.next();
if (this.isDelim(SOLIDUS)) {
this.next();
}

@@ -149,13 +149,9 @@ break;

if (prefix) {
this.scanner.skip(prefix);
}
if (this.scanner.tokenType === HASH) {
this.eat(HASH);
if (this.tokenType === Hash) {
this.eat(Hash);
} else {
this.eat(IDENT);
this.eat(Ident);
}
return this.scanner.substrToCursor(start);
return this.substrToCursor(start);
}

@@ -165,6 +161,6 @@

function getImportant() {
this.eat(DELIM);
this.scanner.skipSC();
this.eat(Delim);
this.skipSC();
var important = this.consume(IDENT);
const important = this.consume(Ident);

@@ -171,0 +167,0 @@ // store original value in case it differ from `important`

@@ -1,49 +0,49 @@

var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('./Raw').mode;
import {
WhiteSpace,
Comment,
Semicolon
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var SEMICOLON = TYPE.Semicolon;
function consumeRaw(startToken) {
return this.Raw(startToken, rawMode.semicolonIncluded, true);
return this.Raw(startToken, this.consumeUntilSemicolonIncluded, true);
}
module.exports = {
name: 'DeclarationList',
structure: {
children: [[
'Declaration'
]]
},
parse: function() {
var children = this.createList();
export const name = 'DeclarationList';
export const structure = {
children: [[
'Declaration'
]]
};
scan:
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case WHITESPACE:
case COMMENT:
case SEMICOLON:
this.scanner.next();
break;
export function parse() {
const children = this.createList();
default:
children.push(this.parseWithFallback(this.Declaration, consumeRaw));
}
scan:
while (!this.eof) {
switch (this.tokenType) {
case WhiteSpace:
case Comment:
case Semicolon:
this.next();
break;
default:
children.push(this.parseWithFallback(this.Declaration, consumeRaw));
}
}
return {
type: 'DeclarationList',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node, function(prev) {
if (prev.type === 'Declaration') {
this.chunk(';');
}
});
}
};
return {
type: 'DeclarationList',
loc: this.getLocationFromList(children),
children
};
}
export function generate(node) {
this.children(node, prev => {
if (prev.type === 'Declaration') {
this.token(Semicolon, ';');
}
});
}

@@ -1,29 +0,23 @@

var consumeNumber = require('../../tokenizer/utils').consumeNumber;
var TYPE = require('../../tokenizer').TYPE;
import { Dimension } from '../../tokenizer/index.js';
var DIMENSION = TYPE.Dimension;
export const name = 'Dimension';
export const structure = {
value: String,
unit: String
};
module.exports = {
name: 'Dimension',
structure: {
value: String,
unit: String
},
parse: function() {
var start = this.scanner.tokenStart;
var numberEnd = consumeNumber(this.scanner.source, start);
export function parse() {
const start = this.tokenStart;
const value = this.consumeNumber(Dimension);
this.eat(DIMENSION);
return {
type: 'Dimension',
loc: this.getLocation(start, this.tokenStart),
value,
unit: this.substring(start + value.length, this.tokenStart)
};
}
return {
type: 'Dimension',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.source.substring(start, numberEnd),
unit: this.scanner.source.substring(numberEnd, this.scanner.tokenStart)
};
},
generate: function(node) {
this.chunk(node.value);
this.chunk(node.unit);
}
};
export function generate(node) {
this.token(Dimension, node.value + node.unit);
}

@@ -1,40 +0,41 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Function as FunctionToken,
RightParenthesis
} from '../../tokenizer/index.js';
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
export const name = 'Function';
export const walkContext = 'function';
export const structure = {
name: String,
children: [[]]
};
// <function-token> <sequence> )
module.exports = {
name: 'Function',
structure: {
name: String,
children: [[]]
},
parse: function(readSequence, recognizer) {
var start = this.scanner.tokenStart;
var name = this.consumeFunctionName();
var nameLowerCase = name.toLowerCase();
var children;
export function parse(readSequence, recognizer) {
const start = this.tokenStart;
const name = this.consumeFunctionName();
const nameLowerCase = name.toLowerCase();
let children;
children = recognizer.hasOwnProperty(nameLowerCase)
? recognizer[nameLowerCase].call(this, recognizer)
: readSequence.call(this, recognizer);
children = recognizer.hasOwnProperty(nameLowerCase)
? recognizer[nameLowerCase].call(this, recognizer)
: readSequence.call(this, recognizer);
if (!this.scanner.eof) {
this.eat(RIGHTPARENTHESIS);
}
if (!this.eof) {
this.eat(RightParenthesis);
}
return {
type: 'Function',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
children: children
};
},
generate: function(node) {
this.chunk(node.name);
this.chunk('(');
this.children(node);
this.chunk(')');
},
walkContext: 'function'
};
return {
type: 'Function',
loc: this.getLocation(start, this.tokenStart),
name,
children
};
}
export function generate(node) {
this.token(FunctionToken, node.name + '(');
this.children(node);
this.token(RightParenthesis, ')');
}

@@ -1,26 +0,23 @@

var TYPE = require('../../tokenizer').TYPE;
import { Hash } from '../../tokenizer/index.js';
var HASH = TYPE.Hash;
// '#' ident
module.exports = {
name: 'Hash',
structure: {
value: String
},
parse: function() {
var start = this.scanner.tokenStart;
export const xxx = 'XXX';
export const name = 'Hash';
export const structure = {
value: String
};
export function parse() {
const start = this.tokenStart;
this.eat(HASH);
this.eat(Hash);
return {
type: 'Hash',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.substrToCursor(start + 1)
};
},
generate: function(node) {
this.chunk('#');
this.chunk(node.value);
}
};
return {
type: 'Hash',
loc: this.getLocation(start, this.tokenStart),
value: this.substrToCursor(start + 1)
};
}
export function generate(node) {
this.token(Hash, '#' + node.value);
}

@@ -1,20 +0,18 @@

var TYPE = require('../../tokenizer').TYPE;
import { Ident } from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
export const name = 'Identifier';
export const structure = {
name: String
};
module.exports = {
name: 'Identifier',
structure: {
name: String
},
parse: function() {
return {
type: 'Identifier',
loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd),
name: this.consume(IDENT)
};
},
generate: function(node) {
this.chunk(node.name);
}
};
export function parse() {
return {
type: 'Identifier',
loc: this.getLocation(this.tokenStart, this.tokenEnd),
name: this.consume(Ident)
};
}
export function generate(node) {
this.token(Ident, node.name);
}

@@ -1,27 +0,23 @@

var TYPE = require('../../tokenizer').TYPE;
import { Hash } from '../../tokenizer/index.js';
var HASH = TYPE.Hash;
export const name = 'IdSelector';
export const structure = {
name: String
};
// <hash-token>
module.exports = {
name: 'IdSelector',
structure: {
name: String
},
parse: function() {
var start = this.scanner.tokenStart;
export function parse() {
const start = this.tokenStart;
// TODO: check value is an ident
this.eat(HASH);
// TODO: check value is an ident
this.eat(Hash);
return {
type: 'IdSelector',
loc: this.getLocation(start, this.scanner.tokenStart),
name: this.scanner.substrToCursor(start + 1)
};
},
generate: function(node) {
this.chunk('#');
this.chunk(node.name);
}
};
return {
type: 'IdSelector',
loc: this.getLocation(start, this.tokenStart),
name: this.substrToCursor(start + 1)
};
}
export function generate(node) {
this.token(Hash, '#' + node.name);
}

@@ -1,42 +0,40 @@

module.exports = {
AnPlusB: require('./AnPlusB'),
Atrule: require('./Atrule'),
AtrulePrelude: require('./AtrulePrelude'),
AttributeSelector: require('./AttributeSelector'),
Block: require('./Block'),
Brackets: require('./Brackets'),
CDC: require('./CDC'),
CDO: require('./CDO'),
ClassSelector: require('./ClassSelector'),
Combinator: require('./Combinator'),
Comment: require('./Comment'),
Declaration: require('./Declaration'),
DeclarationList: require('./DeclarationList'),
Dimension: require('./Dimension'),
Function: require('./Function'),
Hash: require('./Hash'),
Identifier: require('./Identifier'),
IdSelector: require('./IdSelector'),
MediaFeature: require('./MediaFeature'),
MediaQuery: require('./MediaQuery'),
MediaQueryList: require('./MediaQueryList'),
Nth: require('./Nth'),
Number: require('./Number'),
Operator: require('./Operator'),
Parentheses: require('./Parentheses'),
Percentage: require('./Percentage'),
PseudoClassSelector: require('./PseudoClassSelector'),
PseudoElementSelector: require('./PseudoElementSelector'),
Ratio: require('./Ratio'),
Raw: require('./Raw'),
Rule: require('./Rule'),
Selector: require('./Selector'),
SelectorList: require('./SelectorList'),
String: require('./String'),
StyleSheet: require('./StyleSheet'),
TypeSelector: require('./TypeSelector'),
UnicodeRange: require('./UnicodeRange'),
Url: require('./Url'),
Value: require('./Value'),
WhiteSpace: require('./WhiteSpace')
};
export * as AnPlusB from './AnPlusB.js';
export * as Atrule from './Atrule.js';
export * as AtrulePrelude from './AtrulePrelude.js';
export * as AttributeSelector from './AttributeSelector.js';
export * as Block from './Block.js';
export * as Brackets from './Brackets.js';
export * as CDC from './CDC.js';
export * as CDO from './CDO.js';
export * as ClassSelector from './ClassSelector.js';
export * as Combinator from './Combinator.js';
export * as Comment from './Comment.js';
export * as Declaration from './Declaration.js';
export * as DeclarationList from './DeclarationList.js';
export * as Dimension from './Dimension.js';
export * as Function from './Function.js';
export * as Hash from './Hash.js';
export * as Identifier from './Identifier.js';
export * as IdSelector from './IdSelector.js';
export * as MediaFeature from './MediaFeature.js';
export * as MediaQuery from './MediaQuery.js';
export * as MediaQueryList from './MediaQueryList.js';
export * as Nth from './Nth.js';
export * as Number from './Number.js';
export * as Operator from './Operator.js';
export * as Parentheses from './Parentheses.js';
export * as Percentage from './Percentage.js';
export * as PseudoClassSelector from './PseudoClassSelector.js';
export * as PseudoElementSelector from './PseudoElementSelector.js';
export * as Ratio from './Ratio.js';
export * as Raw from './Raw.js';
export * as Rule from './Rule.js';
export * as Selector from './Selector.js';
export * as SelectorList from './SelectorList.js';
export * as String from './String.js';
export * as StyleSheet from './StyleSheet.js';
export * as TypeSelector from './TypeSelector.js';
export * as UnicodeRange from './UnicodeRange.js';
export * as Url from './Url.js';
export * as Value from './Value.js';
export * as WhiteSpace from './WhiteSpace.js';

@@ -1,76 +0,77 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Ident,
Number,
Dimension,
LeftParenthesis,
RightParenthesis,
Colon,
Delim
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var NUMBER = TYPE.Number;
var DIMENSION = TYPE.Dimension;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
var COLON = TYPE.Colon;
var DELIM = TYPE.Delim;
export const name = 'MediaFeature';
export const structure = {
name: String,
value: ['Identifier', 'Number', 'Dimension', 'Ratio', null]
};
module.exports = {
name: 'MediaFeature',
structure: {
name: String,
value: ['Identifier', 'Number', 'Dimension', 'Ratio', null]
},
parse: function() {
var start = this.scanner.tokenStart;
var name;
var value = null;
export function parse() {
const start = this.tokenStart;
let name;
let value = null;
this.eat(LEFTPARENTHESIS);
this.scanner.skipSC();
this.eat(LeftParenthesis);
this.skipSC();
name = this.consume(IDENT);
this.scanner.skipSC();
name = this.consume(Ident);
this.skipSC();
if (this.scanner.tokenType !== RIGHTPARENTHESIS) {
this.eat(COLON);
this.scanner.skipSC();
if (this.tokenType !== RightParenthesis) {
this.eat(Colon);
this.skipSC();
switch (this.scanner.tokenType) {
case NUMBER:
if (this.lookupNonWSType(1) === DELIM) {
value = this.Ratio();
} else {
value = this.Number();
}
switch (this.tokenType) {
case Number:
if (this.lookupNonWSType(1) === Delim) {
value = this.Ratio();
} else {
value = this.Number();
}
break;
break;
case DIMENSION:
value = this.Dimension();
break;
case Dimension:
value = this.Dimension();
break;
case IDENT:
value = this.Identifier();
case Ident:
value = this.Identifier();
break;
break;
default:
this.error('Number, dimension, ratio or identifier is expected');
}
default:
this.error('Number, dimension, ratio or identifier is expected');
}
this.skipSC();
}
this.scanner.skipSC();
}
this.eat(RightParenthesis);
this.eat(RIGHTPARENTHESIS);
return {
type: 'MediaFeature',
loc: this.getLocation(start, this.tokenStart),
name,
value
};
}
return {
type: 'MediaFeature',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
value: value
};
},
generate: function(node) {
this.chunk('(');
this.chunk(node.name);
if (node.value !== null) {
this.chunk(':');
this.node(node.value);
}
this.chunk(')');
export function generate(node) {
this.token(LeftParenthesis, '(');
this.token(Ident, node.name);
if (node.value !== null) {
this.token(Colon, ':');
this.node(node.value);
}
};
this.token(RightParenthesis, ')');
}

@@ -1,68 +0,60 @@

var TYPE = require('../../tokenizer').TYPE;
import {
WhiteSpace,
Comment,
Ident,
LeftParenthesis
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var IDENT = TYPE.Ident;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
export const name = 'MediaQuery';
export const structure = {
children: [[
'Identifier',
'MediaFeature',
'WhiteSpace'
]]
};
module.exports = {
name: 'MediaQuery',
structure: {
children: [[
'Identifier',
'MediaFeature',
'WhiteSpace'
]]
},
parse: function() {
this.scanner.skipSC();
export function parse() {
const children = this.createList();
let child = null;
var children = this.createList();
var child = null;
var space = null;
this.skipSC();
scan:
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case COMMENT:
this.scanner.next();
continue;
scan:
while (!this.eof) {
switch (this.tokenType) {
case Comment:
case WhiteSpace:
this.next();
continue;
case WHITESPACE:
space = this.WhiteSpace();
continue;
case Ident:
child = this.Identifier();
break;
case IDENT:
child = this.Identifier();
break;
case LeftParenthesis:
child = this.MediaFeature();
break;
case LEFTPARENTHESIS:
child = this.MediaFeature();
break;
default:
break scan;
}
default:
break scan;
}
children.push(child);
}
if (space !== null) {
children.push(space);
space = null;
}
if (child === null) {
this.error('Identifier or parenthesis is expected');
}
children.push(child);
}
return {
type: 'MediaQuery',
loc: this.getLocationFromList(children),
children
};
}
if (child === null) {
this.error('Identifier or parenthesis is expected');
}
export function generate(node) {
this.children(node);
}
return {
type: 'MediaQuery',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node);
}
};

@@ -1,36 +0,34 @@

var COMMA = require('../../tokenizer').TYPE.Comma;
import { Comma } from '../../tokenizer/index.js';
module.exports = {
name: 'MediaQueryList',
structure: {
children: [[
'MediaQuery'
]]
},
parse: function(relative) {
var children = this.createList();
export const name = 'MediaQueryList';
export const structure = {
children: [[
'MediaQuery'
]]
};
this.scanner.skipSC();
export function parse() {
const children = this.createList();
while (!this.scanner.eof) {
children.push(this.MediaQuery(relative));
this.skipSC();
if (this.scanner.tokenType !== COMMA) {
break;
}
while (!this.eof) {
children.push(this.MediaQuery());
this.scanner.next();
if (this.tokenType !== Comma) {
break;
}
return {
type: 'MediaQueryList',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node, function() {
this.chunk(',');
});
this.next();
}
};
return {
type: 'MediaQueryList',
loc: this.getLocationFromList(children),
children
};
}
export function generate(node) {
this.children(node, () => this.token(Comma, ','));
}

@@ -1,51 +0,47 @@

module.exports = {
name: 'Nth',
structure: {
nth: ['AnPlusB', 'Identifier'],
selector: ['SelectorList', null]
},
parse: function(allowOfClause) {
this.scanner.skipSC();
import { Ident } from '../../tokenizer/index.js';
var start = this.scanner.tokenStart;
var end = start;
var selector = null;
var query;
export const name = 'Nth';
export const structure = {
nth: ['AnPlusB', 'Identifier'],
selector: ['SelectorList', null]
};
if (this.scanner.lookupValue(0, 'odd') || this.scanner.lookupValue(0, 'even')) {
query = this.Identifier();
} else {
query = this.AnPlusB();
}
export function parse() {
this.skipSC();
this.scanner.skipSC();
const start = this.tokenStart;
let end = start;
let selector = null;
let nth;
if (allowOfClause && this.scanner.lookupValue(0, 'of')) {
this.scanner.next();
if (this.lookupValue(0, 'odd') || this.lookupValue(0, 'even')) {
nth = this.Identifier();
} else {
nth = this.AnPlusB();
}
selector = this.SelectorList();
end = this.tokenStart;
this.skipSC();
if (this.needPositions) {
end = this.getLastListNode(selector.children).loc.end.offset;
}
} else {
if (this.needPositions) {
end = query.loc.end.offset;
}
}
if (this.lookupValue(0, 'of')) {
this.next();
return {
type: 'Nth',
loc: this.getLocation(start, end),
nth: query,
selector: selector
};
},
generate: function(node) {
this.node(node.nth);
if (node.selector !== null) {
this.chunk(' of ');
this.node(node.selector);
}
selector = this.SelectorList();
end = this.tokenStart;
}
};
return {
type: 'Nth',
loc: this.getLocation(start, end),
nth,
selector
};
}
export function generate(node) {
this.node(node.nth);
if (node.selector !== null) {
this.token(Ident, 'of');
this.node(node.selector);
}
}

@@ -1,18 +0,18 @@

var NUMBER = require('../../tokenizer').TYPE.Number;
import { Number as NumberToken } from '../../tokenizer/index.js';
module.exports = {
name: 'Number',
structure: {
value: String
},
parse: function() {
return {
type: 'Number',
loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd),
value: this.consume(NUMBER)
};
},
generate: function(node) {
this.chunk(node.value);
}
export const name = 'Number';
export const structure = {
value: String
};
export function parse() {
return {
type: 'Number',
loc: this.getLocation(this.tokenStart, this.tokenEnd),
value: this.consume(NumberToken)
};
}
export function generate(node) {
this.token(NumberToken, node.value);
}
// '/' | '*' | ',' | ':' | '+' | '-'
module.exports = {
name: 'Operator',
structure: {
value: String
},
parse: function() {
var start = this.scanner.tokenStart;
export const name = 'Operator';
export const structure = {
value: String
};
this.scanner.next();
export function parse() {
const start = this.tokenStart;
return {
type: 'Operator',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.substrToCursor(start)
};
},
generate: function(node) {
this.chunk(node.value);
}
};
this.next();
return {
type: 'Operator',
loc: this.getLocation(start, this.tokenStart),
value: this.substrToCursor(start)
};
}
export function generate(node) {
this.tokenize(node.value);
}

@@ -1,34 +0,34 @@

var TYPE = require('../../tokenizer').TYPE;
import {
LeftParenthesis,
RightParenthesis
} from '../../tokenizer/index.js';
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
export const name = 'Parentheses';
export const structure = {
children: [[]]
};
module.exports = {
name: 'Parentheses',
structure: {
children: [[]]
},
parse: function(readSequence, recognizer) {
var start = this.scanner.tokenStart;
var children = null;
export function parse(readSequence, recognizer) {
const start = this.tokenStart;
let children = null;
this.eat(LEFTPARENTHESIS);
this.eat(LeftParenthesis);
children = readSequence.call(this, recognizer);
children = readSequence.call(this, recognizer);
if (!this.scanner.eof) {
this.eat(RIGHTPARENTHESIS);
}
if (!this.eof) {
this.eat(RightParenthesis);
}
return {
type: 'Parentheses',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
},
generate: function(node) {
this.chunk('(');
this.children(node);
this.chunk(')');
}
};
return {
type: 'Parentheses',
loc: this.getLocation(start, this.tokenStart),
children
};
}
export function generate(node) {
this.token(LeftParenthesis, '(');
this.children(node);
this.token(RightParenthesis, ')');
}

@@ -1,27 +0,18 @@

var consumeNumber = require('../../tokenizer/utils').consumeNumber;
var TYPE = require('../../tokenizer').TYPE;
import { Percentage } from '../../tokenizer/index.js';
var PERCENTAGE = TYPE.Percentage;
export const name = 'Percentage';
export const structure = {
value: String
};
module.exports = {
name: 'Percentage',
structure: {
value: String
},
parse: function() {
var start = this.scanner.tokenStart;
var numberEnd = consumeNumber(this.scanner.source, start);
export function parse() {
return {
type: 'Percentage',
loc: this.getLocation(this.tokenStart, this.tokenEnd),
value: this.consumeNumber(Percentage)
};
}
this.eat(PERCENTAGE);
return {
type: 'Percentage',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.source.substring(start, numberEnd)
};
},
generate: function(node) {
this.chunk(node.value);
this.chunk('%');
}
};
export function generate(node) {
this.token(Percentage, node.value + '%');
}

@@ -1,61 +0,63 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Ident,
Function as FunctionToken,
Colon,
RightParenthesis
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var FUNCTION = TYPE.Function;
var COLON = TYPE.Colon;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
export const name = 'PseudoClassSelector';
export const walkContext = 'function';
export const structure = {
name: String,
children: [['Raw'], null]
};
// : [ <ident> | <function-token> <any-value>? ) ]
module.exports = {
name: 'PseudoClassSelector',
structure: {
name: String,
children: [['Raw'], null]
},
parse: function() {
var start = this.scanner.tokenStart;
var children = null;
var name;
var nameLowerCase;
export function parse() {
const start = this.tokenStart;
let children = null;
let name;
let nameLowerCase;
this.eat(COLON);
this.eat(Colon);
if (this.scanner.tokenType === FUNCTION) {
name = this.consumeFunctionName();
nameLowerCase = name.toLowerCase();
if (this.tokenType === FunctionToken) {
name = this.consumeFunctionName();
nameLowerCase = name.toLowerCase();
if (this.pseudo.hasOwnProperty(nameLowerCase)) {
this.scanner.skipSC();
children = this.pseudo[nameLowerCase].call(this);
this.scanner.skipSC();
} else {
children = this.createList();
children.push(
this.Raw(this.scanner.tokenIndex, null, false)
);
}
this.eat(RIGHTPARENTHESIS);
if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
this.skipSC();
children = this.pseudo[nameLowerCase].call(this);
this.skipSC();
} else {
name = this.consume(IDENT);
children = this.createList();
children.push(
this.Raw(this.tokenIndex, null, false)
);
}
return {
type: 'PseudoClassSelector',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
children: children
};
},
generate: function(node) {
this.chunk(':');
this.chunk(node.name);
this.eat(RightParenthesis);
} else {
name = this.consume(Ident);
}
if (node.children !== null) {
this.chunk('(');
this.children(node);
this.chunk(')');
}
},
walkContext: 'function'
};
return {
type: 'PseudoClassSelector',
loc: this.getLocation(start, this.tokenStart),
name,
children
};
}
export function generate(node) {
this.token(Colon, ':');
if (node.children === null) {
this.token(Ident, node.name);
} else {
this.token(FunctionToken, node.name + '(');
this.children(node);
this.token(RightParenthesis, ')');
}
}

@@ -1,62 +0,64 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Ident,
Function as FunctionToken,
Colon,
RightParenthesis
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var FUNCTION = TYPE.Function;
var COLON = TYPE.Colon;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
export const name = 'PseudoElementSelector';
export const walkContext = 'function';
export const structure = {
name: String,
children: [['Raw'], null]
};
// :: [ <ident> | <function-token> <any-value>? ) ]
module.exports = {
name: 'PseudoElementSelector',
structure: {
name: String,
children: [['Raw'], null]
},
parse: function() {
var start = this.scanner.tokenStart;
var children = null;
var name;
var nameLowerCase;
export function parse() {
const start = this.tokenStart;
let children = null;
let name;
let nameLowerCase;
this.eat(COLON);
this.eat(COLON);
this.eat(Colon);
this.eat(Colon);
if (this.scanner.tokenType === FUNCTION) {
name = this.consumeFunctionName();
nameLowerCase = name.toLowerCase();
if (this.tokenType === FunctionToken) {
name = this.consumeFunctionName();
nameLowerCase = name.toLowerCase();
if (this.pseudo.hasOwnProperty(nameLowerCase)) {
this.scanner.skipSC();
children = this.pseudo[nameLowerCase].call(this);
this.scanner.skipSC();
} else {
children = this.createList();
children.push(
this.Raw(this.scanner.tokenIndex, null, false)
);
}
this.eat(RIGHTPARENTHESIS);
if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
this.skipSC();
children = this.pseudo[nameLowerCase].call(this);
this.skipSC();
} else {
name = this.consume(IDENT);
children = this.createList();
children.push(
this.Raw(this.tokenIndex, null, false)
);
}
return {
type: 'PseudoElementSelector',
loc: this.getLocation(start, this.scanner.tokenStart),
name: name,
children: children
};
},
generate: function(node) {
this.chunk('::');
this.chunk(node.name);
this.eat(RightParenthesis);
} else {
name = this.consume(Ident);
}
if (node.children !== null) {
this.chunk('(');
this.children(node);
this.chunk(')');
}
},
walkContext: 'function'
};
return {
type: 'PseudoElementSelector',
loc: this.getLocation(start, this.tokenStart),
name,
children
};
}
export function generate(node) {
this.token(Colon, ':');
this.token(Colon, ':');
if (node.children === null) {
this.token(Ident, node.name);
} else {
this.token(FunctionToken, node.name + '(');
this.children(node);
this.token(RightParenthesis, ')');
}
}

@@ -1,8 +0,5 @@

var isDigit = require('../../tokenizer').isDigit;
var TYPE = require('../../tokenizer').TYPE;
import { isDigit, Delim, Number as NumberToken } from '../../tokenizer/index.js';
var NUMBER = TYPE.Number;
var DELIM = TYPE.Delim;
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
var FULLSTOP = 0x002E; // U+002E FULL STOP (.)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const FULLSTOP = 0x002E; // U+002E FULL STOP (.)

@@ -16,10 +13,10 @@ // Terms of <ratio> should be a positive numbers (not zero or negative)

function consumeNumber() {
this.scanner.skipWS();
this.skipSC();
var value = this.consume(NUMBER);
const value = this.consume(NumberToken);
for (var i = 0; i < value.length; i++) {
var code = value.charCodeAt(i);
for (let i = 0; i < value.length; i++) {
const code = value.charCodeAt(i);
if (!isDigit(code) && code !== FULLSTOP) {
this.error('Unsigned number is expected', this.scanner.tokenStart - value.length + i);
this.error('Unsigned number is expected', this.tokenStart - value.length + i);
}

@@ -29,3 +26,3 @@ }

if (Number(value) === 0) {
this.error('Zero number is not allowed', this.scanner.tokenStart - value.length);
this.error('Zero number is not allowed', this.tokenStart - value.length);
}

@@ -36,34 +33,30 @@

export const name = 'Ratio';
export const structure = {
left: String,
right: String
};
// <positive-integer> S* '/' S* <positive-integer>
module.exports = {
name: 'Ratio',
structure: {
left: String,
right: String
},
parse: function() {
var start = this.scanner.tokenStart;
var left = consumeNumber.call(this);
var right;
export function parse() {
const start = this.tokenStart;
const left = consumeNumber.call(this);
let right;
this.scanner.skipWS();
this.skipSC();
this.eatDelim(SOLIDUS);
right = consumeNumber.call(this);
if (!this.scanner.isDelim(SOLIDUS)) {
this.error('Solidus is expected');
}
this.eat(DELIM);
right = consumeNumber.call(this);
return {
type: 'Ratio',
loc: this.getLocation(start, this.tokenStart),
left,
right
};
}
return {
type: 'Ratio',
loc: this.getLocation(start, this.scanner.tokenStart),
left: left,
right: right
};
},
generate: function(node) {
this.chunk(node.left);
this.chunk('/');
this.chunk(node.right);
}
};
export function generate(node) {
this.token(NumberToken, node.left);
this.token(Delim, '/');
this.token(NumberToken, node.right);
}

@@ -1,87 +0,41 @@

var tokenizer = require('../../tokenizer');
var TYPE = tokenizer.TYPE;
import { WhiteSpace } from '../../tokenizer/index.js';
var WhiteSpace = TYPE.WhiteSpace;
var Semicolon = TYPE.Semicolon;
var LeftCurlyBracket = TYPE.LeftCurlyBracket;
var Delim = TYPE.Delim;
var EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
function getOffsetExcludeWS() {
if (this.scanner.tokenIndex > 0) {
if (this.scanner.lookupType(-1) === WhiteSpace) {
return this.scanner.tokenIndex > 1
? this.scanner.getTokenStart(this.scanner.tokenIndex - 1)
: this.scanner.firstCharOffset;
if (this.tokenIndex > 0) {
if (this.lookupType(-1) === WhiteSpace) {
return this.tokenIndex > 1
? this.getTokenStart(this.tokenIndex - 1)
: this.firstCharOffset;
}
}
return this.scanner.tokenStart;
return this.tokenStart;
}
// 0, 0, false
function balanceEnd() {
return 0;
}
export const name = 'Raw';
export const structure = {
value: String
};
// LEFTCURLYBRACKET, 0, false
function leftCurlyBracket(tokenType) {
return tokenType === LeftCurlyBracket ? 1 : 0;
}
export function parse(startToken, consumeUntil, excludeWhiteSpace) {
const startOffset = this.getTokenStart(startToken);
let endOffset;
// LEFTCURLYBRACKET, SEMICOLON, false
function leftCurlyBracketOrSemicolon(tokenType) {
return tokenType === LeftCurlyBracket || tokenType === Semicolon ? 1 : 0;
}
this.skipUntilBalanced(startToken, consumeUntil || this.consumeUntilBalanceEnd);
// EXCLAMATIONMARK, SEMICOLON, false
function exclamationMarkOrSemicolon(tokenType, source, offset) {
if (tokenType === Delim && source.charCodeAt(offset) === EXCLAMATIONMARK) {
return 1;
if (excludeWhiteSpace && this.tokenStart > startOffset) {
endOffset = getOffsetExcludeWS.call(this);
} else {
endOffset = this.tokenStart;
}
return tokenType === Semicolon ? 1 : 0;
return {
type: 'Raw',
loc: this.getLocation(startOffset, endOffset),
value: this.substring(startOffset, endOffset)
};
}
// 0, SEMICOLON, true
function semicolonIncluded(tokenType) {
return tokenType === Semicolon ? 2 : 0;
export function generate(node) {
this.tokenize(node.value);
}
module.exports = {
name: 'Raw',
structure: {
value: String
},
parse: function(startToken, mode, excludeWhiteSpace) {
var startOffset = this.scanner.getTokenStart(startToken);
var endOffset;
this.scanner.skip(
this.scanner.getRawLength(startToken, mode || balanceEnd)
);
if (excludeWhiteSpace && this.scanner.tokenStart > startOffset) {
endOffset = getOffsetExcludeWS.call(this);
} else {
endOffset = this.scanner.tokenStart;
}
return {
type: 'Raw',
loc: this.getLocation(startOffset, endOffset),
value: this.scanner.source.substring(startOffset, endOffset)
};
},
generate: function(node) {
this.chunk(node.value);
},
mode: {
default: balanceEnd,
leftCurlyBracket: leftCurlyBracket,
leftCurlyBracketOrSemicolon: leftCurlyBracketOrSemicolon,
exclamationMarkOrSemicolon: exclamationMarkOrSemicolon,
semicolonIncluded: semicolonIncluded
}
};

@@ -1,16 +0,13 @@

var TYPE = require('../../tokenizer').TYPE;
var rawMode = require('./Raw').mode;
import { LeftCurlyBracket } from '../../tokenizer/index.js';
var LEFTCURLYBRACKET = TYPE.LeftCurlyBracket;
function consumeRaw(startToken) {
return this.Raw(startToken, rawMode.leftCurlyBracket, true);
return this.Raw(startToken, this.consumeUntilLeftCurlyBracket, true);
}
function consumePrelude() {
var prelude = this.SelectorList();
const prelude = this.SelectorList();
if (prelude.type !== 'Raw' &&
this.scanner.eof === false &&
this.scanner.tokenType !== LEFTCURLYBRACKET) {
this.eof === false &&
this.tokenType !== LeftCurlyBracket) {
this.error();

@@ -22,34 +19,34 @@ }

module.exports = {
name: 'Rule',
structure: {
prelude: ['SelectorList', 'Raw'],
block: ['Block']
},
parse: function() {
var startToken = this.scanner.tokenIndex;
var startOffset = this.scanner.tokenStart;
var prelude;
var block;
export const name = 'Rule';
export const walkContext = 'rule';
export const structure = {
prelude: ['SelectorList', 'Raw'],
block: ['Block']
};
if (this.parseRulePrelude) {
prelude = this.parseWithFallback(consumePrelude, consumeRaw);
} else {
prelude = consumeRaw.call(this, startToken);
}
export function parse() {
const startToken = this.tokenIndex;
const startOffset = this.tokenStart;
let prelude;
let block;
block = this.Block(true);
if (this.parseRulePrelude) {
prelude = this.parseWithFallback(consumePrelude, consumeRaw);
} else {
prelude = consumeRaw.call(this, startToken);
}
return {
type: 'Rule',
loc: this.getLocation(startOffset, this.scanner.tokenStart),
prelude: prelude,
block: block
};
},
generate: function(node) {
this.node(node.prelude);
this.node(node.block);
},
walkContext: 'rule'
};
block = this.Block(true);
return {
type: 'Rule',
loc: this.getLocation(startOffset, this.tokenStart),
prelude,
block
};
}
export function generate(node) {
this.node(node.prelude);
this.node(node.block);
}

@@ -1,32 +0,32 @@

module.exports = {
name: 'Selector',
structure: {
children: [[
'TypeSelector',
'IdSelector',
'ClassSelector',
'AttributeSelector',
'PseudoClassSelector',
'PseudoElementSelector',
'Combinator',
'WhiteSpace'
]]
},
parse: function() {
var children = this.readSequence(this.scope.Selector);
export const name = 'Selector';
export const structure = {
children: [[
'TypeSelector',
'IdSelector',
'ClassSelector',
'AttributeSelector',
'PseudoClassSelector',
'PseudoElementSelector',
'Combinator',
'WhiteSpace'
]]
};
// nothing were consumed
if (this.getFirstListNode(children) === null) {
this.error('Selector is expected');
}
export function parse() {
const children = this.readSequence(this.scope.Selector);
return {
type: 'Selector',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node);
// nothing were consumed
if (this.getFirstListNode(children) === null) {
this.error('Selector is expected');
}
};
return {
type: 'Selector',
loc: this.getLocationFromList(children),
children
};
}
export function generate(node) {
this.children(node);
}

@@ -1,39 +0,35 @@

var TYPE = require('../../tokenizer').TYPE;
import { Comma } from '../../tokenizer/index.js';
var COMMA = TYPE.Comma;
export const name = 'SelectorList';
export const walkContext = 'selector';
export const structure = {
children: [[
'Selector',
'Raw'
]]
};
module.exports = {
name: 'SelectorList',
structure: {
children: [[
'Selector',
'Raw'
]]
},
parse: function() {
var children = this.createList();
export function parse() {
const children = this.createList();
while (!this.scanner.eof) {
children.push(this.Selector());
while (!this.eof) {
children.push(this.Selector());
if (this.scanner.tokenType === COMMA) {
this.scanner.next();
continue;
}
break;
if (this.tokenType === Comma) {
this.next();
continue;
}
return {
type: 'SelectorList',
loc: this.getLocationFromList(children),
children: children
};
},
generate: function(node) {
this.children(node, function() {
this.chunk(',');
});
},
walkContext: 'selector'
};
break;
}
return {
type: 'SelectorList',
loc: this.getLocationFromList(children),
children
};
}
export function generate(node) {
this.children(node, () => this.token(Comma, ','));
}

@@ -1,18 +0,19 @@

var STRING = require('../../tokenizer').TYPE.String;
import { String as StringToken } from '../../tokenizer/index.js';
import { decode, encode } from '../../utils/string.js';
module.exports = {
name: 'String',
structure: {
value: String
},
parse: function() {
return {
type: 'String',
loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd),
value: this.consume(STRING)
};
},
generate: function(node) {
this.chunk(node.value);
}
export const name = 'String';
export const structure = {
value: String
};
export function parse() {
return {
type: 'String',
loc: this.getLocation(this.tokenStart, this.tokenEnd),
value: decode(this.consume(StringToken))
};
}
export function generate(node) {
this.token(StringToken, encode(node.value));
}

@@ -1,9 +0,10 @@

var TYPE = require('../../tokenizer').TYPE;
import {
WhiteSpace,
Comment,
AtKeyword,
CDO,
CDC
} from '../../tokenizer/index.js';
var WHITESPACE = TYPE.WhiteSpace;
var COMMENT = TYPE.Comment;
var ATKEYWORD = TYPE.AtKeyword;
var CDO = TYPE.CDO;
var CDC = TYPE.CDC;
var EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)
const EXCLAMATIONMARK = 0x0021; // U+0021 EXCLAMATION MARK (!)

@@ -14,69 +15,69 @@ function consumeRaw(startToken) {

module.exports = {
name: 'StyleSheet',
structure: {
children: [[
'Comment',
'CDO',
'CDC',
'Atrule',
'Rule',
'Raw'
]]
},
parse: function() {
var start = this.scanner.tokenStart;
var children = this.createList();
var child;
export const name = 'StyleSheet';
export const walkContext = 'stylesheet';
export const structure = {
children: [[
'Comment',
'CDO',
'CDC',
'Atrule',
'Rule',
'Raw'
]]
};
scan:
while (!this.scanner.eof) {
switch (this.scanner.tokenType) {
case WHITESPACE:
this.scanner.next();
continue;
export function parse() {
const start = this.tokenStart;
const children = this.createList();
let child;
case COMMENT:
// ignore comments except exclamation comments (i.e. /*! .. */) on top level
if (this.scanner.source.charCodeAt(this.scanner.tokenStart + 2) !== EXCLAMATIONMARK) {
this.scanner.next();
continue;
}
scan:
while (!this.eof) {
switch (this.tokenType) {
case WhiteSpace:
this.next();
continue;
child = this.Comment();
break;
case Comment:
// ignore comments except exclamation comments (i.e. /*! .. */) on top level
if (this.charCodeAt(this.tokenStart + 2) !== EXCLAMATIONMARK) {
this.next();
continue;
}
case CDO: // <!--
child = this.CDO();
break;
child = this.Comment();
break;
case CDC: // -->
child = this.CDC();
break;
case CDO: // <!--
child = this.CDO();
break;
// CSS Syntax Module Level 3
// §2.2 Error handling
// At the "top level" of a stylesheet, an <at-keyword-token> starts an at-rule.
case ATKEYWORD:
child = this.parseWithFallback(this.Atrule, consumeRaw);
break;
case CDC: // -->
child = this.CDC();
break;
// Anything else starts a qualified rule ...
default:
child = this.parseWithFallback(this.Rule, consumeRaw);
}
// CSS Syntax Module Level 3
// §2.2 Error handling
// At the "top level" of a stylesheet, an <at-keyword-token> starts an at-rule.
case AtKeyword:
child = this.parseWithFallback(this.Atrule, consumeRaw);
break;
children.push(child);
// Anything else starts a qualified rule ...
default:
child = this.parseWithFallback(this.Rule, consumeRaw);
}
return {
type: 'StyleSheet',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
},
generate: function(node) {
this.children(node);
},
walkContext: 'stylesheet'
};
children.push(child);
}
return {
type: 'StyleSheet',
loc: this.getLocation(start, this.tokenStart),
children
};
}
export function generate(node) {
this.children(node);
}

@@ -1,16 +0,20 @@

var TYPE = require('../../tokenizer').TYPE;
import { Ident } from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
function eatIdentifierOrAsterisk() {
if (this.scanner.tokenType !== IDENT &&
this.scanner.isDelim(ASTERISK) === false) {
if (this.tokenType !== Ident &&
this.isDelim(ASTERISK) === false) {
this.error('Identifier or asterisk is expected');
}
this.scanner.next();
this.next();
}
export const name = 'TypeSelector';
export const structure = {
name: String
};
// ident

@@ -24,31 +28,26 @@ // ident|ident

// |*
module.exports = {
name: 'TypeSelector',
structure: {
name: String
},
parse: function() {
var start = this.scanner.tokenStart;
export function parse() {
const start = this.tokenStart;
if (this.scanner.isDelim(VERTICALLINE)) {
this.scanner.next();
if (this.isDelim(VERTICALLINE)) {
this.next();
eatIdentifierOrAsterisk.call(this);
} else {
eatIdentifierOrAsterisk.call(this);
if (this.isDelim(VERTICALLINE)) {
this.next();
eatIdentifierOrAsterisk.call(this);
} else {
eatIdentifierOrAsterisk.call(this);
if (this.scanner.isDelim(VERTICALLINE)) {
this.scanner.next();
eatIdentifierOrAsterisk.call(this);
}
}
}
return {
type: 'TypeSelector',
loc: this.getLocation(start, this.scanner.tokenStart),
name: this.scanner.substrToCursor(start)
};
},
generate: function(node) {
this.chunk(node.name);
}
};
return {
type: 'TypeSelector',
loc: this.getLocation(start, this.tokenStart),
name: this.substrToCursor(start)
};
}
export function generate(node) {
this.tokenize(node.name);
}

@@ -1,23 +0,20 @@

var isHexDigit = require('../../tokenizer').isHexDigit;
var cmpChar = require('../../tokenizer').cmpChar;
var TYPE = require('../../tokenizer').TYPE;
var NAME = require('../../tokenizer').NAME;
import {
isHexDigit,
Ident,
Number,
Dimension
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var NUMBER = TYPE.Number;
var DIMENSION = TYPE.Dimension;
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
var QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
const QUESTIONMARK = 0x003F; // U+003F QUESTION MARK (?)
function eatHexSequence(offset, allowDash) {
for (var pos = this.scanner.tokenStart + offset, len = 0; pos < this.scanner.tokenEnd; pos++) {
var code = this.scanner.source.charCodeAt(pos);
let len = 0;
for (let pos = this.tokenStart + offset; pos < this.tokenEnd; pos++) {
const code = this.charCodeAt(pos);
if (code === HYPHENMINUS && allowDash && len !== 0) {
if (eatHexSequence.call(this, offset + len + 1, false) === 0) {
this.error();
}
eatHexSequence.call(this, offset + len + 1, false);
return -1;

@@ -29,3 +26,3 @@ }

allowDash && len !== 0
? 'HyphenMinus' + (len < 6 ? ' or hex digit' : '') + ' is expected'
? 'Hyphen minus' + (len < 6 ? ' or hex digit' : '') + ' is expected'
: (len < 6 ? 'Hex digit is expected' : 'Unexpected input'),

@@ -41,3 +38,3 @@ pos

this.scanner.next();
this.next();
return len;

@@ -47,5 +44,5 @@ }

function eatQuestionMarkSequence(max) {
var count = 0;
let count = 0;
while (this.scanner.isDelim(QUESTIONMARK)) {
while (this.isDelim(QUESTIONMARK)) {
if (++count > max) {

@@ -55,3 +52,3 @@ this.error('Too many question marks');

this.scanner.next();
this.next();
}

@@ -61,4 +58,4 @@ }

function startsWith(code) {
if (this.scanner.source.charCodeAt(this.scanner.tokenStart) !== code) {
this.error(NAME[code] + ' is expected');
if (this.charCodeAt(this.tokenStart) !== code) {
this.error((code === PLUSSIGN ? 'Plus sign' : 'Hyphen minus') + ' is expected');
}

@@ -87,93 +84,79 @@ }

function scanUnicodeRange() {
var hexLength = 0;
let hexLength = 0;
// u '+' <ident-token> '?'*
// u '+' '?'+
if (this.scanner.isDelim(PLUSSIGN)) {
this.scanner.next();
switch (this.tokenType) {
case Number:
// u <number-token> '?'*
// u <number-token> <dimension-token>
// u <number-token> <number-token>
hexLength = eatHexSequence.call(this, 1, true);
if (this.scanner.tokenType === IDENT) {
hexLength = eatHexSequence.call(this, 0, true);
if (hexLength > 0) {
if (this.isDelim(QUESTIONMARK)) {
eatQuestionMarkSequence.call(this, 6 - hexLength);
break;
}
return;
}
if (this.scanner.isDelim(QUESTIONMARK)) {
this.scanner.next();
eatQuestionMarkSequence.call(this, 5);
return;
}
if (this.tokenType === Dimension ||
this.tokenType === Number) {
startsWith.call(this, HYPHENMINUS);
eatHexSequence.call(this, 1, false);
break;
}
this.error('Hex digit or question mark is expected');
return;
}
break;
// u <number-token> '?'*
// u <number-token> <dimension-token>
// u <number-token> <number-token>
if (this.scanner.tokenType === NUMBER) {
startsWith.call(this, PLUSSIGN);
hexLength = eatHexSequence.call(this, 1, true);
case Dimension:
// u <dimension-token> '?'*
hexLength = eatHexSequence.call(this, 1, true);
if (this.scanner.isDelim(QUESTIONMARK)) {
eatQuestionMarkSequence.call(this, 6 - hexLength);
return;
}
if (hexLength > 0) {
eatQuestionMarkSequence.call(this, 6 - hexLength);
}
if (this.scanner.tokenType === DIMENSION ||
this.scanner.tokenType === NUMBER) {
startsWith.call(this, HYPHENMINUS);
eatHexSequence.call(this, 1, false);
return;
}
break;
return;
}
default:
// u '+' <ident-token> '?'*
// u '+' '?'+
this.eatDelim(PLUSSIGN);
// u <dimension-token> '?'*
if (this.scanner.tokenType === DIMENSION) {
startsWith.call(this, PLUSSIGN);
hexLength = eatHexSequence.call(this, 1, true);
if (this.tokenType === Ident) {
hexLength = eatHexSequence.call(this, 0, true);
if (hexLength > 0) {
eatQuestionMarkSequence.call(this, 6 - hexLength);
}
break;
}
if (hexLength > 0) {
eatQuestionMarkSequence.call(this, 6 - hexLength);
}
if (this.isDelim(QUESTIONMARK)) {
this.next();
eatQuestionMarkSequence.call(this, 5);
break;
}
return;
this.error('Hex digit or question mark is expected');
}
this.error();
}
module.exports = {
name: 'UnicodeRange',
structure: {
value: String
},
parse: function() {
var start = this.scanner.tokenStart;
export const name = 'UnicodeRange';
export const structure = {
value: String
};
// U or u
if (!cmpChar(this.scanner.source, start, U)) {
this.error('U is expected');
}
export function parse() {
const start = this.tokenStart;
if (!cmpChar(this.scanner.source, start + 1, PLUSSIGN)) {
this.error('Plus sign is expected');
}
// U or u
this.eatIdent('u');
scanUnicodeRange.call(this);
this.scanner.next();
scanUnicodeRange.call(this);
return {
type: 'UnicodeRange',
loc: this.getLocation(start, this.tokenStart),
value: this.substrToCursor(start)
};
}
return {
type: 'UnicodeRange',
loc: this.getLocation(start, this.scanner.tokenStart),
value: this.scanner.substrToCursor(start)
};
},
generate: function(node) {
this.chunk(node.value);
}
};
export function generate(node) {
this.tokenize(node.value);
}

@@ -1,69 +0,52 @@

var isWhiteSpace = require('../../tokenizer').isWhiteSpace;
var cmpStr = require('../../tokenizer').cmpStr;
var TYPE = require('../../tokenizer').TYPE;
import * as url from '../../utils/url.js';
import * as string from '../../utils/string.js';
import {
Function as FunctionToken,
String as StringToken,
Url,
RightParenthesis
} from '../../tokenizer/index.js';
var FUNCTION = TYPE.Function;
var URL = TYPE.Url;
var RIGHTPARENTHESIS = TYPE.RightParenthesis;
export const name = 'Url';
export const structure = {
value: String
};
// <url-token> | <function-token> <string> )
module.exports = {
name: 'Url',
structure: {
value: ['String', 'Raw']
},
parse: function() {
var start = this.scanner.tokenStart;
var value;
export function parse() {
const start = this.tokenStart;
let value;
switch (this.scanner.tokenType) {
case URL:
var rawStart = start + 4;
var rawEnd = this.scanner.tokenEnd - 1;
switch (this.tokenType) {
case Url:
value = url.decode(this.consume(Url));
break;
while (rawStart < rawEnd && isWhiteSpace(this.scanner.source.charCodeAt(rawStart))) {
rawStart++;
}
case FunctionToken:
if (!this.cmpStr(this.tokenStart, this.tokenEnd, 'url(')) {
this.error('Function name must be `url`');
}
while (rawStart < rawEnd && isWhiteSpace(this.scanner.source.charCodeAt(rawEnd - 1))) {
rawEnd--;
}
this.eat(FunctionToken);
this.skipSC();
value = string.decode(this.consume(StringToken));
this.skipSC();
if (!this.eof) {
this.eat(RightParenthesis);
}
break;
value = {
type: 'Raw',
loc: this.getLocation(rawStart, rawEnd),
value: this.scanner.source.substring(rawStart, rawEnd)
};
default:
this.error('Url or Function is expected');
}
this.eat(URL);
break;
return {
type: 'Url',
loc: this.getLocation(start, this.tokenStart),
value
};
}
case FUNCTION:
if (!cmpStr(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(')) {
this.error('Function name must be `url`');
}
this.eat(FUNCTION);
this.scanner.skipSC();
value = this.String();
this.scanner.skipSC();
this.eat(RIGHTPARENTHESIS);
break;
default:
this.error('Url or Function is expected');
}
return {
type: 'Url',
loc: this.getLocation(start, this.scanner.tokenStart),
value: value
};
},
generate: function(node) {
this.chunk('url');
this.chunk('(');
this.node(node.value);
this.chunk(')');
}
};
export function generate(node) {
this.token(Url, url.encode(node.value));
}

@@ -1,19 +0,19 @@

module.exports = {
name: 'Value',
structure: {
children: [[]]
},
parse: function() {
var start = this.scanner.tokenStart;
var children = this.readSequence(this.scope.Value);
export const name = 'Value';
export const structure = {
children: [[]]
};
return {
type: 'Value',
loc: this.getLocation(start, this.scanner.tokenStart),
children: children
};
},
generate: function(node) {
this.children(node);
}
};
export function parse() {
const start = this.tokenStart;
const children = this.readSequence(this.scope.Value);
return {
type: 'Value',
loc: this.getLocation(start, this.tokenStart),
children
};
}
export function generate(node) {
this.children(node);
}

@@ -1,3 +0,4 @@

var WHITESPACE = require('../../tokenizer').TYPE.WhiteSpace;
var SPACE = Object.freeze({
import { WhiteSpace } from '../../tokenizer/index.js';
const SPACE = Object.freeze({
type: 'WhiteSpace',

@@ -8,20 +9,20 @@ loc: null,

module.exports = {
name: 'WhiteSpace',
structure: {
value: String
},
parse: function() {
this.eat(WHITESPACE);
return SPACE;
export const name = 'WhiteSpace';
export const structure = {
value: String
};
// return {
// type: 'WhiteSpace',
// loc: this.getLocation(this.scanner.tokenStart, this.scanner.tokenEnd),
// value: this.consume(WHITESPACE)
// };
},
generate: function(node) {
this.chunk(node.value);
}
};
export function parse() {
this.eat(WhiteSpace);
return SPACE;
// return {
// type: 'WhiteSpace',
// loc: this.getLocation(this.tokenStart, this.tokenEnd),
// value: this.consume(WHITESPACE)
// };
}
export function generate(node) {
this.token(WhiteSpace, node.value);
}

@@ -1,12 +0,44 @@

module.exports = {
'dir': require('./dir'),
'has': require('./has'),
'lang': require('./lang'),
'matches': require('./matches'),
'not': require('./not'),
'nth-child': require('./nth-child'),
'nth-last-child': require('./nth-last-child'),
'nth-last-of-type': require('./nth-last-of-type'),
'nth-of-type': require('./nth-of-type'),
'slotted': require('./slotted')
const selectorList = {
parse() {
return this.createSingleNodeList(
this.SelectorList()
);
}
};
const selector = {
parse() {
return this.createSingleNodeList(
this.Selector()
);
}
};
const identList = {
parse() {
return this.createSingleNodeList(
this.Identifier()
);
}
};
const nth = {
parse() {
return this.createSingleNodeList(
this.Nth()
);
}
};
export default {
'dir': identList,
'has': selectorList,
'lang': identList,
'matches': selectorList,
'not': selectorList,
'nth-child': nth,
'nth-last-child': nth,
'nth-last-of-type': nth,
'nth-of-type': nth,
'slotted': selector
};

@@ -1,3 +0,5 @@

module.exports = {
getNode: require('./default')
import getNode from './default.js';
export default {
getNode
};

@@ -1,64 +0,61 @@

var cmpChar = require('../../tokenizer').cmpChar;
var cmpStr = require('../../tokenizer').cmpStr;
var TYPE = require('../../tokenizer').TYPE;
import {
Ident,
String as StringToken,
Number as NumberToken,
Function as FunctionToken,
Url,
Hash,
Dimension,
Percentage,
LeftParenthesis,
LeftSquareBracket,
Comma,
Delim
} from '../../tokenizer/index.js';
var IDENT = TYPE.Ident;
var STRING = TYPE.String;
var NUMBER = TYPE.Number;
var FUNCTION = TYPE.Function;
var URL = TYPE.Url;
var HASH = TYPE.Hash;
var DIMENSION = TYPE.Dimension;
var PERCENTAGE = TYPE.Percentage;
var LEFTPARENTHESIS = TYPE.LeftParenthesis;
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;
var COMMA = TYPE.Comma;
var DELIM = TYPE.Delim;
var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
var U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
const NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const U = 0x0075; // U+0075 LATIN SMALL LETTER U (u)
module.exports = function defaultRecognizer(context) {
switch (this.scanner.tokenType) {
case HASH:
export default function defaultRecognizer(context) {
switch (this.tokenType) {
case Hash:
return this.Hash();
case COMMA:
context.space = null;
context.ignoreWSAfter = true;
case Comma:
return this.Operator();
case LEFTPARENTHESIS:
case LeftParenthesis:
return this.Parentheses(this.readSequence, context.recognizer);
case LEFTSQUAREBRACKET:
case LeftSquareBracket:
return this.Brackets(this.readSequence, context.recognizer);
case STRING:
case StringToken:
return this.String();
case DIMENSION:
case Dimension:
return this.Dimension();
case PERCENTAGE:
case Percentage:
return this.Percentage();
case NUMBER:
case NumberToken:
return this.Number();
case FUNCTION:
return cmpStr(this.scanner.source, this.scanner.tokenStart, this.scanner.tokenEnd, 'url(')
case FunctionToken:
return this.cmpStr(this.tokenStart, this.tokenEnd, 'url(')
? this.Url()
: this.Function(this.readSequence, context.recognizer);
case URL:
case Url:
return this.Url();
case IDENT:
case Ident:
// check for unicode range, it should start with u+ or U+
if (cmpChar(this.scanner.source, this.scanner.tokenStart, U) &&
cmpChar(this.scanner.source, this.scanner.tokenStart + 1, PLUSSIGN)) {
if (this.cmpChar(this.tokenStart, U) &&
this.cmpChar(this.tokenStart + 1, PLUSSIGN)) {
return this.UnicodeRange();

@@ -69,4 +66,4 @@ } else {

case DELIM:
var code = this.scanner.source.charCodeAt(this.scanner.tokenStart);
case Delim: {
const code = this.charCodeAt(this.tokenStart);

@@ -83,7 +80,8 @@ if (code === SOLIDUS ||

if (code === NUMBERSIGN) {
this.error('Hex or identifier is expected', this.scanner.tokenStart + 1);
this.error('Hex or identifier is expected', this.tokenStart + 1);
}
break;
}
}
};

@@ -1,5 +0,3 @@

module.exports = {
AtrulePrelude: require('./atrulePrelude'),
Selector: require('./selector'),
Value: require('./value')
};
export { default as AtrulePrelude } from './atrulePrelude.js';
export { default as Selector } from './selector.js';
export { default as Value } from './value.js';

@@ -1,30 +0,42 @@

var TYPE = require('../../tokenizer').TYPE;
import {
Delim,
Ident,
Dimension,
Percentage,
Number as NumberToken,
Hash,
Colon,
LeftSquareBracket
} from '../../tokenizer/index.js';
var DELIM = TYPE.Delim;
var IDENT = TYPE.Ident;
var DIMENSION = TYPE.Dimension;
var PERCENTAGE = TYPE.Percentage;
var NUMBER = TYPE.Number;
var HASH = TYPE.Hash;
var COLON = TYPE.Colon;
var LEFTSQUAREBRACKET = TYPE.LeftSquareBracket;
var NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
var ASTERISK = 0x002A; // U+002A ASTERISK (*)
var PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
var SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
var FULLSTOP = 0x002E; // U+002E FULL STOP (.)
var GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
var VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
var TILDE = 0x007E; // U+007E TILDE (~)
const NUMBERSIGN = 0x0023; // U+0023 NUMBER SIGN (#)
const ASTERISK = 0x002A; // U+002A ASTERISK (*)
const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+)
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const FULLSTOP = 0x002E; // U+002E FULL STOP (.)
const GREATERTHANSIGN = 0x003E; // U+003E GREATER-THAN SIGN (>)
const VERTICALLINE = 0x007C; // U+007C VERTICAL LINE (|)
const TILDE = 0x007E; // U+007E TILDE (~)
function getNode(context) {
switch (this.scanner.tokenType) {
case LEFTSQUAREBRACKET:
function onWhiteSpace(next, children) {
if (children.last !== null && children.last.type !== 'Combinator' &&
next !== null && next.type !== 'Combinator') {
children.push({ // FIXME: this.Combinator() should be used instead
type: 'Combinator',
loc: null,
name: ' '
});
}
}
function getNode() {
switch (this.tokenType) {
case LeftSquareBracket:
return this.AttributeSelector();
case HASH:
case Hash:
return this.IdSelector();
case COLON:
if (this.scanner.lookupType(1) === COLON) {
case Colon:
if (this.lookupType(1) === Colon) {
return this.PseudoElementSelector();

@@ -35,18 +47,18 @@ } else {

case IDENT:
case Ident:
return this.TypeSelector();
case NUMBER:
case PERCENTAGE:
case NumberToken:
case Percentage:
return this.Percentage();
case DIMENSION:
case Dimension:
// throws when .123ident
if (this.scanner.source.charCodeAt(this.scanner.tokenStart) === FULLSTOP) {
this.error('Identifier is expected', this.scanner.tokenStart + 1);
if (this.charCodeAt(this.tokenStart) === FULLSTOP) {
this.error('Identifier is expected', this.tokenStart + 1);
}
break;
case DELIM:
var code = this.scanner.source.charCodeAt(this.scanner.tokenStart);
case Delim: {
const code = this.charCodeAt(this.tokenStart);

@@ -57,6 +69,2 @@ switch (code) {

case TILDE:
context.space = null;
context.ignoreWSAfter = true;
return this.Combinator();
case SOLIDUS: // /deep/

@@ -77,7 +85,9 @@ return this.Combinator();

break;
}
}
};
module.exports = {
getNode: getNode
export default {
onWhiteSpace,
getNode
};

@@ -1,5 +0,25 @@

module.exports = {
getNode: require('./default'),
'expression': require('../function/expression'),
'var': require('../function/var')
import getNode from './default.js';
import expressionFn from '../function/expression.js';
import varFn from '../function/var.js';
function isPlusMinusOperator(node) {
return (
node !== null &&
node.type === 'Operator' &&
(node.value[node.value.length - 1] === '-' || node.value[node.value.length - 1] === '+')
);
}
export default {
getNode,
onWhiteSpace: function(next, children) {
if (isPlusMinusOperator(next)) {
next.value = ' ' + next.value;
}
if (isPlusMinusOperator(children.last)) {
children.last.value += ' ';
}
},
'expression': expressionFn,
'var': varFn
};

@@ -1,2 +0,2 @@

var EOF = 0;
const EOF = 0;

@@ -8,3 +8,3 @@ // https://drafts.csswg.org/css-syntax-3/

// 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;

@@ -16,3 +16,3 @@ }

// 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 (

@@ -27,3 +27,3 @@ isDigit(code) || // 0 .. 9

// 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;

@@ -34,3 +34,3 @@ }

// 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;

@@ -41,3 +41,3 @@ }

// An uppercase letter or a lowercase letter.
function isLetter(code) {
export function isLetter(code) {
return isUppercaseLetter(code) || isLowercaseLetter(code);

@@ -48,3 +48,3 @@ }

// A code point with a value equal to or greater than U+0080 <control>.
function isNonAscii(code) {
export function isNonAscii(code) {
return code >= 0x0080;

@@ -55,3 +55,3 @@ }

// 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;

@@ -62,3 +62,3 @@ }

// 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;

@@ -70,3 +70,3 @@ }

// 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 (

@@ -84,3 +84,3 @@ (code >= 0x0000 && code <= 0x0008) ||

// 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;

@@ -91,3 +91,3 @@ }

// A newline, U+0009 CHARACTER TABULATION, or U+0020 SPACE.
function isWhiteSpace(code) {
export function isWhiteSpace(code) {
return isNewline(code) || code === 0x0020 || code === 0x0009;

@@ -97,3 +97,3 @@ }

// § 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.

@@ -114,3 +114,3 @@ if (first !== 0x005C) {

// § 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:

@@ -147,3 +147,3 @@

// § 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:

@@ -187,3 +187,3 @@

// detect BOM (https://en.wikipedia.org/wiki/Byte_order_mark)
function isBOM(code) {
export function isBOM(code) {
// UTF-16BE

@@ -203,63 +203,21 @@ if (code === 0xFEFF) {

// 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;
for (let i = 0; i < CATEGORY.length; i++) {
CATEGORY[i] =
isWhiteSpace(i) && WhiteSpaceCategory ||
isDigit(i) && DigitCategory ||
isNameStart(i) && NameStartCategory ||
isNonPrintable(i) && NonPrintableCategory ||
i || EofCategory;
}
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;
}
export function charCodeCategory(code) {
return code < 0x80 ? CATEGORY[code] : NameStartCategory;
}
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
};

@@ -1,29 +0,26 @@

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) {

@@ -114,3 +111,3 @@ return offset < sourceLength ? source.charCodeAt(offset) : 0;

for (; offset < source.length; offset++) {
var code = source.charCodeAt(offset);
const code = source.charCodeAt(offset);

@@ -124,9 +121,9 @@ switch (charCodeCategory(code)) {

// 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)) {

@@ -148,3 +145,3 @@ // This is a parse error. Reconsume the current input code point,

var nextCode = getCharCode(offset + 1);
const nextCode = getCharCode(offset + 1);

@@ -182,3 +179,3 @@ // Otherwise, if the next input code point is a newline, consume it.

for (; offset < source.length; offset++) {
var code = source.charCodeAt(offset);
const code = source.charCodeAt(offset);

@@ -192,9 +189,9 @@ switch (charCodeCategory(code)) {

// 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.

@@ -226,3 +223,3 @@ offset = findWhiteSpaceEnd(source, offset);

case 0x0028:
case charCodeCategory.NonPrintable:
case NonPrintableCategory:
// This is a parse error. Consume the remnants of a bad url,

@@ -255,18 +252,9 @@ // create a <bad-url-token>, and return it.

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;

@@ -276,10 +264,7 @@ // https://drafts.csswg.org/css-syntax-3/#consume-token

while (offset < sourceLength) {
var code = source.charCodeAt(offset);
var type = 0;
const code = source.charCodeAt(offset);
balance[tokenCount] = sourceLength;
switch (charCodeCategory(code)) {
// whitespace
case charCodeCategory.WhiteSpace:
case WhiteSpaceCategory:
// Consume as much whitespace as possible. Return a <whitespace-token>.

@@ -406,6 +391,4 @@ type = TYPE.WhiteSpace;

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 {

@@ -505,3 +488,3 @@ type = TYPE.Delim;

// digit
case charCodeCategory.Digit:
case DigitCategory:
// Reconsume the current input code point, consume a numeric token, and return it.

@@ -512,3 +495,3 @@ consumeNumericToken();

// name-start code point
case charCodeCategory.NameStart:
case NameStartCategory:
// Reconsume the current input code point, consume an ident-like token, and return it.

@@ -518,6 +501,6 @@ consumeIdentLikeToken();

// EOF
case charCodeCategory.Eof:
// EOF
// case EofCategory:
// Return an <EOF-token>.
break;
// break;

@@ -531,74 +514,13 @@ // anything else

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';

@@ -1,8 +0,9 @@

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';

@@ -13,3 +14,3 @@ function getCharCode(source, offset) {

function getNewlineLength(source, offset, code) {
export function getNewlineLength(source, offset, code) {
if (code === 13 /* \r */ && getCharCode(source, offset + 1) === 10 /* \n */) {

@@ -22,4 +23,4 @@ return 2;

function cmpChar(testStr, offset, referenceCode) {
var code = testStr.charCodeAt(offset);
export function cmpChar(testStr, offset, referenceCode) {
let code = testStr.charCodeAt(offset);

@@ -34,3 +35,3 @@ // code.toLowerCase() for A..Z

function cmpStr(testStr, start, end, referenceStr) {
export function cmpStr(testStr, start, end, referenceStr) {
if (end - start !== referenceStr.length) {

@@ -44,5 +45,5 @@ 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);

@@ -62,3 +63,3 @@ // testCode.toLowerCase() for A..Z

function findWhiteSpaceStart(source, offset) {
export function findWhiteSpaceStart(source, offset) {
for (; offset >= 0; offset--) {

@@ -73,3 +74,3 @@ if (!isWhiteSpace(source.charCodeAt(offset))) {

function findWhiteSpaceEnd(source, offset) {
export function findWhiteSpaceEnd(source, offset) {
for (; offset < source.length; offset++) {

@@ -84,3 +85,3 @@ if (!isWhiteSpace(source.charCodeAt(offset))) {

function findDecimalNumberEnd(source, offset) {
export function findDecimalNumberEnd(source, offset) {
for (; offset < source.length; offset++) {

@@ -96,3 +97,3 @@ if (!isDigit(source.charCodeAt(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

@@ -106,3 +107,3 @@ // that the next input code point has already been verified to be part of a valid escape.

// 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))) {

@@ -114,3 +115,3 @@ 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)) {

@@ -128,7 +129,7 @@ offset += getNewlineLength(source, offset, code);

// 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);

@@ -157,4 +158,4 @@ // name code point

// §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);

@@ -177,3 +178,3 @@ // 2. If the next input code point is U+002B PLUS SIGN (+) or U+002D HYPHEN-MINUS (-),

// 4.2 Append them to repr.
code = source.charCodeAt(offset += 2);
offset += 2;

@@ -191,3 +192,3 @@ // 4.3 Set type to "number".

if (cmpChar(source, offset, 101 /* e */)) {
var sign = 0;
let sign = 0;
code = source.charCodeAt(offset + 1);

@@ -220,6 +221,6 @@

// 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);

@@ -246,14 +247,24 @@ // U+0029 RIGHT PARENTHESIS ())

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);
}

@@ -1,8 +0,8 @@

var List = require('../common/List');
import { List } from './List.js';
module.exports = function clone(node) {
var result = {};
export function clone(node) {
const result = {};
for (var key in node) {
var value = node[key];
for (const key in node) {
let value = node[key];

@@ -21,2 +21,2 @@ if (value) {

return result;
};
}

@@ -1,7 +0,9 @@

var hasOwnProperty = Object.prototype.hasOwnProperty;
var keywords = Object.create(null);
var properties = Object.create(null);
var HYPHENMINUS = 45; // '-'.charCodeAt()
const keywords = new Map();
const properties = new Map();
const HYPHENMINUS = 45; // '-'.charCodeAt()
function isCustomProperty(str, offset) {
export const keyword = getKeywordDescriptor;
export const property = getPropertyDescriptor;
export const vendorPrefix = getVendorPrefix;
export function isCustomProperty(str, offset) {
offset = offset || 0;

@@ -23,3 +25,3 @@

// vendor prefix should contain a hyper minus at the ending
var secondDashIndex = str.indexOf('-', offset + 2);
const secondDashIndex = str.indexOf('-', offset + 2);

@@ -36,31 +38,33 @@ if (secondDashIndex !== -1) {

function getKeywordDescriptor(keyword) {
if (hasOwnProperty.call(keywords, keyword)) {
return keywords[keyword];
if (keywords.has(keyword)) {
return keywords.get(keyword);
}
var name = keyword.toLowerCase();
const name = keyword.toLowerCase();
let descriptor = keywords.get(name);
if (hasOwnProperty.call(keywords, name)) {
return keywords[keyword] = keywords[name];
if (descriptor === undefined) {
const custom = isCustomProperty(name, 0);
const vendor = !custom ? getVendorPrefix(name, 0) : '';
descriptor = Object.freeze({
basename: name.substr(vendor.length),
name,
prefix: vendor,
vendor,
custom
});
}
var custom = isCustomProperty(name, 0);
var vendor = !custom ? getVendorPrefix(name, 0) : '';
keywords.set(keyword, descriptor);
return keywords[keyword] = Object.freeze({
basename: name.substr(vendor.length),
name: name,
vendor: vendor,
prefix: vendor,
custom: custom
});
return descriptor;
}
function getPropertyDescriptor(property) {
if (hasOwnProperty.call(properties, property)) {
return properties[property];
if (properties.has(property)) {
return properties.get(property);
}
var name = property;
var hack = property[0];
let name = property;
let hack = property[0];

@@ -78,3 +82,3 @@ if (hack === '/') {

var custom = isCustomProperty(name, hack.length);
const custom = isCustomProperty(name, hack.length);

@@ -84,25 +88,23 @@ // re-use result when possible (the same as for lower case)

name = name.toLowerCase();
if (hasOwnProperty.call(properties, name)) {
return properties[property] = properties[name];
if (properties.has(name)) {
const descriptor = properties.get(name);
properties.set(property, descriptor);
return descriptor;
}
}
var vendor = !custom ? getVendorPrefix(name, hack.length) : '';
var prefix = name.substr(0, hack.length + vendor.length);
return properties[property] = Object.freeze({
const vendor = !custom ? getVendorPrefix(name, hack.length) : '';
const prefix = name.substr(0, hack.length + vendor.length);
const descriptor = Object.freeze({
basename: name.substr(prefix.length),
name: name.substr(hack.length),
hack: hack,
vendor: vendor,
prefix: prefix,
custom: custom
hack,
vendor,
prefix,
custom
});
properties.set(property, descriptor);
return descriptor;
}
module.exports = {
keyword: getKeywordDescriptor,
property: getPropertyDescriptor,
isCustomProperty: isCustomProperty,
vendorPrefix: getVendorPrefix
};

@@ -1,3 +0,3 @@

var hasOwnProperty = Object.prototype.hasOwnProperty;
var noop = function() {};
const { hasOwnProperty } = Object.prototype;
const noop = function() {};

@@ -17,6 +17,6 @@ function ensureFunction(value) {

function getWalkersFromStructure(name, nodeType) {
var structure = nodeType.structure;
var walkers = [];
const structure = nodeType.structure;
const walkers = [];
for (var key in structure) {
for (const key in structure) {
if (hasOwnProperty.call(structure, key) === false) {

@@ -26,4 +26,4 @@ continue;

var fieldTypes = structure[key];
var walker = {
let fieldTypes = structure[key];
const walker = {
name: key,

@@ -34,8 +34,7 @@ type: false,

if (!Array.isArray(structure[key])) {
fieldTypes = [structure[key]];
if (!Array.isArray(fieldTypes)) {
fieldTypes = [fieldTypes];
}
for (var i = 0; i < fieldTypes.length; i++) {
var fieldType = fieldTypes[i];
for (const fieldType of fieldTypes) {
if (fieldType === null) {

@@ -66,7 +65,7 @@ walker.nullable = true;

function getTypesFromConfig(config) {
var types = {};
const types = {};
for (var name in config.node) {
for (const name in config.node) {
if (hasOwnProperty.call(config.node, name)) {
var nodeType = config.node[name];
const nodeType = config.node[name];

@@ -85,5 +84,5 @@ if (!nodeType.structure) {

function createTypeIterator(config, reverse) {
var fields = config.fields.slice();
var contextName = config.context;
var useContext = typeof contextName === 'string';
const fields = config.fields.slice();
const contextName = config.context;
const useContext = typeof contextName === 'string';

@@ -95,3 +94,3 @@ if (reverse) {

return function(node, context, walk, walkReducer) {
var prevContextValue;
let prevContextValue;

@@ -103,5 +102,4 @@ if (useContext) {

for (var i = 0; i < fields.length; i++) {
var field = fields[i];
var ref = node[field.name];
for (const field of fields) {
const ref = node[field.name];

@@ -129,22 +127,28 @@ if (!field.nullable || ref) {

function createFastTraveralMap(iterators) {
function createFastTraveralMap({
StyleSheet,
Atrule,
Rule,
Block,
DeclarationList
}) {
return {
Atrule: {
StyleSheet: iterators.StyleSheet,
Atrule: iterators.Atrule,
Rule: iterators.Rule,
Block: iterators.Block
StyleSheet,
Atrule,
Rule,
Block
},
Rule: {
StyleSheet: iterators.StyleSheet,
Atrule: iterators.Atrule,
Rule: iterators.Rule,
Block: iterators.Block
StyleSheet,
Atrule,
Rule,
Block
},
Declaration: {
StyleSheet: iterators.StyleSheet,
Atrule: iterators.Atrule,
Rule: iterators.Rule,
Block: iterators.Block,
DeclarationList: iterators.DeclarationList
StyleSheet,
Atrule,
Rule,
Block,
DeclarationList
}

@@ -154,10 +158,10 @@ };

module.exports = function createWalker(config) {
var types = getTypesFromConfig(config);
var iteratorsNatural = {};
var iteratorsReverse = {};
var breakWalk = Symbol('break-walk');
var skipNode = Symbol('skip-node');
export function createWalker(config) {
const types = getTypesFromConfig(config);
const iteratorsNatural = {};
const iteratorsReverse = {};
const breakWalk = Symbol('break-walk');
const skipNode = Symbol('skip-node');
for (var name in types) {
for (const name in types) {
if (hasOwnProperty.call(types, name) && types[name] !== null) {

@@ -169,6 +173,6 @@ iteratorsNatural[name] = createTypeIterator(types[name], false);

var fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural);
var fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse);
const fastTraversalIteratorsNatural = createFastTraveralMap(iteratorsNatural);
const fastTraversalIteratorsReverse = createFastTraveralMap(iteratorsReverse);
var walk = function(root, options) {
const walk = function(root, options) {
function walkNode(node, item, list) {

@@ -178,3 +182,2 @@ var enterRet = enter.call(context, node, item, list);

if (enterRet === breakWalk) {
debugger;
return true;

@@ -200,11 +203,11 @@ }

var walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list);
var enter = noop;
var leave = noop;
var iterators = iteratorsNatural;
var context = {
let enter = noop;
let leave = noop;
let iterators = iteratorsNatural;
let walkReducer = (ret, data, item, list) => ret || walkNode(data, item, list);
const context = {
break: breakWalk,
skip: skipNode,
root: root,
root,
stylesheet: null,

@@ -236,3 +239,3 @@ atrule: null,

} else if (!types.hasOwnProperty(options.visit)) {
throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).join(', ') + ')');
throw new Error('Bad value `' + options.visit + '` for `visit` option (should be: ' + Object.keys(types).sort().join(', ') + ')');
}

@@ -256,3 +259,3 @@

walk.find = function(ast, fn) {
var found = null;
let found = null;

@@ -270,3 +273,3 @@ walk(ast, function(node, item, list) {

walk.findLast = function(ast, fn) {
var found = null;
let found = null;

@@ -287,3 +290,3 @@ walk(ast, {

walk.findAll = function(ast, fn) {
var found = [];
const found = [];

@@ -290,0 +293,0 @@ walk(ast, function(node, item, list) {

@@ -1,4 +0,4 @@

var createWalker = require('./create');
var config = require('../syntax/config/walker');
import { createWalker } from './create.js';
import config from '../syntax/config/walker.js';
module.exports = createWalker(config);
export default createWalker(config);
{
"name": "css-tree",
"version": "1.1.3",
"version": "2.0.0",
"description": "A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations",

@@ -20,36 +20,83 @@ "author": "Roman Dvornov <rdvornov@gmail.com> (https://github.com/lahmatiy)",

],
"main": "lib/index.js",
"unpkg": "dist/csstree.min.js",
"jsdelivr": "dist/csstree.min.js",
"type": "module",
"main": "./cjs/index.cjs",
"exports": {
".": {
"import": "./lib/index.js",
"require": "./cjs/index.cjs"
},
"./dist/*": "./dist/*.js",
"./package.json": "./package.json",
"./tokenizer": {
"import": "./lib/tokenizer/index.js",
"require": "./cjs/tokenizer/index.cjs"
},
"./parser": {
"import": "./lib/parser/index.js",
"require": "./cjs/parser/index.cjs"
},
"./generator": {
"import": "./lib/generator/index.js",
"require": "./cjs/generator/index.cjs"
},
"./walker": {
"import": "./lib/walker/index.js",
"require": "./cjs/walker/index.cjs"
},
"./lexer": {
"import": "./lib/lexer/index.js",
"require": "./cjs/lexer/index.cjs"
},
"./definition-syntax": {
"import": "./lib/definition-syntax/index.js",
"require": "./cjs/definition-syntax/index.cjs"
},
"./utils": {
"import": "./lib/utils/index.js",
"require": "./cjs/utils/index.cjs"
}
},
"browser": {
"./cjs/data.cjs": "./dist/data.js",
"./cjs/version.cjs": "./dist/version.js",
"./lib/data.js": "./dist/data.js",
"./lib/version.js": "./dist/version.js"
},
"unpkg": "dist/csstree.esm.js",
"jsdelivr": "dist/csstree.esm.js",
"scripts": {
"build": "rollup --config",
"lint": "eslint data lib scripts test && node scripts/review-syntax-patch --lint && node scripts/update-docs --lint",
"build": "npm run bundle && npm run esm-to-cjs",
"build-and-test": "npm run bundle-and-test && npm run esm-to-cjs-and-test",
"bundle": "node scripts/bundle",
"bundle-and-test": "npm run bundle && npm run test:dist",
"esm-to-cjs": "node scripts/esm-to-cjs",
"esm-to-cjs-and-test": "npm run esm-to-cjs && npm run test:cjs",
"lint": "eslint lib scripts && node scripts/review-syntax-patch --lint && node scripts/update-docs --lint",
"lint-and-test": "npm run lint && npm test",
"update:docs": "node scripts/update-docs",
"review:syntax-patch": "node scripts/review-syntax-patch",
"test": "mocha --reporter progress",
"coverage": "nyc npm test",
"travis": "nyc npm run lint-and-test && npm run coveralls",
"coveralls": "nyc report --reporter=text-lcov | coveralls",
"prepublishOnly": "npm run build",
"test": "mocha lib/__tests --reporter ${REPORTER:-progress}",
"test:cjs": "mocha cjs/__tests --reporter ${REPORTER:-progress}",
"test:dist": "mocha dist/__tests --reporter ${REPORTER:-progress}",
"coverage": "c8 --exclude lib/__tests --reporter=lcovonly npm test",
"prepublishOnly": "npm run lint-and-test && npm run build-and-test",
"hydrogen": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/parse --stat -o /dev/null"
},
"dependencies": {
"mdn-data": "2.0.14",
"mdn-data": "2.0.23",
"source-map": "^0.6.1"
},
"devDependencies": {
"@rollup/plugin-commonjs": "^11.0.2",
"@rollup/plugin-json": "^4.0.2",
"@rollup/plugin-node-resolve": "^7.1.1",
"coveralls": "^3.0.9",
"eslint": "^6.8.0",
"c8": "^7.7.1",
"clap": "^2.0.1",
"coveralls": "^3.1.1",
"esbuild": "^0.13.3",
"eslint": "^7.24.0",
"json-to-ast": "^2.1.0",
"mocha": "^6.2.3",
"nyc": "^14.1.1",
"rollup": "^1.32.1",
"rollup-plugin-terser": "^5.3.0"
"mocha": "^9.1.2",
"rollup": "^2.58.0"
},
"engines": {
"node": ">=8.0.0"
"node": "^14.16.0 || >=15.0.0",
"npm": ">=7.0.0"
},

@@ -59,4 +106,7 @@ "files": [

"dist",
"lib"
"cjs",
"!cjs/__tests",
"lib",
"!lib/__tests"
]
}

@@ -8,3 +8,3 @@ <img align="right" width="111" height="111"

[![NPM version](https://img.shields.io/npm/v/css-tree.svg)](https://www.npmjs.com/package/css-tree)
[![Build Status](https://travis-ci.org/csstree/csstree.svg?branch=master)](https://travis-ci.org/csstree/csstree)
[![Build Status](https://github.com/csstree/csstree/actions/workflows/build.yml/badge.svg)](https://github.com/csstree/csstree/actions/workflows/build.yml)
[![Coverage Status](https://coveralls.io/repos/github/csstree/csstree/badge.svg?branch=master)](https://coveralls.io/github/csstree/csstree?branch=master)

@@ -14,6 +14,4 @@ [![NPM Downloads](https://img.shields.io/npm/dm/css-tree.svg)](https://www.npmjs.com/package/css-tree)

CSSTree is a tool set for CSS: [fast](https://github.com/postcss/benchmark) detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations. The main goal is to be efficient and W3C specs compliant, with focus on CSS analyzing and source-to-source transforming tasks.
CSSTree is a tool set for CSS: [fast](https://github.com/postcss/benchmark) detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations. The main goal is to be efficient and W3C spec compliant, with focus on CSS analyzing and source-to-source transforming tasks.
> NOTE: The library isn't in final shape and needs further improvements (e.g. AST format and API are subjects to change in next major versions). However it's stable enough and used by projects like [CSSO](https://github.com/css/csso) (CSS minifier) and [SVGO](https://github.com/svg/svgo) (SVG optimizer) in production.
## Features

@@ -37,2 +35,13 @@

## Projects using CSSTree
- [Svelte](https://github.com/sveltejs/svelte) – Cybernetically enhanced web apps
- [SVGO](https://github.com/svg/svgo) – Node.js tool for optimizing SVG files
- [CSSO](https://github.com/css/csso) – CSS minifier with structural optimizations
- [NativeScript](https://github.com/NativeScript/NativeScript) – NativeScript empowers you to access native APIs from JavaScript directly
- [react-native-svg](https://github.com/react-native-svg/react-native-svg) – SVG library for React Native, React Native Web, and plain React web projects
- [penthouse](https://github.com/pocketjoso/penthouse) – Critical Path CSS Generator
- [Bit](https://github.com/teambit/bit) – Bit is the platform for collaborating on components
- and more...
## Documentation

@@ -50,8 +59,13 @@

- [findAll(ast, fn)](docs/traversal.md#findallast-fn)
- [Utils for AST](docs/utils.md)
- [property(name)](docs/utils.md#propertyname)
- [keyword(name)](docs/utils.md#keywordname)
- [clone(ast)](docs/utils.md#cloneast)
- [fromPlainObject(object)](docs/utils.md#fromplainobjectobject)
- [toPlainObject(ast)](docs/utils.md#toplainobjectast)
- [Util functions](docs/utils.md)
- Value encoding & decoding
- [property(name)](docs/utils.md#propertyname)
- [keyword(name)](docs/utils.md#keywordname)
- [ident](docs/utils.md#ident)
- [string](docs/utils.md#string)
- [url](docs/utils.md#url)
- AST transforming
- [clone(ast)](docs/utils.md#cloneast)
- [fromPlainObject(object)](docs/utils.md#fromplainobjectobject)
- [toPlainObject(ast)](docs/utils.md#toplainobjectast)
- [Value Definition Syntax](docs/definition-syntax.md)

@@ -84,3 +98,3 @@ - [parse(source)](docs/definition-syntax.md#parsesource)

```
> npm install css-tree
npm install css-tree
```

@@ -91,9 +105,9 @@

```js
var csstree = require('css-tree');
import * as csstree from 'css-tree';
// parse CSS to AST
var ast = csstree.parse('.example { world: "!" }');
const ast = csstree.parse('.example { world: "!" }');
// traverse AST and modify it
csstree.walk(ast, function(node) {
csstree.walk(ast, (node) => {
if (node.type === 'ClassSelector' && node.name === 'example') {

@@ -113,6 +127,6 @@ node.name = 'hello';

// parse CSS to AST as a declaration value
var ast = csstree.parse('red 1px solid', { context: 'value' });
const ast = csstree.parse('red 1px solid', { context: 'value' });
// match to syntax of `border` property
var matchResult = csstree.lexer.matchProperty('border', ast);
const matchResult = csstree.lexer.matchProperty('border', ast);

@@ -131,5 +145,52 @@ // check first value node is a <color>

### Exports
Is it possible to import just a needed part of library like a parser or a walker. That's might useful for loading time or bundle size optimisations.
```js
import * as tokenizer from 'css-tree/tokenizer';
import * as parser from 'css-tree/parser';
import * as walker from 'css-tree/walker';
import * as lexer from 'css-tree/lexer';
import * as definitionSyntax from 'css-tree/definition-syntax';
import * as utils from 'css-tree/utils';
```
### Using in a browser
There are bundles are available for using in a browser:
- `dist/csstree.js` – minified IIFE with `csstree` as global
```html
<script src="node_modules/css-tree/dist/csstreejs"></script>
<script>
csstree.parse('.example { color: green }');
</script>
```
- `dist/csstree.esm.js` – minified ES module
```html
<script type="module">
import { parse } from 'node_modules/css-tree/dist/csstree.esm.js'
parse('.example { color: green }');
</script>
```
One of CDN services like `unpkg` or `jsDelivr` can be used. By default (for short path) a ESM version is exposing. For IIFE version a full path to a bundle should be specified:
```html
<!-- ESM -->
<script type="module">
import * as csstree from 'https://cdn.jsdelivr.net/npm/css-tree';
import * as csstree from 'https://unpkg.com/css-tree';
</script>
<!-- IIFE with an export to global -->
<script src="https://cdn.jsdelivr.net/npm/css-tree/dist/csstree.js"></script>
<script src="https://unpkg.com/css-tree/dist/csstree.js"></script>
```
## Top level API
![API map](https://cdn.rawgit.com/csstree/csstree/1.0/docs/api-map.svg)
![API map](https://cdn.rawgit.com/csstree/csstree/aaf327e/docs/api-map.svg)

@@ -136,0 +197,0 @@ ## License

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc