Skip to content

Refactor CSS node types with reusable type builders#267

Merged
bartveneman merged 4 commits into
mainfrom
claude/package-size-reduction-97fdn8
Jul 19, 2026
Merged

Refactor CSS node types with reusable type builders#267
bartveneman merged 4 commits into
mainfrom
claude/package-size-reduction-97fdn8

Conversation

@bartveneman

Copy link
Copy Markdown
Member

Summary

This refactor introduces reusable type builders (Toggle, WithClone, and Leaf) to reduce duplication across ~40 CSS node type definitions. These are pure type-level utilities that compile away entirely, improving maintainability without runtime cost.

Key Changes

  • Added Toggle<HasKey, ValueKey, T> type: A discriminated union pattern for optional fields gated by boolean flags (e.g., has_prelude / prelude). Replaces repeated inline union patterns throughout the file.

  • Added WithClone<T> type: Wraps a node type to add a clone() method with proper return type inference (ToPlain<T>). Eliminates repetitive clone method declarations.

  • Added Leaf<Type, Name, Extra> type: Combines CSSNode, type tag, and optional extra fields for leaf nodes (nodes without children). Significantly reduces boilerplate for simple node types.

  • Refactored all node type definitions to use these builders:

    • Structural nodes: StyleSheet, Rule, Atrule, Declaration, Selector, SelectorList, Block, Comment, Raw
    • Value nodes: Identifier, Number, Dimension, String, Hash, Function, Operator, Parenthesis, Url, UnicodeRange, Value
    • Selector nodes: TypeSelector, ClassSelector, IdSelector, AttributeSelector, PseudoClassSelector, PseudoElementSelector, Combinator, UniversalSelector, NestingSelector, NthSelector, NthOfSelector, LangSelector
    • At-rule prelude nodes: AtrulePrelude, MediaQuery, MediaFeature, MediaType, ContainerQuery, SupportsQuery, SupportsDeclaration, LayerName, PreludeSelectorList, PreludeOperator, FeatureRange

Implementation Details

  • The Toggle type replaces verbose union patterns like ({ readonly has_X: true } & { readonly X: T }) | ({ readonly has_X: false } & { readonly X: null }) with a single, reusable construct.
  • BlockChild now uses Toggle for its has_next / next_sibling pattern.
  • All type definitions maintain identical semantics and exported interfaces—this is purely a refactoring for code clarity and maintainability.
  • The builders are documented with JSDoc comments explaining their purpose and usage.

https://claude.ai/code/session_01FuvCERnifYS6ggHAXMwVkD

Factor the ~44 near-identical node-type declarations (CSSNode & {
type, type_name, clone(): ToPlain<Self> }) into two small internal
generics, Leaf<> and WithClone<>, instead of hand-rolling each one.
Purely a type-level change (zero runtime/JS output difference,
zero public API change) that shrinks the largest file in the
published tarball (node-types.d.ts: 25.17kB -> 22.18kB), cutting
overall unpacked install size by ~1.5%.
@github-actions

github-actions Bot commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

⚠️ Duplicate Dependencies (found: 11, threshold: 1)

📦 Package 📋 Versions
tinybench
2 versions
  • root@
    • @vitest/coverage-v8@4.1.10
      • vitest@4.1.10
        • tinybench@2.9.0

  • root@
    • tinybench@6.0.2

js-tokens
2 versions
  • root@
    • @vitest/coverage-v8@4.1.10
      • ast-v8-to-istanbul@1.0.5
        • js-tokens@10.0.0

  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • parse-json@5.2.0
          • @babel/code-frame@7.27.1
            • js-tokens@4.0.0

@emnapi/core
2 versions
  • root@
    • knip@6.27.0
      • oxc-resolver@11.21.3
        • @oxc-resolver/binding-wasm32-wasi@11.21.3
          • @emnapi/core@1.11.0

  • root@
    • @vitest/coverage-v8@4.1.10
      • ...
        • rolldown@1.1.5
          • @rolldown/binding-wasm32-wasi@1.1.5
            • @emnapi/core@1.11.1

@emnapi/runtime
2 versions
  • root@
    • knip@6.27.0
      • oxc-resolver@11.21.3
        • @oxc-resolver/binding-wasm32-wasi@11.21.3
          • @emnapi/runtime@1.11.0

  • root@
    • @vitest/coverage-v8@4.1.10
      • ...
        • rolldown@1.1.5
          • @rolldown/binding-wasm32-wasi@1.1.5
            • @emnapi/runtime@1.11.1

picomatch
2 versions
  • root@
    • tailwindcss@2.2.19
      • chokidar@3.6.0
        • anymatch@3.1.3
          • picomatch@2.3.2

  • root@
    • @vitest/coverage-v8@4.1.10
      • vitest@4.1.10
        • @vitest/mocker@4.1.10
          • vite@8.1.4
            • picomatch@4.0.5

postcss-value-parser
2 versions
  • root@
    • tailwindcss@2.2.19
      • reduce-css-calc@2.1.8
        • postcss-value-parser@3.3.1

  • root@
    • tailwindcss@2.2.19
      • autoprefixer@10.4.23
        • postcss-value-parser@4.2.0

glob-parent
2 versions
  • root@
    • tailwindcss@2.2.19
      • chokidar@3.6.0
        • glob-parent@5.1.2

  • root@
    • tailwindcss@2.2.19
      • glob-parent@6.0.2

yaml
2 versions
  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • yaml@1.10.3

  • root@
    • @vitest/coverage-v8@4.1.10
      • vitest@4.1.10
        • @vitest/mocker@4.1.10
          • vite@8.1.4
            • yaml@2.9.0

is-arrayish
2 versions
  • root@
    • tailwindcss@2.2.19
      • cosmiconfig@7.1.0
        • parse-json@5.2.0
          • error-ex@1.3.4
            • is-arrayish@0.2.1

  • root@
    • tailwindcss@2.2.19
      • color@4.2.3
        • color-string@1.9.1
          • simple-swizzle@0.2.4
            • is-arrayish@0.3.4

get-tsconfig
2 versions
  • root@
    • knip@6.27.0
      • get-tsconfig@4.14.0

  • root@
    • tsdown@0.22.8
      • rolldown-plugin-dts@0.27.9
        • get-tsconfig@5.0.0-beta.5

@oxc-project/types
2 versions
  • root@
    • knip@6.27.0
      • oxc-parser@0.137.0
        • @oxc-project/types@0.137.0

  • root@
    • @vitest/coverage-v8@4.1.10
      • ...
        • vite@8.1.4
          • rolldown@1.1.5
            • @oxc-project/types@0.139.0

💡 To find out what depends on a specific package, run: pnpm -r why example-package

🎉 Package Size Decrease

📦 Package 📏 Base Size 📏 Source Size 📈 Size Change
@projectwallace/css-parser 41.3 kB 41.2 kB -100 B

@bartveneman
bartveneman merged commit e2119ca into main Jul 19, 2026
8 checks passed
@bartveneman
bartveneman deleted the claude/package-size-reduction-97fdn8 branch July 19, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants