Skip to content

Framework-adapter layer with first-class Vue 3 + Vuetify 3 support - #2

Merged
ryandmonk merged 2 commits into
mainfrom
claude/naughty-varahamihira-aa3b94
Jun 17, 2026
Merged

Framework-adapter layer with first-class Vue 3 + Vuetify 3 support#2
ryandmonk merged 2 commits into
mainfrom
claude/naughty-varahamihira-aa3b94

Conversation

@ryandmonk

Copy link
Copy Markdown
Contributor

Summary

Evolves dspack-export from a React-only exporter into a framework-agnostic, deterministic, source-driven snapshot generator. Component extraction now runs through a framework-adapter layer; the shared pipeline (token extraction, assembly, provenance, warnings, validation, output) is unchanged and framework-independent. React + Tailwind/shadcn and Vue 3 + Vuetify 3 ship today, with a clean path to Svelte next.

No dspack schema change. One new runtime dependency (@vue/compiler-sfc).

Architecture

  • src/adapters/types.tsFrameworkAdapter / AdapterContext contract (pure, read-only, no side effects).
  • src/adapters/registry.tsresolveAdapter(): explicit framework config wins, else inferred from component file extensions (.tsx/.jsx → react, .vue → vue), with a hard error before extraction on mixed/ambiguous input (nothing is written).
  • ReactAdapter wraps the existing extractors in place — same fragments, same precedence, byte-identical golden output.
  • frameworkBindings is namespaced per adapter (frameworkBindings.react, frameworkBindings.vue).

Vue 3 extraction

  • <script setup> type-based defineProps<T>() + withDefaults, runtime defineProps({...})/defineProps([...]), and Options API (defineComponent / export default, incl. name).
  • Emits (defineEmits type + array forms, Options emits) → on<PascalEvent> handler props (update:modelValueonUpdateModelValue); raw names preserved in frameworkBindings.vue.
  • Slots (defineSlots + template <slot>) → children (default) / slot:<name> (named, namespaced to avoid prop collisions).
  • Conservative Vuetify 3 usage detection (allowlist), surfaced additively as component tags + binding guidance.
  • Extraction reads the original <script> AST; @vue/compiler-sfc is the authoritative SFC/macro parser (compileScript as aid).
  • Conservative by default: computed/factory defaults, spread props, dynamic emit/slot lists, cross-file types → omitted with a provenance-tagged warning, never guessed.

Testing

  • 90 tests pass (was 51) + 1 skipped (ds-mcp round-trip).
  • React golden byte-identical; new fixtures/vuetify-demo golden validates against the bundled dspack v0.2 schema with zero schema changes.
  • Deterministic: double-run byte-identical under pinned SOURCE_DATE_EPOCH.
  • Constraint audit: no network / shell / extra writes in src/adapters/.

Notes for the maintainer

  • Version not bumped. GENERATOR_VERSION stays 0.1.0-alpha.1 so the React golden stays byte-identical. The release notes document the release-commit step: bump package.json + GENERATOR_VERSION to 0.2.0-alpha.0, then regenerate all goldens so metadata.generatedBy updates in lockstep.
  • The Vue fixture uses a DTCG token file rather than CSS: the shared layout extractor injects Tailwind default breakpoints whenever CSS is configured, which is misleading in a Vuetify snapshot. This keeps the Vue golden clean and framework-neutral.

See docs/adapters.md for the adapter contract.

🤖 Generated with Claude Code

Evolve dspack-export from a React-only exporter into a framework-agnostic,
deterministic snapshot generator. Component extraction now runs through a
FrameworkAdapter contract; the shared pipeline (tokens, assembly, provenance,
warnings, validation, output) is unchanged and framework-independent.

- src/adapters/{types,registry}.ts: adapter contract + selection (explicit
  `framework` config, else inferred by extension, hard error on ambiguous input
  before any output is written).
- ReactAdapter wraps the existing extractors in place; React golden stays
  byte-identical. `dropOrphanCvaComponents` re-exported from generate.ts.
- VueAdapter: `<script setup>` (type-based + runtime defineProps/withDefaults)
  and Options API props, emits normalized to on<PascalEvent> handler props,
  slots normalized to children / slot:<name>, conservative Vuetify 3 usage
  detection. Extraction reads the original script AST; @vue/compiler-sfc is the
  authoritative SFC/macro parser (compileScript as aid).
- Conservative throughout: partial/ambiguous/unsafe input is omitted with a
  provenance-tagged warning, never guessed.
- No dspack schema change; one new runtime dep (@vue/compiler-sfc).
- New fixtures/vuetify-demo golden + Vue/registry test suites (90 tests pass).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings June 17, 2026 17:20

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR refactors dspack-export to route component extraction through a framework-adapter layer, enabling first-class Vue 3 + Vuetify 3 snapshot generation while keeping the existing token/assembly/validation pipeline shared and deterministic.

