feat: build-time component-style attribution (RFC 0001 — Task A)#49
Merged
Conversation
…N_SCHEMA_VERSION to 2 Introduces optional `styleSource` on `ManifestEntry` (build-time className tokens + CSS-in-JS source-block location) and optional `componentStyles` on `RuntimeContextSchema` (≤32-property computed allowlist + resolved CSS custom properties), per RFC 0001. Lands the schema half so transform, runtime, and relay packages can build against it without circular work. The v1 → v2 migration is purely additive — fields are optional, so v1 payloads pass through untouched. A no-op `migrationSteps[1]` is registered so `migrateAnnotation` can stamp persisted v1 annotations to v2 without throwing on the version walk. Forward-compat guarantee for v1-pinned clients reading v2 annotations is asserted in the migration spec. Also adds `COMPONENT_STYLES_ALLOWLIST` as the authoritative computed-style property list so the runtime, the relay, and downstream tooling agree on the capture contract. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Adds a parser-agnostic style extractor that piggybacks on the existing JSX AST visit: - `extractClassNameFromJSX` resolves className tokens through string literals, no-interpolation template literals, conditional/logical expressions, array/object expressions, and clsx/cn/tw/classNames/twMerge/ cva helpers (incl. member-expression helpers like `utils.cn`). Unknown helpers and bare identifiers yield an empty token set rather than guessing — the agent can read source if static reasoning fails. - `collectCssInJsDeclarations` scans top-level `const X = styled.foo\`\``, `styled(Y)\`\``, and emotion `css\`\`` declarations and records source location + verbatim block text (4 KB cap). Library is inferred from the imported module specifier; no theme or config resolution at transform time (per RFC 0001). - The injector calls both on the same AST pass when `captureStyles` is on, resolves the JSX tag name to its binding via `resolveTagToBindingName`, and attaches an optional `styleSource` to each manifest entry. `captureStyles` defaults off in v0.x per RFC 0001 reversibility plan and is plumbed through `InjectorOptions`, `InjectorRegistry`, Vite, webpack, and turbopack plugins. Tests: - 33-case real-world corpus under `test/className-corpus/` exercising every pattern the RFC review flagged (literals, helpers, templates, conditionals, spread, CSS-in-JS). - End-to-end injector spec runs the real Babel parser with `captureStyles: true` to verify className tokens and styled-component source-block linkage land on manifest entries. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
… tools `ManifestEntrySchema` now carries an optional `styleSource`, so `manifest.query` returns it automatically via the existing schema-driven output. `resolve` extracts individual fields and previously dropped unknown ones — extended to forward `styleSource` alongside `file`/ `start`/`end`/`componentName`/`tagName`. Tool descriptions are updated so agents know they can request styling context via the static `styleSource` (build-time className tokens + CSS- in-JS source-block location) before reaching for the runtime `query.bySource` path. Description text deliberately conditions on "when build-time style capture is enabled" — the field is absent when the transform was run with the default `captureStyles: false`. Storage-layer specs are updated to reference `ANNOTATION_SCHEMA_VERSION` rather than hard-coding `1`, so the v2 bump in @domscribe/core doesn't silently regress the on-read migration assertions. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
|
View your CI Pipeline Execution ↗ for commit 777e497
💡 Verify your cache is correct by running tasks in a sandbox. Read docs ↗ ☁️ Nx Cloud last updated this comment at |
Narrator
pushed a commit
that referenced
this pull request
Jun 7, 2026
Task A (#49) landed on main while this PR was open and added the same optional componentStyles field to RuntimeContextSchema plus the COMPONENT_STYLES_ALLOWLIST constant and a v1→v2 schema version bump in @domscribe/core. Resolved annotation.ts by taking main's version (Task A's additions are a functional superset — same shape for ComponentStylesSchema and componentStyles, plus the version-history note, the allowlist constant, and ComponentStylesAllowlist type). All other changes auto-merged cleanly: this PR's StyleCapturer, relay componentStyles surface, and falsifier harness sit on top of Task A's build-time style-source attribution. Note for follow-up: there are now two allowlists living in two places — COMPONENT_STYLES_ALLOWLIST in @domscribe/core (32 entries from Task A) and STYLE_CAPTURE_ALLOWLIST in @domscribe/runtime (31 entries from this PR). They overlap but are not identical. The schema field is record<string,string> so neither is enforced; this is a documentation/ contract divergence, not a runtime defect. PE/PM should pick one canonical list in a follow-up. Post-merge verification (Nx targets on the merge commit): - domscribe-core:test → pass (all suites green, 100% coverage on annotation.ts) - domscribe-runtime:test → pass (548 tests) - domscribe-relay:test → pass - domscribe-transform:test → pass - typecheck across all 4 → clean - lint across all 4 → clean Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This was referenced Jun 8, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Lands the build-time half of RFC 0001: Component-Style Capture (sprint 2734, Task A).
@domscribe/core: adds optionalStyleSourceonManifestEntry(className + parsed utility tokens + CSS-in-JS source-block location) and optionalComponentStylesonRuntimeContextSchema(≤32-property computed allowlist + resolved CSS custom properties). BumpsANNOTATION_SCHEMA_VERSIONfrom 1 → 2 with a purely-additive v1 → v2 migration step + tests for forward-compat with v1-pinned clients.@domscribe/transform: parser-agnostic style extractor wired into the existing JSX AST visit. Handles className literals, no-interpolation template literals,clsx/cn/classNames/tw/twMerge/cvacalls, conditional/logical/array/object expressions, member-expression helpers, and bare-identifier spread. Scans top-levelstyled.foo/styled(X)/ emotioncssdeclarations to link JSX tags to their source blocks (block text capped at 4 KB, no theme resolution). Behind a newcaptureStylesfeature flag (default off in v0.x per RFC reversibility plan); plumbed through Vite, webpack, and turbopack plugins.@domscribe/relay:manifest.queryreturnsstyleSourceautomatically (schema-driven);resolveextracts and forwards it explicitly. Tool descriptions updated so agents know they can request static styling context before reaching for runtime data.The runtime half (
StyleCapturerpopulatingcomponentStyles, MCPquery.bySourceextension, test-fixtures falsifier harness) is Task B (#49) and depends on the schema additions in this PR.Test plan
nx run domscribe-core:test— 122 tests pass (incl. 3 new migration cases).nx run domscribe-transform:test— 405 tests pass (incl. 33 new corpus cases undertest/className-corpus/+ 7 new injector integration cases forcaptureStyles: true).nx run domscribe-relay:test— 306 tests pass (incl. newresolve.toolforward-the-styleSource case; updatedfile-annotation-storagespecs to referenceANNOTATION_SCHEMA_VERSIONinstead of hard-coding 1).nx run-many -t test --exclude domscribe-test-fixtures— all 10 projects pass.nx run-many -t lint -p domscribe-core,domscribe-transform,domscribe-relay— clean.nx run-many -t build --exclude domscribe-test-fixtures— all 12 projects build.Out of scope
Explicitly deferred per DOP / PM plan: Svelte adapter, post-completion visual-diff loop, props/state hardening, RCP-as-public-protocol revival, vendor directory, per-adapter (React/Vue/Next/Nuxt) styling work, transform-time Tailwind/theme resolution.
Schema-bump risk
ANNOTATION_SCHEMA_VERSION1 → 2 is additive only. V1-pinned consumers reading v2 annotations see the v1 fields untouched (the newcomponentStylesslot is absent). On-disk v1 annotations migrate forward throughFileAnnotationStorage.read/listByStatus(existing migrate-on-read path) without re-validation. Asserted byannotation-migrations.spec.tsandfile-annotation-storage.spec.ts.🤖 Generated with Claude Code