Framework-adapter layer with first-class Vue 3 + Vuetify 3 support - #2
Merged
Conversation
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>
There was a problem hiding this comment.
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 aReactAdapterwrapper 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-sfcas 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.
- 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>
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
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.ts—FrameworkAdapter/AdapterContextcontract (pure, read-only, no side effects).src/adapters/registry.ts—resolveAdapter(): explicitframeworkconfig 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).ReactAdapterwraps the existing extractors in place — same fragments, same precedence, byte-identical golden output.frameworkBindingsis namespaced per adapter (frameworkBindings.react,frameworkBindings.vue).Vue 3 extraction
<script setup>type-baseddefineProps<T>()+withDefaults, runtimedefineProps({...})/defineProps([...]), and Options API (defineComponent/export default, incl.name).defineEmitstype + array forms, Optionsemits) →on<PascalEvent>handler props (update:modelValue→onUpdateModelValue); raw names preserved inframeworkBindings.vue.defineSlots+ template<slot>) →children(default) /slot:<name>(named, namespaced to avoid prop collisions).tags+ bindingguidance.<script>AST;@vue/compiler-sfcis the authoritative SFC/macro parser (compileScriptas aid).Testing
fixtures/vuetify-demogolden validates against the bundled dspack v0.2 schema with zero schema changes.SOURCE_DATE_EPOCH.src/adapters/.Notes for the maintainer
GENERATOR_VERSIONstays0.1.0-alpha.1so the React golden stays byte-identical. The release notes document the release-commit step: bumppackage.json+GENERATOR_VERSIONto0.2.0-alpha.0, then regenerate all goldens sometadata.generatedByupdates in lockstep.See docs/adapters.md for the adapter contract.
🤖 Generated with Claude Code