A tool set for CSS including fast detailed parser, walker, generator and lexer based on W3C specs and browser implementations
:host
, :host()
and :host-context()
pseudo class support (#216)generator
, parse
and parse-selector
entry points by adding missed NestedSelector
node typeNestingSelector
node type for &
(a nesting selector) in selectors@nest
at-rule@media
inside a Rule
to parse its block content as a Declaration
firstDeclarationList
behaviour to follow the rules for Rule
's blockLexer#units
dictionary to provide unit groups (length
, angle
, etc.) used for matchingconfig.units
to override default unitsmdn-data
to 2.0.30
2.2.0
for at-rule syntax matching when at-rule has no prelude (#203)mdn-data
to 2.0.28
revert
and revert-layer
expression()
the same way as CSS wide keywordsbackground-clip
property definition to match Backgrounds and Borders 4 (#190)content
property definition to allow attr()
(#201)<delim-token>
@page
at-rule (#191)rex
, cap
, rcap
, rch
, ic
, ric
, lh
, rlh
, vi
, vb
, sv*
, lv*
, dv*
cqw
, cqh
, cqi
, cqb
, cqmin
, cqmax
vm
unit (supposed to be an old IE versions supported this unit instead of vmax
)+#
and #?
according to spec (#199)[-∞,∞]
rangesmdn-data
to 2.0.27
module
field to package.json
css-tree/utils
export (#181)css-tree/convertor
exportcss-tree/selector-parser
export (~27kb when bundled, #183)css-tree/parser
50kb -> 41kbcss-tree/generator
46kb -> 23kbsyntaxes
into types
in css-tree/definition-syntax-data-patch
:is()
, :-moz-any()
, :-webkit-any()
and :where()
(#182, #184)^10
generate()
in safe mode to add a whitespace between <dimension-token>
and <hash-token>
, otherwise some values are broken in IE11, e.g. border
properties (#173):
for an attribute name on AttributeSelector
parsing as it does not meet the CSS specs (details)generate()
in safe
mode between type-selector
and id-selector
(e.g. a#id
). A regression was introduces in 2.0.2
since IE11 fails on values when <hash-token>
goes after <ident-token>
without a whitespace in the middle, e.g. 1px solid#000
. Thus, in one case, a space between the <ident-token>
and the <hash-token>
is required, and in the other, vice versa. Until a better solution found, a workaround is used on id-selector
generation by producing a <delim-token>
instead of <hash-token>
.width
, min-width
and max-width
syntax definitionsmdn-data
source-map
with source-map-js
which reduce install size by ~700KBcalc()
function consumption on definition syntax matchinggenerate()
auto emitting a whitespace edge cases when next token starts with a dash (minus)generate()
safe mode to cover more cases for IE11dist/data.cjs
and dist/version.cjs
css-tree/definition-syntax-data
css-tree/definition-syntax-data-patch
^12.20.0
and ^14.13.0
versionsThe source code was refactored to use ES2020 syntax and ES modules by default. However, Commonjs version of library is still supported, so the package became a dual module. Using ESM allowed to reduce bundle size from 167Kb down to 164Kb despite that mdn-data
grew up in size by 11Kb.
In case only a part of CSSTree functionality is used (for instance only for a parsing), it's possible now to use specific exports like css-tree/parser
(see the full list of exports) to reduce a bundle size. As new package mechanics are used, the minimal version for Node.js was changed to 14.16+
.
Previously white spaces was preserved on CSS parsing as a WhiteSpace
node with a single space. This was mostly needed to avoid combining the CSS tokens into one when generating back into a CSS string. This is no longer necessary, as the generator has been reworked to independently determine when to use spaces in output. This simplify analysis and construction of the AST, and also improves the performance and memory consumption a bit.
Some changes have been made to the AST construction during parsing. First of all, white spaces in selectors are now producing { type: 'Combinator', name: ' ' }
nodes when appropriate. Second, white spaces surrounding operators -
and +
are now replacing with a single space and appending to operators to preserve a behaviour of expressions in calc()
functions. Finally, the only case a WhiteSpace
node is now created is a custom property declaration with a single whitespace token as the value, since --var: ;
and --var:;
have different behaviour in terms of CSS.
CSS Syntax Module defines rules for CSS serialization that it must "round-trip" with parsing. Starting with this release the CSSTree's generator follows these rules and determines itself when to output the space to avoid unintended CSS tokens combining.
The spec rules allow to omit whitespaces in most cases. However, some older browsers fail to parse the resulting CSS because they didn't follow the spec. For this reason, the generator supports two modes:
safe
(by default) which adds an extra space in some edge cases;spec
which completely follows the spec.import { parse, generate } from 'css-tree';
const ast = parse('a { border: calc(1px) solid #ff0000 }');
// safe mode is by default
// the same as console.log(generate(ast, { mode: 'safe' }));
console.log(generate(ast));
// a{border:calc(1px) solid#ff0000}
// spec mode
console.log(generate(ast, { mode: 'spec' }));
// a{border:calc(1px)solid#ff0000}
These changes to the generator bring it closer to the pretty print output that will be implemented in future releases.
For string and url values an auto encoding and decoding was implemented. This means you no longer need to do any preprocessing on string or url values before analyzing or transforming of it. Most noticeable simplification with Url
nodes:
// CSSTree 1.x
csstree.walk(ast, function(node) {
if (node.type === 'Url') {
if (node.value.type === 'String') {
urls.push(node.value.value.substring(1, node.value.value.length - 1));
} else {
urls.push(node.value.value);
}
}
});
// CSSTree 2.0
csstree.walk(ast, function(node) {
if (node.type === 'Url') {
urls.push(node.value);
}
});
It is worth noting that despite the fact that in many cases the example above will give the same results for both versions, a solution with CSSTree 1.x still lacks decoding of escaped sequences, that is, additional processing of values is needed.
Additionaly, encode and decode functions for string
, url
and ident
values are available as utils:
import { string, url, ident } from 'css-tree';
string.decode('"hello\\9 \\"world\\""') // hello\t "world"
string.decode('\'hello\\9 "world"\'') // hello\t "world"
string.encode('hello\t "world"') // "hello\9 \"world\""
string.encode('hello\t "world"', true) // 'hello\9 "world"'
url.decode('url(file\ \(1\).ext)') // file (1).ext
url.encode('file (1).ext') // url(file\ \(1\).ext)
ident.decode('hello\\9 \\ world') // hello\t world
ident.encode('hello\t world') // hello\9 \ world
14.16
(following patch versions changed it to ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0
)import * as parser from "css-tree/parser"
or require("css-tree/parser")
):
css-tree/tokenizer
css-tree/parser
css-tree/walker
css-tree/generator
css-tree/lexer
css-tree/definition-syntax
css-tree/utils
dist/csstree.js
(an IIFE version with csstree
as a global name) and dist/csstree.esm.js
(as ES module). Both are minifiedmdn-data
to 2.0.23
tokenize()
to take a function as second argument, which will be called for every token. No stream instance is creating when second argument is ommited.TokenStream#getRawLength()
to take second parameter as a function (rule) that check a char code to stop a scanningTokenStream#forEachToken(fn)
methodTokenStream#skipWS()
methodTokenStream#getTokenLength()
methodSyntaxError
(custom parser's error class) from root of public API to parser via parse.SyntaxError
parseError
field in parser's SyntaxError
{ type: 'Combinator', name: ' ' }
node instead of WhiteSpace
nodeWhiteSpace
nodes with the single exception for a custom property declaration with a single white space token as a value+
and -
operators, when a whitespace is before and/or after an operatorparse.config
consumeUntilBalanceEnd()
, consumeUntilLeftCurlyBracket()
, consumeUntilLeftCurlyBracketOrSemicolon()
, consumeUntilExclamationMarkOrSemicolon()
and consumeUntilSemicolonIncluded()
methods to parser's inner API to use with Raw
instead of Raw.mode
Nth
to always consume of
clause when presented, so it became more general and moves validation to lexerString
node type to store decoded string value, i.e. with no quotes and escape sequencesUrl
node type to store decoded url value as a string instead of String
or Raw
node, i.e. with no quotes, escape sequences and url()
wrapperchunk()
handler to token()
(output a single token) and tokenize()
(split a string into tokens and output each of them)mode
option for generate()
to specify a mode of token separation: spec
or safe
(by default)emit(token, type, auto)
handler as implementation specific token processorNth
to serialize +n
as n
string
and url
tokens on serializationLexer#matchDeclaration()
methodident
, string
and url
helpers to decode/encode corresponding values, e.g. url.decode('url("image.jpg")')
=== 'image.jpg'
List
to be iterable (iterates data)List#first
, List#last
and List#isEmpty
to gettersList#getSize()
method to List#size
getterList#each()
and List#eachRight()
methods, List#forEach()
and List#forEachRight()
should be used instead