Skip to content

csstype Property.*/Globals value-unions enumerated instead of mapped to string when reached through DeepPartial<> — 872 giant @unboxed bodies + CSS-keyword constructors leak into shared namespace (blend 0.0.38-beta.1) #206

Description

@jagguji

Summary

csstype Property.* / Globals value-unions (Color, BackgroundColor, the
-moz-initial | inherit | initial | revert | unset … globals, the full 148 CSS
color keywords, etc.) are enumerated into giant @unboxed variants instead
of collapsing to the precise string mapping the extractor already knows how to
apply (isCssType, extract.mjs:1092). This fires when the csstype value is
reached through blend 0.0.38-beta.1's new ComponentTokenOverrides = DeepPartial<ComponentTokenType> wrapper — the same trigger as #205, but a
different symptom on a different code path.

Bindgen held constant, only the blend version bumped 0.0.38-beta.0 → 0.0.38-beta.1:

  • 872 emitted identifiers ≥ 200 chars in ContextSharedTypes.res alone (beta.0: 0); longest emitted line ≈ 12,071 chars.
  • ~3,076 CSS-keyword constructor lines (@as("aliceblue") Aliceblue, @as("-moz-initial") MozInitial, @as("currentcolor") Currentcolor …) added.
  • The collision report's "left as-is" ambiguous constructors jump 162 → 397 — CSS keywords (Aliceblue, AccentColor, Beige, Blueviolet+241 more) now leak into the shared/collision namespace of ContextSharedTypes.
  • The disambiguation table degrades from readable names (CenterConfigAlign, LeftConfigSide) to monstrosities like CenterMozInitialOrInherit…OrCurrentColorOrContextComponentTokensTAGSSmMinWidthConfig.

Not the same as the already-filed issues

TS input → current output → expected output

TypeScript (via DeepPartial<ComponentTokenType>):

// a token leaf whose type is a csstype property union
minWidth?: Property.MinWidth<string | number>   // = "-moz-initial" | "inherit" | … | (string & {}) | number | …

Current ReScript output (beta.1):

@unboxed type centerMozInitialOrInheritOrCurrentColorOrContextComponentTokensTAGSSmMinWidthConfig =
  | @as("-moz-initial") MozInitial
  | @as("inherit") Inherit
  | @as("aliceblue") Aliceblue
  | …  /* ~150 CSS keyword constructors */
  | Currentcolor
  | ContextComponentTokensTAGSSmMinWidthConfig

Expected (what isCssType already produces for a directly-referenced csstype value):

minWidth: string,   // csstype Property.* → string (precise, not a loose fallback)

Suspected root cause

isCssType (extract.mjs:1092-1099) recognises csstype only by the
declaration's source-file path
(/csstype/):

const sym = type.aliasSymbol || (type.getSymbol && type.getSymbol()) || type.symbol
const decl = sym && sym.getDeclarations && sym.getDeclarations()[0]
const file = decl && decl.getSourceFile().fileName
return !!(file && /[\\/]csstype[\\/]/.test(file))

When the value is reached through the homomorphic mapped type
DeepPartial<ComponentTokenType>, the checker hands back a synthesized /
apparent union
of string-literal + globals types whose aliasSymbol /
declaration provenance no longer points at the csstype package file — so
isCssType returns false, the csstype→string shortcut is skipped, and the
union falls through to full member enumeration (→ #200's name bloat, cosmetically
capped by #201, plus the constructor leakage this issue is about).

Directly-referenced csstype values (not wrapped) still collapse to string
correctly — which is why beta.0 had 0 of these and beta.1 has 872.

Fix direction

Make csstype detection structural, not purely path-based, so it survives
mapped-type wrapping — e.g. recognise a union that is dominated by the csstype
Globals set (-moz-initial | inherit | initial | revert | revert-layer | unset)
and/or the CSS named-color vocabulary, optionally with a (string & {}) open arm,
and map it to string. Alternatively, unwrap DeepPartial<> / homomorphic
mapped types back to the source property type before classifying, so the original
aliasSymbol (and its csstype declaration file) is still visible to isCssType.

Collapsing at the source removes the 872 giant bodies entirely (not just their
names), stops the CSS-keyword constructor leakage into ContextSharedTypes, and
should also shrink the type graph enough to relieve part of #205.

Repro

npx @juspay/rescript-bindgen --pkg @juspay/blend-design-system@0.0.38-beta.0 --out /tmp/b0 --webapi --report
npx @juspay/rescript-bindgen --pkg @juspay/blend-design-system@0.0.38-beta.1 --out /tmp/b1 --webapi --report
# ≥200-char identifiers: 0 in b0, ~872 in b1 (ContextSharedTypes.res)
grep -oE '[A-Za-z0-9_]{200,}' /tmp/b1/ContextSharedTypes.res | wc -l
grep -oE '[A-Za-z0-9_]{200,}' /tmp/b0/*.res | wc -l

blend 0.0.38-beta.1 is already pinned in the benchmark, so this reproduces
in-repo. First observed in the downstream regen
blend-rescript#147, which
was generated against the last published bindgen (1.4.0-beta.1, pre-#201).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions