Skip to content

Repository files navigation

oxc-css-parser

This project is a fork of g-plane/raffia for Oxfmt.

Crates.io docs.rs

oxc-css-parser parses CSS, SCSS, Sass, and Less. It produces an AST and does not compile preprocessor syntax to CSS.

Example

use oxc_css_parser::{Allocator, Parser, Syntax, ast::Stylesheet};

let allocator = Allocator::default();
let mut parser = Parser::new(&allocator, "a { color: green }", Syntax::Css);
let ast = parser.parse::<Stylesheet>().unwrap();
println!("{:#?}", ast);

More examples are available in examples.

For detailed API documentation, see docs.rs.

Acceptance

Why there is a line to draw: css-syntax-3 alone rejects the postcss-plugin CSS real projects are full of (*zoom, $var, --color-*, x: { }), while postcss itself is a tokenizer plus a statement splitter, so following its acceptance wholesale means an AST of strings. Leniency never reaches below a statement: selectors, values and preludes are typed or raw, never re-parsed strings.

Each line has one grammar owner. postcss is never one, and neither is "Prettier prints it".

Changing acceptance is additive: it only turns errors into parses, with a comment citing the owner, a test pinning the strict shape, and the conformance snapshot flip in the PR. Changing how already-accepted input is represented is a bug fix or a refactor, and the PR says which.

CSS

Owner: css-syntax-3's syntax layer (tokenizer, rule / declaration / block structure).

  • A declaration value is any component-value run: a value the typed grammar cannot read falls back to raw tokens
  • Two postcss statement shapes on top, because the spec's syntax layer drops them and real projects run through postcss plugins:
    • postcss property names: the glued token run up to the first : / whitespace / comment, not necessarily an <ident-token> (*zoom, +color, #x, 2xl, background+, --color-*, $(var)-size)
    • raw-prelude rules: x: { ... } is a rule, with or without a trailing ;, and so is a numeric-led statement (50% { } outside @keyframes); the prelude is kept as raw tokens (UnknownQualifiedRule)
  • $var gets a typed node (PostcssSimpleVar, postcss-simple-vars): an AST shape for the formatter's layout, not extra acceptance, $var: value is already a postcss property name. $var: value; at the root is a statement, that is where postcss-simple-vars defines variables
  • Root declarations: the TopLevelDeclaration recoverable error. postcss keeps them; not followed
  • Everything else the spec's syntax layer discards stays rejected (color red;, x: {a:b} more;), and so do shapes the spec keeps but nobody asked for ("foo" {}, ( ) {}, , .a {}): the spec is a ceiling, not a floor
  • Errors: css-syntax-3 recovery (EOF closes blocks, bad strings) is kept even where postcss throws
  • Oracles: cssparser (Servo) for the spec ceiling, postcss at Prettier's pinned version for the two shapes

SCSS / Sass

Owner: dart-sass. No postcss-scss leniency.

  • No raw fallback for a normal property's value: the expression grammar owns it
  • A custom property value is text, as dart-sass reads it (// is no comment inside)
  • Root declarations: the TopLevelDeclaration recoverable error, as dart-sass rejects them
  • The IE *color hack is kept as a name prefix, as dart-sass accepts it

Less

Owner: less.js. No postcss-less leniency.

  • No raw fallback for a normal property's value
  • Root declarations parse: less.js accepts them at parse time and fails only at eval
  • The IE *color hack as a name prefix and digit-only names (5: x), as less.js accepts them

css-in-js parse mode

SCSS with template_placeholder set. It is the only option, and the only place a dialect line is relaxed.

  • A backtick-delimited `<prefix><digits>` is one typed Token::Placeholder
  • Root declarations are statements, without the error: a fragment is usually a declaration list (css`display: flex;`)
  • Nothing from the CSS line comes along; postcss property names extend here only on demand

Benchmark

The benchmark suite compares parser performance against other CSS parsers.

Install cargo-criterion, then run the checked-in fixture benchmark:

cargo install cargo-criterion
cargo criterion

To benchmark custom inputs, add CSS, SCSS, Sass, or Less files to a local bench_data directory. When bench_data contains supported files, it is used instead of the checked-in fixtures.

Credits

Tests come from:

License

MIT License

Our sponsors

About

No description, website, or topics provided.

Resources

Stars

12 stars

Watchers

2 watching

Forks

Releases

Packages

Used by

Contributors

Languages