Changes:

  • Introduces FrameworkAdapter/resolveAdapter() and moves React extraction behind a ReactAdapter wrapper to preserve existing output.
  • Adds a Vue 3 adapter that extracts props/emits/slots from SFCs and performs conservative Vuetify usage detection.
  • Expands tests, docs, and fixtures (including a Vue golden) and adds @vue/compiler-sfc as a runtime dependency.

Reviewed changes

Copilot reviewed 35 out of 36 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/tests/vueWarnings.test.ts Adds assertions for Vue adapter “omit + warn” behavior and provenance-tagged warnings.
src/tests/vuetifyUsage.test.ts Unit tests for Vuetify allowlist matching + usage detection.
src/tests/vueSlots.test.ts Unit tests for slot discovery and normalization to children / slot:<name>.
src/tests/vueProps.test.ts Unit tests for Vue props extraction paths (script setup + Options API).
src/tests/vueGolden.test.ts Adds Vue fixture golden test + schema validation and key extraction “facts”.
src/tests/vueEmits.test.ts Unit tests for emits extraction and on<PascalEvent> normalization.
src/tests/adapterRegistry.test.ts Tests adapter resolution and fail-fast behavior on ambiguous input.
src/init.ts Updates init to optionally detect Vue vs React and emit framework/tsconfig appropriately.
src/generate.ts Refactors generation to resolve and delegate to a single adapter; aggregates warnings.
src/config.ts Adds optional framework and makes tsconfig optional (required by React adapter).
src/adapters/vue/vuetifyUsage.ts Implements conservative Vuetify template-AST usage scanning.
src/adapters/vue/vuetifyComponents.ts Adds Vuetify 3 allowlist and tag normalization helpers.
src/adapters/vue/parseSfc.ts Adds Vue SFC parsing/compileScript shim and script AST parsing.
src/adapters/vue/index.ts Implements Vue adapter extraction and emits frameworkBindings.vue.
src/adapters/vue/extractSlots.ts Implements slot detection from defineSlots and <slot> tags.
src/adapters/vue/extractProps.ts Implements conservative Vue props extraction across supported forms.
src/adapters/vue/extractEmits.ts Implements emits extraction and handler-prop normalization.
src/adapters/vue/astHelpers.ts Shared Vue AST utilities (traverse shim, literals, TS-type mapping).
src/adapters/types.ts Defines the adapter contract (FrameworkAdapter / AdapterContext).
src/adapters/registry.ts Adds adapter registry + inference and explicit-framework resolution behavior.
src/adapters/react/index.ts Wraps existing React extractors under the adapter contract (preserving output).
README.md Updates README to describe multi-framework support and adapter selection.
package.json Adds @vue/compiler-sfc and a Vue fixture generation script; adds Vue as devDependency.
package-lock.json Lockfile updates for Vue compiler/tooling dependencies and version metadata.
fixtures/vuetify-demo/vuetify-demo.dspack.json Adds committed Vue golden snapshot output.
fixtures/vuetify-demo/tokens/tokens.json Adds DTCG token fixture used by the Vue demo.
fixtures/vuetify-demo/src/components/StatusBadge.vue Adds Options API fixture component for extraction coverage.
fixtures/vuetify-demo/src/components/FormField.vue Adds script-setup fixture for type-based props + emits.
fixtures/vuetify-demo/src/components/DataCard.vue Adds runtime-props + slot fixture (including non-literal default warning).
fixtures/vuetify-demo/src/components/ArrayProps.vue Adds string-array props fixture for “unknown + warn” behavior.
fixtures/vuetify-demo/src/components/AppButton.vue Adds “canonical wrapper” fixture for defaults/emits/slots + Vuetify usage.
fixtures/vuetify-demo/dspack-export.config.json Adds Vue fixture config enabling explicit framework: "vue".
docs/release-notes-v0.2.0-alpha.0.md Adds release notes describing adapter architecture and Vue support.
docs/handbook.md Documents Vue 3 + Vuetify 3 support and supported extraction surfaces.
docs/adapters.md Documents adapter contract, selection rules, and normalization conventions.
CONTRIBUTING.md Updates contributing guidelines to reflect the new adapter architecture.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/adapters/vue/extractSlots.ts
Comment thread src/adapters/vue/extractSlots.ts Outdated
Comment thread src/generate.ts Outdated
- extractSlots: model directive `arg` in the template-node shape and only treat
  a `:name`/`v-bind:name` binding as a dynamic slot name. `<slot :foo="bar" />`
  is now correctly a default slot, not skipped. Static `name=""` falls back to
  default. Added regression tests.
- generate: provenance-tag adapter-registry warnings as `[adapter-registry] ...`
  to match fragment/assembler warning formatting.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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