πΊπΈ English version | π·πΊ Π ΡΡΡΠΊΠ°Ρ Π²Π΅ΡΡΠΈΡ
High-performance ECSS parser written in Rust (napi-rs). Accepts source text and returns an AST.
- β‘ Written in Rust β native N-API addon, minimal overhead
- π WASM support β works in Node.js without a native build (
@ecss/parser/wasm) and in the browser (@ecss/parser/wasm/browser) - π¦ Dual CJS/ESM β
requireandimportout of the box - π₯οΈ Cross-platform β macOS, Linux, Windows, plus a WASM target
- π TypeScript β types included, auto-generated from Rust code
npm install @ecss/parseror
pnpm add @ecss/parseror
yarn add @ecss/parserimport { parseEcss } from '@ecss/parser';
const ast = parseEcss(`
@state-variant Theme {
values: light, dark;
}
@state-def Button(--theme Theme: "light", --disabled boolean: false) {
border-radius: 6px;
@if (--disabled) {
opacity: 0.4;
cursor: not-allowed;
}
@if (--theme == "light") {
background: #fff;
color: #111;
}
@else {
background: #1e1e1e;
color: #f0f0f0;
}
}
`);
console.log(ast.rules);The only exported function. Accepts an ECSS source string and returns the AST.
On parse failure throws a JavaScript Error with the source location: [line:column] description.
import { parseEcss } from '@ecss/parser';
try {
const ast = parseEcss(source);
// ast: EcssStylesheet
} catch (err) {
// e.g. "[3:5] Unknown at-rule: @unknown"
console.error(err.message);
}The root node of the tree.
interface EcssStylesheet {
rules: EcssRule[];
}A top-level rule. The kind discriminant determines which field is populated.
interface EcssRule {
kind: 'state-variant' | 'state-def' | 'qualified-rule' | 'at-rule';
stateVariant?: StateVariant;
stateDef?: StateDef;
qualifiedRule?: CssQualifiedRule;
atRule?: CssRawAtRule;
}An @state-variant node.
interface StateVariant {
name: string; // enumeration name, e.g. "Theme"
values: string[]; // ["light", "dark"]
span: Span;
}An @state-def node.
interface StateDef {
name: string;
params: StateParam[];
body: StateDefItem[];
span: Span;
}
interface StateParam {
name: string; // "--theme"
paramType: 'boolean' | string; // "boolean" or a @state-variant name
variantName?: string; // @state-variant name for variant params
defaultValue?: string; // "light", "true", "false", etc.
}An item inside a @state-def or @if block body.
interface StateDefItem {
kind: 'declaration' | 'qualified-rule' | 'if-chain' | 'at-rule';
declaration?: CssDeclaration;
qualifiedRule?: CssQualifiedRule;
ifChain?: IfChain;
atRule?: CssRawAtRule;
}An @if / @elseif / @else node.
interface IfChain {
ifClause: IfClause;
elseIfClauses: IfClause[];
elseBody?: StateDefItem[];
span: Span;
}
interface IfClause {
condition: unknown; // JSON-serialized ConditionExpr
body: StateDefItem[];
span: Span;
}The condition field contains a ConditionExpr serialized to JSON. Shape:
// { kind: "var", var: "--name" }
// { kind: "comparison", left: "--name", op: "==" | "!=", right: { kind, value } }
// { kind: "and", left: ConditionExpr, right: ConditionExpr }
// { kind: "or", left: ConditionExpr, right: ConditionExpr }A CSS declaration (property: value).
interface CssDeclaration {
property: string;
value: string;
important: boolean;
span: Span;
}A CSS rule with a selector (including CSS Nesting inside @state-def).
interface CssQualifiedRule {
selector: string; // "&:hover", ".class > div", etc.
body: StateDefItem[];
span: Span;
}An arbitrary CSS at-rule that is not an ECSS construct.
interface CssRawAtRule {
name: string;
prelude: string;
block?: string;
span: Span;
}Source position of a node.
interface Span {
line: number;
column: number;
endLine: number;
endColumn: number;
}If the native build is unavailable (e.g. containers without N-API support, or the browser), use the WASM variants.
Node.js / WASI:
import { parseEcss } from '@ecss/parser/wasm';Browser:
import { parseEcss } from '@ecss/parser/wasm/browser';The native addon is preferred automatically; the WASM binding acts as a fallback. To force WASM, set the environment variable
NAPI_RS_FORCE_WASI=1.
| Platform | Architecture | Target |
|---|---|---|
| macOS | x64 | x86_64-apple-darwin |
| macOS | ARM64 | aarch64-apple-darwin |
| Linux (glibc) | x64 | x86_64-unknown-linux-gnu |
| Windows | x64 | x86_64-pc-windows-msvc |
| WASM | β | wasm32-wasip1-threads |
Build native addon:
pnpm build # release
pnpm build:debug # debugBuild WASM:
pnpm build:wasm # release
pnpm build:wasm:debug # debugTests:
pnpm testType check:
pnpm typecheckLint and format (JS/TS):
pnpm lint # oxlint
pnpm lint:fix # oxlint --fix
pnpm fmt # oxfmt
pnpm fmt:check # oxfmt --checkLint and format (Rust):
pnpm lint:rs # cargo clippy -D warnings
pnpm lint:rs:fix # cargo clippy --fix
pnpm fmt:rs # cargo fmt
pnpm fmt:rs:check # cargo fmt --checkDeveloped and maintained by Ruslan Martynov.
Found a bug or have a suggestion? Open an issue or submit a pull request.
Distributed under the MIT License.