Socket
Socket
Sign inDemoInstall

css-tree

Package Overview
Dependencies
Maintainers
1
Versions
56
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-tree - npm Package Compare versions

Comparing version 1.0.0-alpha21 to 1.0.0-alpha22

lib/convertor/create.js

15

HISTORY.md

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

## 1.0.0-alpha22 (September 8, 2017)
- Parser
- Fixed exception on parsing of unclosed `{}-block` in tolerant mode
- Added tolerant mode support for `DeclarationList`
- Added standalone entry point, i.e. default parser can be used via `require('css-tree/lib/parser')` (#47)
- Generator
- Changed generator to produce `+n` when `AnPlusB.a` is `+1` to be "round-trip" with parser
- Added standalone entry point, i.e. default generators can be used via `require('css-tree/lib/generator')`
- Walker
- Added standalone entry point, i.e. default walkers can be used via `require('css-tree/lib/walker')` (#47)
- Lexer
- Added `default` keyword to the list of invalid values for `<custom-ident>` (since it reversed per [spec](https://www.w3.org/TR/css-values/#custom-idents))
- Convertors (`toPlainObject()` and `fromPlainObject()`) moved to `lib/convertor` (entry point is `require('css-tree/lib/convertor')`)
## 1.0.0-alpha21 (September 5, 2017)

@@ -2,0 +17,0 @@

120

lib/generator/index.js

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

'use strict';
var createGenerator = require('./create');
var config = require('../syntax/config/parser');
var hasOwnProperty = Object.prototype.hasOwnProperty;
var noop = function() {};
function each(processChunk, node) {
var list = node.children;
var cursor = list.head;
while (cursor !== null) {
this.generate(processChunk, cursor.data, cursor, list);
cursor = cursor.next;
}
}
function eachComma(processChunk, node) {
var list = node.children;
var cursor = list.head;
while (cursor !== null) {
if (cursor.prev) {
processChunk(',');
}
this.generate(processChunk, cursor.data, cursor, list);
cursor = cursor.next;
}
}
function createGenerator(types) {
var context = {
generate: function(processChunk, node, item, list) {
if (hasOwnProperty.call(types, node.type)) {
types[node.type].call(this, processChunk, node, item, list);
} else {
throw new Error('Unknown node type: ' + node.type);
}
},
each: each,
eachComma: eachComma
};
return function(node, fn) {
if (typeof fn !== 'function') {
// default generator concats all chunks in a single string
var buffer = [];
context.generate(function(chunk) {
buffer.push(chunk);
}, node);
return buffer.join('');
}
context.generate(fn, node);
};
}
function createMarkupGenerator(types) {
var context = {
generate: function(processChunk, node, item, list) {
if (hasOwnProperty.call(types, node.type)) {
var nodeBuffer = [];
types[node.type].call(this, function(chunk) {
nodeBuffer.push(chunk);
}, node, item, list);
processChunk({
node: node,
value: nodeBuffer
});
} else {
throw new Error('Unknown node type: ' + node.type);
}
},
each: each,
eachComma: eachComma
};
return function(node, enter, leave) {
function walk(node, buffer) {
var value = node.value;
enter(node.node, buffer, value);
if (typeof value === 'string') {
buffer += value;
} else {
for (var i = 0; i < value.length; i++) {
if (typeof value[i] === 'string') {
buffer += value[i];
} else {
buffer = walk(value[i], buffer);
}
}
}
leave(node.node, buffer, value);
return buffer;
}
if (typeof enter !== 'function') {
enter = noop;
}
if (typeof leave !== 'function') {
leave = noop;
}
var buffer = [];
context.generate(function() {
buffer.push.apply(buffer, arguments);
}, node);
return walk(buffer[0], '');
};
}
module.exports = {
createGenerator: createGenerator,
createMarkupGenerator: createMarkupGenerator,
sourceMap: require('./sourceMap')
};
module.exports = createGenerator(config);
'use strict';
module.exports = require('./syntax/default');
module.exports = require('./syntax');

@@ -169,2 +169,3 @@ 'use strict';

// https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident
// https://drafts.csswg.org/css-values-4/#identifier-value
function customIdent(node) {

@@ -177,3 +178,4 @@ if (node.data.type !== 'Identifier') {

// can't be a global CSS value
// § 3.2. Author-defined Identifiers: the <custom-ident> type
// The CSS-wide keywords are not valid <custom-ident>s
if (name === 'unset' || name === 'initial' || name === 'inherit') {

@@ -183,2 +185,7 @@ return false;

// The default keyword is reserved and is also not a valid <custom-ident>
if (name === 'default') {
return false;
}
// TODO: ignore property specific keywords (as described https://developer.mozilla.org/en-US/docs/Web/CSS/custom-ident)

@@ -185,0 +192,0 @@

@@ -13,2 +13,3 @@ 'use strict';

var search = require('./search');
var getStructureFromConfig = require('./structure').getStructureFromConfig;
var cssWideKeywords = parse('inherit | initial | unset');

@@ -125,3 +126,3 @@ var cssWideKeywordsWithExpression = parse('inherit | initial | unset | <expression>');

this.types = {};
this.structure = structure;
this.structure = structure || getStructureFromConfig(config);

@@ -128,0 +129,0 @@ if (config) {

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

'use strict';
var createParser = require('./create');
var config = require('../syntax/config/parser');
var Tokenizer = require('../tokenizer');
var sequence = require('./sequence');
var noop = function() {};
module.exports = function createParser(config) {
var parser = {
scanner: new Tokenizer(),
filename: '<unknown>',
needPositions: false,
tolerant: false,
onParseError: noop,
parseAtruleExpression: true,
parseSelector: true,
parseValue: true,
parseCustomProperty: false,
readSequence: sequence,
tolerantParse: function(consumer, fallback) {
if (this.tolerant) {
var start = this.scanner.currentToken;
try {
return consumer.call(this);
} catch (e) {
this.onParseError(e);
return fallback.call(this, start);
}
} else {
return consumer.call(this);
}
},
getLocation: function(start, end) {
if (this.needPositions) {
return this.scanner.getLocationRange(
start,
end,
this.filename
);
}
return null;
},
getLocationFromList: function(list) {
if (this.needPositions) {
return this.scanner.getLocationRange(
list.head !== null ? list.first().loc.start.offset - this.scanner.startOffset : this.scanner.tokenStart,
list.head !== null ? list.last().loc.end.offset - this.scanner.startOffset : this.scanner.tokenStart,
this.filename
);
}
return null;
},
parse: function(source, options) {
options = options || {};
var context = options.context || 'default';
var ast;
this.scanner.setSource(source, options.offset, options.line, options.column);
this.filename = options.filename || '<unknown>';
this.needPositions = Boolean(options.positions);
this.tolerant = Boolean(options.tolerant);
this.onParseError = typeof options.onParseError === 'function' ? options.onParseError : noop;
this.parseAtruleExpression = 'parseAtruleExpression' in options ? Boolean(options.parseAtruleExpression) : true;
this.parseSelector = 'parseSelector' in options ? Boolean(options.parseSelector) : true;
this.parseValue = 'parseValue' in options ? Boolean(options.parseValue) : true;
this.parseCustomProperty = 'parseCustomProperty' in options ? Boolean(options.parseCustomProperty) : false;
if (!this.context.hasOwnProperty(context)) {
throw new Error('Unknown context `' + context + '`');
}
ast = this.context[context].call(this, options);
if (!this.scanner.eof) {
this.scanner.error();
}
// console.log(JSON.stringify(ast, null, 4));
return ast;
}
};
for (var key in config) {
parser[key] = config[key];
}
return parser.parse.bind(parser);
};
module.exports = createParser(config);

@@ -1,15 +0,9 @@

var hasOwnProperty = Object.prototype.hasOwnProperty;
var List = require('../utils/list');
var createParser = require('../parser');
var createGenerator = require('../generator').createGenerator;
var createMarkupGenerator = require('../generator').createMarkupGenerator;
var sourceMapGenerator = require('../generator').sourceMap;
var createConvertors = require('../utils/convert');
var createWalker = require('../walker');
var names = require('../utils/names');
var mix = require('./mix');
function merge() {
var dest = {};
function assign(dest, src) {
for (var key in src) {
dest[key] = src[key];
for (var i = 0; i < arguments.length; i++) {
var src = arguments[i];
for (var key in src) {
dest[key] = src[key];
}
}

@@ -20,277 +14,8 @@

function createParseContext(name) {
return function() {
return this[name]();
};
}
function isValidNumber(value) {
// Number.isInteger(value) && value >= 0
return (
typeof value === 'number' &&
isFinite(value) &&
Math.floor(value) === value &&
value >= 0
);
}
function isValidLocation(loc) {
return (
Boolean(loc) &&
isValidNumber(loc.offset) &&
isValidNumber(loc.line) &&
isValidNumber(loc.column)
);
}
function createNodeStructureChecker(type, fields) {
return function checkNode(node, warn) {
if (!node || node.constructor !== Object) {
return warn('Type of node should be an object');
}
for (var key in node) {
if (key === 'type') {
if (node.type !== type) {
warn('Wrong node type `' + node.type + '` but expected `' + type + '`');
}
} else if (key === 'loc') {
if (node.loc === null) {
continue;
} else if (node.loc && node.loc.constructor === Object) {
if (typeof node.loc.source === 'string' &&
isValidLocation(node.loc.start) &&
isValidLocation(node.loc.end)) {
continue;
}
}
warn('Wrong value for `' + type + '.' + key + '` field');
} else if (fields.hasOwnProperty(key)) {
for (var i = 0, valid = false; !valid && i < fields[key].length; i++) {
var fieldType = fields[key][i];
switch (fieldType) {
case String:
valid = typeof node[key] === 'string';
break;
case Boolean:
valid = typeof node[key] === 'boolean';
break;
case null:
valid = node[key] === null;
break;
default:
if (typeof fieldType === 'string') {
valid = node[key] && node[key].type === fieldType;
} else if (Array.isArray(fieldType)) {
valid = node[key] instanceof List;
}
}
}
if (!valid) {
warn('Wrong value for `' + type + '.' + key + '` field');
}
} else {
warn('Unknown field `' + key + '` for ' + type);
}
}
for (var key in fields) {
if (hasOwnProperty.call(node, key) === false) {
warn('Field `' + type + '.' + key + '` is missed');
}
}
};
}
function processStructure(name, nodeType) {
var structure = nodeType.structure;
var fields = {
type: String,
loc: true
};
var walkers = [];
var docs = {
type: '"' + name + '"'
};
for (var key in structure) {
var walker = {
name: key,
type: false,
nullable: false
};
var docsTypes = [];
var fieldTypes = fields[key] = Array.isArray(structure[key])
? structure[key].slice()
: [structure[key]];
for (var i = 0; i < fieldTypes.length; i++) {
var fieldType = fieldTypes[i];
if (fieldType === String || fieldType === Boolean) {
docsTypes.push(fieldType.name);
} else if (fieldType === null) {
walker.nullable = true;
docsTypes.push('null');
} else if (typeof fieldType === 'string') {
walker.type = 'node';
docsTypes.push('<' + fieldType + '>');
} else if (Array.isArray(fieldType)) {
walker.type = 'list';
docsTypes.push('List'); // TODO: use type enum
} else {
throw new Error('Wrong value in `' + name + '` structure definition');
}
}
docs[key] = docsTypes.join(' | ');
if (walker.type) {
walkers.push(walker);
}
}
return {
docs: docs,
check: createNodeStructureChecker(name, fields),
walk: walkers.length ? {
context: nodeType.walkContext,
fields: walkers
} : null
};
}
function createSyntax(config) {
var parser = { context: {}, scope: {}, atrule: {}, pseudo: {} };
var walker = { type: {} };
var generator = {};
var lexer = { structure: {} };
if (config.parseContext) {
for (var name in config.parseContext) {
switch (typeof config.parseContext[name]) {
case 'function':
parser.context[name] = config.parseContext[name];
break;
case 'string':
parser.context[name] = createParseContext(config.parseContext[name]);
break;
}
}
}
if (config.scope) {
for (var name in config.scope) {
parser.scope[name] = config.scope[name];
}
}
if (config.atrule) {
for (var name in config.atrule) {
var atrule = config.atrule[name];
if (atrule.parse) {
parser.atrule[name] = atrule.parse;
}
}
}
if (config.pseudo) {
for (var name in config.pseudo) {
var pseudo = config.pseudo[name];
if (pseudo.parse) {
parser.pseudo[name] = pseudo.parse;
}
}
}
if (config.node) {
for (var name in config.node) {
var nodeType = config.node[name];
parser[name] = nodeType.parse;
generator[name] = nodeType.generate;
if (nodeType.structure) {
var structure = processStructure(name, nodeType);
lexer.structure[name] = {
docs: structure.docs,
check: structure.check
};
if (structure.walk) {
walker.type[name] = structure.walk;
}
} else {
throw new Error('Missed `structure` field in `' + name + '` node type definition');
}
}
}
var parse = createParser(parser);
var Lexer = require('../lexer/Lexer');
var walker = createWalker(walker.type);
var convertors = createConvertors(walker);
var markupGenerator = createMarkupGenerator(generator);
var syntax = {
List: require('../utils/list'),
Tokenizer: require('../tokenizer'),
Lexer: require('../lexer/Lexer'),
property: names.property,
keyword: names.keyword,
lexer: null,
syntax: require('../lexer'),
createLexer: function(config) {
return new Lexer(config, syntax, lexer.structure);
},
parse: parse,
walk: walker.all,
walkUp: walker.allUp,
walkRules: walker.rules,
walkRulesRight: walker.rulesRight,
walkDeclarations: walker.declarations,
translate: createGenerator(generator),
translateWithSourceMap: function(node) {
return sourceMapGenerator(markupGenerator, node);
},
translateMarkup: markupGenerator,
clone: require('../utils/clone'),
fromPlainObject: convertors.fromPlainObject,
toPlainObject: convertors.toPlainObject,
createSyntax: function(config) {
return createSyntax(mix({}, config));
},
fork: function(extension) {
var base = mix({}, config); // copy of config
return createSyntax(
typeof extension === 'function'
? extension(base, assign)
: mix(base, extension)
);
}
};
syntax.lexer = new Lexer({
generic: true,
types: config.types,
properties: config.properties
}, syntax, lexer.structure);
return syntax;
};
exports.create = function(config) {
return createSyntax(mix({}, config));
};
module.exports = require('./create').create(
merge(
require('./config/lexer'),
require('./config/parser'),
require('./config/walker')
)
);

@@ -160,3 +160,4 @@ var cmpChar = require('../../tokenizer').cmpChar;

processChunk(
node.a === '+1' || node.a === '1' ? 'n' :
node.a === '+1' ? '+n' :
node.a === '1' ? 'n' :
node.a === '-1' ? '-n' :

@@ -163,0 +164,0 @@ node.a + 'n'

@@ -51,3 +51,5 @@ var List = require('../../utils/list');

this.scanner.eat(RIGHTCURLYBRACKET);
if (!this.tolerant || !this.scanner.eof) {
this.scanner.eat(RIGHTCURLYBRACKET);
}

@@ -54,0 +56,0 @@ return {

@@ -8,2 +8,6 @@ var List = require('../../utils/list');

function consumeRaw(startToken) {
return this.Raw(startToken, 0, SEMICOLON, true, true);
}
module.exports = {

@@ -27,3 +31,3 @@ name: 'DeclarationList',

default:
children.appendData(this.Declaration());
children.appendData(this.tolerantParse(this.Declaration, consumeRaw));
}

@@ -30,0 +34,0 @@ }

@@ -76,6 +76,14 @@ 'use strict';

// https://drafts.csswg.org/css-syntax/#tokenizer-definitions
// > non-ASCII code point
// > A code point with a value equal to or greater than U+0080 <control>
// > name-start code point
// > A letter, a non-ASCII code point, or U+005F LOW LINE (_).
// > name code point
// > A name-start code point, a digit, or U+002D HYPHEN-MINUS (-)
// That means only ASCII code points has a special meaning and we a maps for 0..127 codes only
var SafeUint32Array = typeof Uint32Array !== 'undefined' ? Uint32Array : Array; // fallback on Array when TypedArray is not supported
var SYMBOL_TYPE = new SafeUint32Array(Math.max.apply(null, Object.keys(NAME).map(Number)) + 1);
var PUNCTUATION = new SafeUint32Array(SYMBOL_TYPE.length);
var STOP_URL_RAW = new SafeUint32Array(SYMBOL_TYPE.length);
var SYMBOL_TYPE = new SafeUint32Array(0x80);
var PUNCTUATION = new SafeUint32Array(0x80);
var STOP_URL_RAW = new SafeUint32Array(0x80);

@@ -82,0 +90,0 @@ for (var i = 0; i < SYMBOL_TYPE.length; i++) {

@@ -9,3 +9,2 @@ 'use strict';

var SYMBOL_TYPE = constants.SYMBOL_TYPE;
var SYMBOL_TYPE_LENGTH = SYMBOL_TYPE.length;

@@ -122,3 +121,3 @@ var utils = require('./utils');

var code = source.charCodeAt(offset);
var type = code < SYMBOL_TYPE_LENGTH ? SYMBOL_TYPE[code] : IDENTIFIER;
var type = code < 0x80 ? SYMBOL_TYPE[code] : IDENTIFIER;

@@ -125,0 +124,0 @@ balance[tokenCount] = sourceLength;

@@ -5,6 +5,3 @@ 'use strict';

var PUNCTUATION = constants.PUNCTUATION;
var SYMBOL_TYPE = constants.SYMBOL_TYPE;
var SYMBOL_TYPE_LENGTH = SYMBOL_TYPE.length;
var STOP_URL_RAW = constants.STOP_URL_RAW;
var STOP_URL_RAW_LENGTH = STOP_URL_RAW.length;
var TYPE = constants.TYPE;

@@ -221,3 +218,3 @@ var FULLSTOP = TYPE.FullStop;

offset = findEscaseEnd(source, offset + 1);
} else if (code < SYMBOL_TYPE_LENGTH && PUNCTUATION[code] === PUNCTUATOR) {
} else if (code < 0x80 && PUNCTUATION[code] === PUNCTUATOR) {
break;

@@ -236,3 +233,3 @@ }

offset = findEscaseEnd(source, offset + 1);
} else if (code < STOP_URL_RAW_LENGTH && STOP_URL_RAW[code] === 1) {
} else if (code < 0x80 && STOP_URL_RAW[code] === 1) {
break;

@@ -239,0 +236,0 @@ }

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

'use strict';
var createWalker = require('./create');
var config = require('../syntax/config/walker');
function walkRules(node, item, list) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.children.each(walkRules, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.block !== null) {
var oldAtrule = this.atrule;
this.atrule = node;
walkRules.call(this, node.block);
this.atrule = oldAtrule;
}
this.fn(node, item, list);
break;
case 'Rule':
this.fn(node, item, list);
var oldRule = this.rule;
this.rule = node;
walkRules.call(this, node.block);
this.rule = oldRule;
break;
case 'Block':
var oldBlock = this.block;
this.block = node;
node.children.each(walkRules, this);
this.block = oldBlock;
break;
}
}
function walkRulesRight(node, item, list) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.children.eachRight(walkRulesRight, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.block !== null) {
var oldAtrule = this.atrule;
this.atrule = node;
walkRulesRight.call(this, node.block);
this.atrule = oldAtrule;
}
this.fn(node, item, list);
break;
case 'Rule':
var oldRule = this.rule;
this.rule = node;
walkRulesRight.call(this, node.block);
this.rule = oldRule;
this.fn(node, item, list);
break;
case 'Block':
var oldBlock = this.block;
this.block = node;
node.children.eachRight(walkRulesRight, this);
this.block = oldBlock;
break;
}
}
function walkDeclarations(node) {
switch (node.type) {
case 'StyleSheet':
var oldStylesheet = this.stylesheet;
this.stylesheet = node;
node.children.each(walkDeclarations, this);
this.stylesheet = oldStylesheet;
break;
case 'Atrule':
if (node.block !== null) {
var oldAtrule = this.atrule;
this.atrule = node;
walkDeclarations.call(this, node.block);
this.atrule = oldAtrule;
}
break;
case 'Rule':
var oldRule = this.rule;
this.rule = node;
if (node.block !== null) {
walkDeclarations.call(this, node.block);
}
this.rule = oldRule;
break;
case 'Block':
node.children.each(function(node, item, list) {
if (node.type === 'Declaration') {
this.fn(node, item, list);
} else {
walkDeclarations.call(this, node);
}
}, this);
break;
}
}
function createContext(root, fn) {
var context = {
fn: fn,
root: root,
stylesheet: null,
atrule: null,
atruleExpression: null,
rule: null,
selector: null,
block: null,
declaration: null,
function: null
};
return context;
}
module.exports = function createWalker(types) {
var walkers = {};
for (var name in types) {
var config = types[name];
walkers[name] = Function('node', 'context', 'walk',
(config.context ? 'var old = context.' + config.context + ';\ncontext.' + config.context + ' = node;\n' : '') +
config.fields.map(function(field) {
var line = field.type === 'list'
? 'node.' + field.name + '.each(walk);'
: 'walk(node.' + field.name + ');';
if (field.nullable) {
line = 'if (node.' + field.name + ') {\n ' + line + '}';
}
return line;
}).join('\n') +
(config.context ? '\ncontext.' + config.context + ' = old;' : '')
);
}
return {
all: function(root, fn) {
function walk(node, item, list) {
fn.call(context, node, item, list);
if (walkers.hasOwnProperty(node.type)) {
walkers[node.type](node, context, walk);
}
}
var context = createContext(root, fn);
walk(root);
},
allUp: function(root, fn) {
function walk(node, item, list) {
if (walkers.hasOwnProperty(node.type)) {
walkers[node.type](node, context, walk);
}
fn.call(context, node, item, list);
}
var context = createContext(root, fn);
walk(root);
},
rules: function(root, fn) {
walkRules.call(createContext(root, fn), root);
},
rulesRight: function(root, fn) {
walkRulesRight.call(createContext(root, fn), root);
},
declarations: function(root, fn) {
walkDeclarations.call(createContext(root, fn), root);
}
};
};
module.exports = createWalker(config);
{
"name": "css-tree",
"version": "1.0.0-alpha21",
"version": "1.0.0-alpha22",
"description": "Fast detailed CSS parser",

@@ -5,0 +5,0 @@ "keywords": [

Sorry, the diff of this file is too big to display

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc