mrkeyoor.com_
Sat 08 Aug 21:56 UTC
npmUtilsupdated 08 Aug 2026

css

css is the old Rework CSS parser and stringifier. It turns a stylesheet string into a plain JavaScript AST with rules, declarations, comments, selected at-rules, source positions, and non-enumerable parent links; you can edit that tree and turn it back into readable or compressed CSS. It is a CommonJS syntax utility, not a validator, browser compatibility layer, prefixer, module system, or plugin runner.

Verdict

Do not install it for a new CSS tool; its own maintainers tell you to move to @adobe/css-tools. Keep it only where compatibility with the Rework AST is more valuable than modern syntax coverage, types, and planned bug fixes.

API stability4/5The two-function parse and stringify API and the documented AST shapes have barely moved, and version 3.0.0 still preserves the Rework-era model, non-enumerable parent links, positional errors, compression, and source maps. That makes old integrations predictable. It does not earn a five because the API's apparent stability is tied to a frozen grammar, and unsupported new CSS can force a migration even if this package never changes.
Docs4/5The README documents both functions, every option, structured parse errors, common node properties, and each supported AST node with an example tree. It also gives unusually direct maintenance guidance and names the recommended successor. It falls short on modern syntax boundaries, traversal patterns, mutation examples, CommonJS and browser constraints, the source-map return-type change, and the practical consequences of non-enumerable parent and source-content properties.
Maintenance1/5The latest npm release is 3.0.0 from July 2020, its packaged history records its last functional parser fix in June 2015, and the current README says no material changes have happened in ten years and that new changes and bug fixes are not planned. GitHub was pushed in June 2026 and the repository is not archived, but that activity includes the maintenance warning rather than a renewed roadmap; only concrete security issues may still receive changes.
Ecosystem3/5The package recorded 4,298,721 downloads in the measured week and the repository has 1,646 stars, reflecting its long history in Rework-derived dependency trees. Its AST is recognizable and easy to manipulate with ordinary JavaScript. The active CSS tooling ecosystem has moved to PostCSS, css-tree, Lightning CSS, and the compatible @adobe/css-tools successor, so high transitive traffic should not be mistaken for a growing plugin or contributor community here.

Use it if

  • You maintain a Rework-era tool whose plugins already expect this package's exact AST node shapes
  • You need a small synchronous CommonJS parser for CSS 2.1-era rules and the documented set of older at-rules
  • You want simple parse, mutate, and stringify behavior without adopting a plugin architecture
  • You need its non-enumerable parent links and source-position objects for an existing analysis script
Skip it if

Setup reality

npm install css gives you a CommonJS module with parse and stringify; there are no peer dependencies, credentials, config files, binaries, or native compilation. The package does bring inherits, source-map 0.6, and source-map-resolve. Parsing and stringifying are synchronous, so large or hostile stylesheets block the event loop. Pass source when parsing if filenames and generated mappings matter. Without silent, the first syntax problem throws an Error carrying reason, filename, line, column, and the full source. With silent, parsing continues where its hand-written grammar can recover and errors collect under ast.stylesheet.parsingErrors; that is not the same as accepting valid modern CSS. Each AST node gets a non-enumerable parent property, and each position object inherits the full input through position.content. JSON.stringify omits those properties, which makes serialized trees look simpler than live ones. The parser only knows its documented node set, declaration values stay opaque strings, and comments embedded inside selectors, properties, or values are removed rather than round-tripped. Stringification defaults to readable output; compress strips comments and unnecessary whitespace. Sourcemap mode changes the return type from a string to an object with code and map. Input map resolution is enabled by default, can synchronously read files named by sourceMappingURL comments, and should be disabled with inputSourcemaps: false when file access is unwanted. No TypeScript declarations or ESM export map are included.

Patterns

Parse CSS into an ASTparse-stylesheet

const css = require('css');

const ast = css.parse('body { color: #222; }', {
  source: 'styles/app.css',
});
console.log(ast.stylesheet.rules[0].type); // rule

source is optional, but supplying the real path produces useful filenames in errors and source maps.

Report a positioned syntax errorhandle-parse-error

try {
  css.parse('a { color red }', { source: 'broken.css' });
} catch (error) {
  console.error({
    reason: error.reason,
    file: error.filename,
    line: error.line,
    column: error.column,
  });
}

