A tool set for CSS including fast detailed parser, walker, generator and lexer based on W3C specs and browser implementations
MIT License
Bot releases are visible (Hide)
@container
at-rule@starting-style
at-rule@scope
at-rule@position-try
at-rule@layer
at-rulelayer
, layer()
and supports()
in the @media
at-rule (according to the @import rule in Cascading and Inheritance 5)Layer
and LayerList
node typesTokenStream#lookupTypeNonSC()
method<dashed-ident>
to generic typesmdn/data
to 2.10.0
<'font'>
to CSS Fonts 4
<color>
to CSS Color 5
Object.prototype
is extended or polluted (#262)fork()
method to consider the generic
option when creating a Lexer instance (#266)line
or offset
is specified via options (#251)speak
syntax patch (#241):lang()
to accept a list of <ident>
or <string>
per spec (#265)<'property'>
, when the syntax has a top-level #
-multiplier (#102)parseWithFallback()
to rollback tokenIndex
before calling a fallbackBlock
to not include {
and }
Atrule
and Rule
to include {
and }
for a blockRatio
parsing:
Ratio
can be omitted. While this can't be a parser output (which would produce a Number
node), it's feasible during Ratio
node construction or transformation.Feature
: represents features like (feature)
and (feature: value)
, fundamental for both @media
and @container
at-rulesFeatureRange
: represents features in a range context
FeatureFunction
: represents functional features such as @supports
's selector()
or @container
's style()
Condition
: used across all query-like at-rules, encapsulating queries with features and the not
, and
, and or
operatorsGeneralEnclosure
: represents the <general-enclosed>
production, which caters to unparsed parentheses or functional expressionsNote: All new nodes include a
kind
property to define the at-rule type. Supported kinds aremedia
,supports
, andcontainer
(width: calc(100cm / 6))
condition
value for the parser's context option to parse queries. Use the kind
option to specify the condition type, e.g., parse('...', { context: 'condition', kind: 'media' })
features
section in the syntax configuration for defining functional features of at-rules. Expand definitions using the fork()
method. The current definition is as follows:
features: {
supports: { selector() { /* ... */ } },
container: { style() { /* ... */ } }
}
@media
at-rule:
GeneralEnclosed
(width > 100px)
or (100px < height < 400px)
MediaFeature
node type to the Feature
node type with kind: "media"
MediaQuery
node structure into the following form:
type MediaQuery = {
type: "MediaQuery";
modifier: string | null; // e.g. "not", "only", etc.
mediaType: string | null; // e.g. "all", "screen", etc.
condition: Condition | null;
}
@supports
at-rule:
GeneralEnclosed
(width > 100px)
or (100px < height < 400px)
SupportsDeclaration
node type to encapsulate a declaration in a query, replacing Parentheses
Condition
or SupportsDeclaration
nodes of kind supports
instead of Parentheses
selector()
feature via the FeatureFunction
node (configured in features.supports.selector
)Published by lahmatiy almost 2 years ago
:host
, :host()
and :host-context()
pseudo class support (#216)generator
, parse
and parse-selector
entry points by adding missed NestedSelector
node typePublished by lahmatiy almost 2 years ago
NestingSelector
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
Published by lahmatiy about 2 years ago
2.2.0
for at-rule syntax matching when at-rule has no prelude (#203)Published by lahmatiy about 2 years ago
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)[-∞,∞]
rangesPublished by lahmatiy over 2 years ago
mdn-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)Published by lahmatiy almost 3 years ago
^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)Published by lahmatiy almost 3 years ago
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>
.Published by lahmatiy almost 3 years ago
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
Published by lahmatiy almost 3 years ago
^12.20.0
and ^14.13.0
versionsPublished by lahmatiy almost 3 years ago
The 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 insteadPublished by lahmatiy over 3 years ago
fit-content
to width
property patch as browsers are supported it as a keyword (nonstandard), but spec defines it as a functionparseValue
option is set to false
, in that case !important
was included into a value but must not (#155)Published by lahmatiy almost 4 years ago
Published by lahmatiy almost 4 years ago
SyntaxMatchError
Published by lahmatiy almost 4 years ago
parseCustomProperty:true
Published by lahmatiy almost 4 years ago
mdn-data
to 2.0.14fork()
method to allow append syntax instead of overriding for types
, properties
and atrules
, e.g. csstree.fork({ types: { color: '| foo | bar' } })
Lexer#checkAtruleName(atruleName)
, Lexer#checkAtrulePrelude(atruleName, prelude)
, Lexer#checkAtruleDescriptorName(atruleName, descriptorName)
and Lexer#checkPropertyName(propertyName)
Lexer#getAtrule(atruleName, fallbackBasename)
methodLexer#getAtrulePrelude()
and Lexer#getProperty()
methods to take fallbackBasename
parameterPublished by lahmatiy almost 4 years ago
onComment
option to parser configbreak
and skip
values in walk()
to control traversalList#reduce()
and List#reduceRight()
methodsmdn-data
to 2.0.12import { version } from 'css-tree'
)HexColor
node type into Hash
element()
specific parsing rulesdist/default-syntax.json
from packageLexer#dump()
to dump atrules syntaxes as well<urange>
list (#135)Published by lahmatiy almost 5 years ago
visit: "Declaration"
to iterate DeclarationList
(#114)Published by lahmatiy almost 5 years ago
mdn-data
to 2.0.6
Lexer#matchAtrulePrelude()
and Lexer#matchAtruleDescriptor()
methods-moz-control-character-visibility
, -ms-grid-columns
, -ms-grid-rows
and -ms-hyphenate-limit-last
properties to patch (#111, thanks to @life777)flow
, flow-root
and table-caption
values to patched display
(#112, thanks to @silverwind)Published by lahmatiy almost 5 years ago
source-map
version to ^0.6.1
to fix source map generation inconsistency across node.js versions due to mappings sorting bug and v8 moving to a stable Array#sort (fix commit in source-map
)