The default mode stops at the first parser error. error.source also contains the complete input string, which may be too much to log.

Collect errors without throwingcollect-parse-errors

const ast = css.parse(input, {
  source: 'input.css',
  silent: true,
});

for (const error of ast.stylesheet.parsingErrors) {
  console.error(`${error.line}:${error.column} ${error.reason}`);
}

silent only changes error handling. It does not make the grammar understand unsupported modern at-rules or guarantee a complete recovered tree.

Read selectors from top-level ruleslist-selectors

const selectors = ast.stylesheet.rules
  .filter((node) => node.type === 'rule')
  .flatMap((rule) => rule.selectors);

console.log(selectors);

Nested rules under @media, @supports, @document, and @host are not included; recurse through their rules arrays when they matter.

Walk rules inside supported block at-ruleswalk-rules

function walk(nodes, visit) {
  for (const node of nodes) {
    visit(node);
    if (Array.isArray(node.rules)) walk(node.rules, visit);
    if (Array.isArray(node.keyframes)) walk(node.keyframes, visit);
    if (Array.isArray(node.declarations)) walk(node.declarations, visit);
  }
}

walk(ast.stylesheet.rules, (node) => {
  if (node.type === 'declaration') console.log(node.property);
});

There is no built-in walker. Different node types store children under rules, keyframes, or declarations, so a generic Object.keys recursion can accidentally follow parent links.

Rewrite declaration valueschange-declaration

walk(ast.stylesheet.rules, (node) => {
  if (node.type === 'declaration' && node.property === 'color') {
    node.value = 'rebeccapurple';
  }
});

const output = css.stringify(ast);

Values are opaque strings. The package will print your replacement without checking property grammar, units, functions, or browser support.

Remove comment nodes before outputremove-comments

function stripComments(nodes) {
  return nodes
    .filter((node) => node.type !== 'comment')
    .map((node) => {
      if (node.rules) node.rules = stripComments(node.rules);
      if (node.declarations) node.declarations = stripComments(node.declarations);
      if (node.keyframes) node.keyframes = stripComments(node.keyframes);
      return node;
    });
}

ast.stylesheet.rules = stripComments(ast.stylesheet.rules);

Comments are explicit nodes only at rule and declaration boundaries. Comments embedded in selectors, properties, or values were already discarded during parsing.

Generate readable CSS with custom indentationstringify-readable

const output = css.stringify(ast, {
  indent: '    ',
});
console.log(output);

Stringification normalizes formatting rather than preserving the original whitespace and comment placement byte for byte.

Generate compact CSSstringify-compressed

const minified = css.stringify(ast, { compress: true });
console.log(minified);

Compression removes comments and extra whitespace, but this is an old syntax printer rather than a modern optimizer that merges, rewrites, or validates rules.

Generate CSS and a serialized source mapgenerate-source-map

const ast = css.parse(input, { source: 'src/input.css' });
const result = css.stringify(ast, {
  sourcemap: true,
  inputSourcemaps: false,
});

console.log(result.code);
console.log(result.map);

With sourcemap enabled, stringify returns { code, map } instead of a string. Parsing with source gives mappings a meaningful filename.

Return a SourceMapGeneratorget-map-generator

const result = css.stringify(ast, {
  sourcemap: 'generator',
  inputSourcemaps: false,
});

const json = result.map.toJSON();

The generator is from the package's source-map 0.6 dependency, so methods and async behavior differ from newer source-map releases.

Serialize the enumerable AST safelyserialize-ast

const snapshot = JSON.stringify(ast, null, 2);
const restored = JSON.parse(snapshot);

parent references and position.content are non-enumerable, so JSON.stringify avoids cycles but restored nodes lose parent links and the original source content used for maps.

Alternatives

PackageRegistryPick it when
@adobe/css-toolsnpmUse the repository's recommended successor for a familiar AST plus TypeScript support and current fixes
postcssnpmUse the dominant plugin ecosystem when you need transforms, syntax extensions, warnings, or established tooling integrations
css-treenpmUse a detailed parser, walker, generator, and lexer when standards-aware analysis and validation matter
lightningcssnpmUse a fast parser, transformer, prefixer, and minifier when native binaries are acceptable