Skip to content

feat(compiler-sfc,compiler-spatial): add spatial computing support for visionOS#14612

Closed
Amiya167 wants to merge 3 commits intovuejs:mainfrom
Amiya167:feat/spatial-computing-phase1
Closed

feat(compiler-sfc,compiler-spatial): add spatial computing support for visionOS#14612
Amiya167 wants to merge 3 commits intovuejs:mainfrom
Amiya167:feat/spatial-computing-phase1

Conversation

@Amiya167
Copy link

@Amiya167 Amiya167 commented Mar 21, 2026

Summary

Introduce spatial computing compilation support for Vue SFCs, enabling compilation of <template spatial> to native SwiftUI views for visionOS. This PR implements two phases:

Phase 1: SFC Parser (compiler-sfc)

  • Recognize <script setup spatial>, <template spatial>, <style spatial> attributes
  • Add spatial, stylesSpatial fields to SFCDescriptor
  • Validation rules: spatial requires setup, no coexistence with normal <script>
  • Export isSpatialComponent() utility

Phase 2: SwiftUI Compiler (compiler-spatial)

  • New @vue/compiler-spatial package following compiler-ssr two-pass architecture
  • Element mapping: 30 Vue spatial tags → SwiftUI views (<v-stack>VStack, <text>Text, <button>Button, <model3d>Model3D, etc.)
  • Directive compilation: v-if → Swift if/else, v-forForEach, v-modelvm.binding(), v-show.opacity(), spatial gesture directives
  • Scene types: <spatial-window>WindowGroup, <spatial-volume>.windowStyle(.volumetric), <spatial-immersive>ImmersiveSpace
  • Swift codegen: generates complete SwiftUI View structs with VueViewModel bridge
  • Bridge manifest: JSON contract for JS↔Swift IPC communication
  • Re-exported as compileSpatial from @vue/compiler-sfc

Example

<template spatial>
  <spatial-window title="Hello visionOS">
    <v-stack spacing="16">
      <text font="largeTitle">{{ greeting }}</text>
      <button @tap="count++">
        <label>
          <text>Increment</text>
          <sf-symbol name="plus.circle.fill" />
        </label>
      </button>
    </v-stack>
  </spatial-window>
</template>

Compiles to:

struct HelloVisionOS: View {
    @ObservedObject var vm: VueViewModel

    var body: some View {
        WindowGroup("Hello visionOS") {
            VStack(spacing: 16) {
                Text(vm.get("greeting"))
                    .font(.largeTitle)
                Button(action: { vm.emit("count++") }) {
                    Label {
                        Text("Increment")
                        Image(systemName: "plus.circle.fill")
                    }
                }
            }
        }
    }
}

Test plan

  • 10 parser tests in compiler-sfc (spatial attribute parsing, validation errors)
  • 28 compiler tests in compiler-spatial (elements, v-if, v-for, v-model, v-show, full codegen)
  • All 454 existing compiler-sfc tests pass unchanged
  • Manual verification with RFC example templates

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • Full support for spatial components (spatial templates, spatial script-setup and spatial styles)
    • New spatial compiler and public APIs to compile spatial templates and detect spatial components; generates SwiftUI output and a bridge manifest
  • Behavior Changes

    • Spatial styles and spatial script-setup are handled separately from standard assets and compilation flow
  • Bug Fixes / Validation

    • New validations and clearer errors for invalid spatial combinations
  • Tests

    • Extensive new test coverage for spatial parsing, codegen, directives, and error paths

Add `<script setup spatial>` attribute parsing to enable Vue SFC
compilation targeting SwiftUI on visionOS. This is Phase 1 of the
spatial computing initiative (RFC 0000).

Changes:
- SFCBlock: add `spatial` field
- SFCDescriptor: add `spatial` flag and `stylesSpatial` array
- parse(): route `<script setup spatial>` and `<style spatial>` blocks
- createBlock(): recognize `spatial` attribute
- compileScript(): early return for spatial components (defers to
  future @vue/compiler-spatial package)
- Add `isSpatialComponent()` utility
- 10 new tests covering parsing and validation

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link

coderabbitai bot commented Mar 21, 2026

📝 Walkthrough

Walkthrough

Adds spatial SFC support and a new spatial compiler: parses spatial attributes on <template>, <script setup>, and <style>, validates spatial combinations, early-returns compileScript for spatial setup scripts, exposes isSpatialComponent, and introduces a new @vue/compiler-spatial package with transforms and Swift codegen.

Changes

Cohort / File(s) Summary
SFC tests
packages/compiler-sfc/__tests__/parse.spec.ts
Adds tests for spatial parsing, spatial style partitioning, and error cases for invalid spatial combinations and duplicates.
SFC parser & types
packages/compiler-sfc/src/parse.ts
Adds spatial?: boolean on SFCBlock, spatial and stylesSpatial on SFCDescriptor; detects spatial on template/script/style, routes spatial styles to stylesSpatial, emits SyntaxErrors for invalid combos, and includes spatial blocks in source map generation.
Compile flow
packages/compiler-sfc/src/compileScript.ts
When sfc.spatial and sfc.scriptSetup?.spatial are present, compileScript() returns the scriptSetup block early, skipping normal compile steps.
SFC helper & public API
packages/compiler-sfc/src/spatial.ts, packages/compiler-sfc/src/index.ts, packages/compiler-sfc/package.json
Adds isSpatialComponent helper; re-exports spatial compiler API (compileSpatial, SpatialCompilerOptions, SpatialCodegenResult) and adds @vue/compiler-spatial dependency.
New spatial package tests & utils
packages/compiler-spatial/__tests__/*, packages/compiler-spatial/__tests__/utils.ts
Adds extensive Vitest suites and helpers validating spatial codegen (Swift output), element mappings, directives (v-for, v-if, v-model, v-show), and utility wrappers.
Spatial package manifest & license
packages/compiler-spatial/package.json, packages/compiler-spatial/LICENSE
New package manifest for @vue/compiler-spatial and MIT LICENSE file.
Spatial errors & runtime helpers
packages/compiler-spatial/src/errors.ts, packages/compiler-spatial/src/runtimeHelpers.ts
New spatial-specific compiler error types/messages and registered runtime helper symbols for spatial helpers.
Spatial compiler entry & re-exports
packages/compiler-spatial/src/index.ts
New compile entry returning { swift, bridgeManifest, lines }; defines SpatialCompilerOptions/SpatialCodegenResult and re-exports errors and swift codegen utilities.
Swift codegen core
packages/compiler-spatial/src/swiftCodegen.ts
New ELEMENT_MAP, constructor/modifier/style mappings, generateSwiftView, and BridgeManifest creation.
Spatial codegen transform
packages/compiler-spatial/src/spatialCodegenTransform.ts
New transform context and AST traversal producing Swift code lines, handling text, interpolations, conditionals, loops, and error reporting.
Element transform & directives
packages/compiler-spatial/src/transforms/*
Adds spatialProcessElement, spatialTransformFor/spatialProcessFor, spatialTransformIf/spatialProcessIf, spatialTransformModel, and spatialTransformShow implementing element mapping, bindings, events, gestures, v-for, v-if, v-model, and v-show handling.

Sequence Diagram(s)

mermaid
sequenceDiagram
rect rgba(100,149,237,0.5)
participant Dev as Developer (SFC template)
end
rect rgba(50,205,50,0.5)
participant SFC as SFC Parser (parse.ts)
end
rect rgba(255,165,0,0.5)
participant SFC_C as compileScript (compiler-sfc)
end
rect rgba(218,112,214,0.5)
participant SPAT as Spatial Compiler (@vue/compiler-spatial)
end
rect rgba(240,128,128,0.5)
participant SWIFT as Swift Codegen (swiftCodegen)
end

Dev->>SFC: submit SFC (template/script/style)
SFC-->>SFC: detect `spatial` flags, build descriptor
SFC->>SFC_C: pass descriptor
alt descriptor.spatial && scriptSetup.spatial
    SFC_C-->>Dev: early return scriptSetup (skip normal compile)
    SFC_C->>SPAT: forward template to spatial compile path
else
    SFC_C->>SPAT: use normal compile path (non-spatial)
end
SPAT->>SPAT: transforms (v-if, v-for, v-model, element processing)
SPAT->>SWIFT: produce body lines & bridge manifest
SWIFT-->>Dev: return { swift, bridgeManifest, lines }

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

scope: compiler, version: minor

Suggested reviewers

  • sxzz
  • baiwusanyu-c
  • KazariEX

Poem

🐰 I hopped through parse and code tonight,

flags of spatial glowing bright,
transforms danced and Swift lines grew,
bridge manifest and tests in view.
Thump-thump — a new compiler bite!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately describes the main feature addition: spatial computing support for visionOS. It clearly summarizes the primary change across both compiler-sfc and compiler-spatial packages.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for vue-next-template-explorer failed. Why did it fail? →

Name Link
🔨 Latest commit 1b447e5
🔍 Latest deploy log https://app.netlify.com/projects/vue-next-template-explorer/deploys/69be81fe3b8e980008d1b1df

@netlify
Copy link

netlify bot commented Mar 21, 2026

Deploy Preview for vue-sfc-playground failed. Why did it fail? →

Name Link
🔨 Latest commit 1b447e5
🔍 Latest deploy log https://app.netlify.com/projects/vue-sfc-playground/deploys/69be81feffebdd00084b2897

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🧹 Nitpick comments (2)
packages/compiler-sfc/src/parse.ts (2)

354-357: slotted check does not include stylesSpatial.

Similar to the CSS vars issue, the :slotted() detection only checks descriptor.styles. If scoped spatial styles can use :slotted(), this check should include stylesSpatial. However, if spatial styles compile entirely differently (to SwiftUI), this may be intentional.

Consider documenting the design decision or extending the check if applicable.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-sfc/src/parse.ts` around lines 354 - 357, The slotted
detection only inspects descriptor.styles and thus misses scoped spatial styles;
update the check that sets descriptor.slotted to include
descriptor.stylesSpatial as well (e.g., iterate both descriptor.styles and
descriptor.stylesSpatial or concat them) by testing s.scoped &&
slottedRE.test(s.content) for entries in both collections (referencing
slottedRE, descriptor.slotted, descriptor.styles, descriptor.stylesSpatial, and
the s.scoped/s.content predicate), or if spatial styles intentionally differ,
add a comment documenting that design decision instead of changing the logic.

350-351: Consider adding a comment clarifying why parseCssVars intentionally omits stylesSpatial blocks.

The concern is accurate: parseCssVars only iterates over sfc.styles and excludes stylesSpatial. However, this is intentional design. Spatial styles (marked with <style spatial>) compile to SwiftUI view modifiers rather than CSS, as documented in the SFCDescriptor interface. Since SwiftUI modifiers don't use CSS v-bind() expressions, processing them in parseCssVars would be unnecessary and semantically incorrect. The actual compilation of spatial styles is delegated to @vue/compiler-spatial.

A brief inline comment at line 350 could improve clarity for future maintainers:

// parse CSS vars (spatial styles use SwiftUI modifiers instead of CSS)
descriptor.cssVars = parseCssVars(descriptor)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-sfc/src/parse.ts` around lines 350 - 351, Add a short
inline comment above the existing assignment to explain why parseCssVars only
processes descriptor.styles and intentionally omits stylesSpatial: note that
styles with the "spatial" flag compile to SwiftUI view modifiers (handled by
`@vue/compiler-spatial`) rather than CSS, so they don't contain CSS v-bind()
expressions and should not be processed by parseCssVars; update the line with
descriptor.cssVars = parseCssVars(descriptor) to include that brief
clarification.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/compiler-sfc/src/parse.ts`:
- Around line 214-234: The variables declared in the case 'script' branch
(scriptBlock, isSetup, isSpatial) leak into other switch cases; wrap the entire
case 'script' body in a block (add { ... } after case 'script':) to create a
local scope for those declarations so they cannot be accessed by other cases;
adjust control flow (break statements) to remain inside that new block and keep
existing uses of scriptBlock/isSetup/isSpatial (and assignments to
descriptor.scriptSetup / descriptor.spatial and pushes to errors) unchanged.

---

Nitpick comments:
In `@packages/compiler-sfc/src/parse.ts`:
- Around line 354-357: The slotted detection only inspects descriptor.styles and
thus misses scoped spatial styles; update the check that sets descriptor.slotted
to include descriptor.stylesSpatial as well (e.g., iterate both
descriptor.styles and descriptor.stylesSpatial or concat them) by testing
s.scoped && slottedRE.test(s.content) for entries in both collections
(referencing slottedRE, descriptor.slotted, descriptor.styles,
descriptor.stylesSpatial, and the s.scoped/s.content predicate), or if spatial
styles intentionally differ, add a comment documenting that design decision
instead of changing the logic.
- Around line 350-351: Add a short inline comment above the existing assignment
to explain why parseCssVars only processes descriptor.styles and intentionally
omits stylesSpatial: note that styles with the "spatial" flag compile to SwiftUI
view modifiers (handled by `@vue/compiler-spatial`) rather than CSS, so they don't
contain CSS v-bind() expressions and should not be processed by parseCssVars;
update the line with descriptor.cssVars = parseCssVars(descriptor) to include
that brief clarification.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 1f88850c-ae52-42d5-b94f-45258dfc820f

📥 Commits

Reviewing files that changed from the base of the PR and between d61d803 and 1b447e5.

📒 Files selected for processing (6)
  • docs/spatial-computing-dev.md
  • packages/compiler-sfc/__tests__/parse.spec.ts
  • packages/compiler-sfc/src/compileScript.ts
  • packages/compiler-sfc/src/index.ts
  • packages/compiler-sfc/src/parse.ts
  • packages/compiler-sfc/src/spatial.ts

- Wrap `case 'script'` and `case 'style'` in block scope to prevent
  variable leakage across switch clauses (CodeRabbit feedback)
- Remove docs/spatial-computing-dev.md from commit — its `export enum`
  code examples trigger scanEnums() which tries to Babel-parse .md files

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/compiler-sfc/src/parse.ts`:
- Around line 307-317: The current check only triggers when descriptor.template
exists, so a standalone `<script setup spatial>` slips through; update the
condition to reject whenever descriptor.scriptSetup?.spatial is true and either
descriptor.template is missing or descriptor.template.spatial is false. In other
words, replace the existing conditional with one that tests
descriptor.scriptSetup?.spatial && (!descriptor.template ||
!descriptor.template.spatial) and keep the same errors.push(new
SyntaxError(...)) logic to report the missing/incorrect <template spatial>
invariant.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 07b69d25-3d2d-4e66-b7c6-db2b442b02fb

📥 Commits

Reviewing files that changed from the base of the PR and between 1b447e5 and 505aab6.

📒 Files selected for processing (1)
  • packages/compiler-sfc/src/parse.ts

Comment on lines +307 to +317
if (
descriptor.template &&
!descriptor.template.spatial &&
descriptor.scriptSetup?.spatial
) {
errors.push(
new SyntaxError(
`<script setup spatial> requires <template spatial>. ` +
`Add the "spatial" attribute to the <template> block.`,
),
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Reject <script setup spatial> when the template is missing.

Line 308 only fires this check when descriptor.template exists, so <script setup spatial> without any <template> currently parses without the new error. That leaves the main spatial invariant unenforced for one of the invalid shapes this PR is supposed to catch.

🛠️ Suggested change
-    if (
-      descriptor.template &&
-      !descriptor.template.spatial &&
-      descriptor.scriptSetup?.spatial
-    ) {
+    if (descriptor.scriptSetup?.spatial && !descriptor.template?.spatial) {
       errors.push(
         new SyntaxError(
           `<script setup spatial> requires <template spatial>. ` +
             `Add the "spatial" attribute to the <template> block.`,
         ),
       )
     }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (
descriptor.template &&
!descriptor.template.spatial &&
descriptor.scriptSetup?.spatial
) {
errors.push(
new SyntaxError(
`<script setup spatial> requires <template spatial>. ` +
`Add the "spatial" attribute to the <template> block.`,
),
)
if (descriptor.scriptSetup?.spatial && !descriptor.template?.spatial) {
errors.push(
new SyntaxError(
`<script setup spatial> requires <template spatial>. ` +
`Add the "spatial" attribute to the <template> block.`,
),
)
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-sfc/src/parse.ts` around lines 307 - 317, The current check
only triggers when descriptor.template exists, so a standalone `<script setup
spatial>` slips through; update the condition to reject whenever
descriptor.scriptSetup?.spatial is true and either descriptor.template is
missing or descriptor.template.spatial is false. In other words, replace the
existing conditional with one that tests descriptor.scriptSetup?.spatial &&
(!descriptor.template || !descriptor.template.spatial) and keep the same
errors.push(new SyntaxError(...)) logic to report the missing/incorrect
<template spatial> invariant.

… codegen

Add the compiler-spatial package that compiles Vue spatial templates into
SwiftUI source code, following the same two-pass architecture as compiler-ssr.

- Element mapping: 30 Vue spatial tags → SwiftUI views (VStack, Text, Button, etc.)
- Directive compilation: v-if → Swift if/else, v-for → ForEach, v-model → vm.binding(),
  v-show → .opacity(), spatial gesture directives → SwiftUI gestures
- Style mapping: CSS-like spatial properties → SwiftUI view modifiers
- Swift codegen: generates complete SwiftUI View structs with VueViewModel bridge
- Bridge manifest: JSON contract for JS↔Swift IPC communication
- Wire compiler-sfc to re-export compileSpatial from compiler-spatial
- 28 tests covering elements, directives, codegen, and RFC examples

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@Amiya167 Amiya167 changed the title feat(compiler-sfc): add spatial computing support for visionOS feat(compiler-sfc,compiler-spatial): add spatial computing support for visionOS Mar 22, 2026
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (2)
packages/compiler-spatial/__tests__/spatialElement.spec.ts (1)

67-74: Align the Button test with its name by asserting child rendering.

This case says “with @tap and children” but currently validates only the action closure. Add an assertion for Text("Click") to lock in child emission behavior.

Suggested addition
   test('Button with `@tap` and children', () => {
     const lines = getSwiftLines(
       `<button `@tap`="increment"><text>Click</text></button>`,
     )
     expect(
       lines.some(l => l.includes('Button(action: { vm.emit("increment") })')),
     ).toBe(true)
+    expect(lines.some(l => l.includes('Text("Click")'))).toBe(true)
   })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/__tests__/spatialElement.spec.ts` around lines 67 -
74, The test "Button with `@tap` and children" currently only asserts the action
closure; update the test to also assert that child rendering is emitted by
checking for Text("Click") in the output from getSwiftLines — use the existing
lines variable (from getSwiftLines(...)) and add an expect that lines.some(l =>
l.includes('Text("Click")')) or equivalent to ensure child emission is validated
alongside Button(action: { vm.emit("increment") }).
packages/compiler-spatial/__tests__/spatialVIf.spec.ts (1)

22-29: Strengthen the v-else-if / v-else test with branch content assertions.

Current checks verify control flow tokens, but not rendered branch bodies. Adding Text("B") / Text("C") assertions will reduce false positives in regressions.

Suggested test hardening
   test('v-if with v-else-if and v-else', () => {
     const lines = getSwiftLines(
       `<text v-if="a">A</text><text v-else-if="b">B</text><text v-else>C</text>`,
     )
     expect(lines.some(l => l.includes('if vm.get("a")'))).toBe(true)
     expect(lines.some(l => l.includes('} else if vm.get("b")'))).toBe(true)
     expect(lines.some(l => l.includes('} else {'))).toBe(true)
+    expect(lines.some(l => l.includes('Text("B")'))).toBe(true)
+    expect(lines.some(l => l.includes('Text("C")'))).toBe(true)
   })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/__tests__/spatialVIf.spec.ts` around lines 22 - 29,
Update the test 'v-if with v-else-if and v-else' so it not only checks
control-flow tokens but also asserts that the branch bodies are rendered: after
calling getSwiftLines(...) verify that generated lines include the rendered
branch contents like Text("B") for the v-else-if branch and Text("C") for the
v-else branch (in addition to the existing checks for if vm.get("a"), } else if
vm.get("b"), and } else {). This change targets the test case in
packages/compiler-spatial/__tests__/spatialVIf.spec.ts and ensures the output
contains the expected Text("B") and Text("C") strings.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@packages/compiler-spatial/src/spatialCodegenTransform.ts`:
- Around line 18-25: The transform currently discards the collected metadata
(events, bindings, spatialGestures) in SpatialTransformContext when returning
from spatialCodegenTransform; update spatialCodegenTransform to include and
return those context fields (events, bindings, spatialGestures) alongside lines
so the caller can build a BridgeManifest; locate the SpatialTransformContext
interface and the spatialCodegenTransform function (and the return at the second
instance around the lines noted) and modify the return value to propagate the
Map<string,string> events, string[] bindings and string[] spatialGestures
instead of only returning lines.
- Around line 112-121: The default clauses in the switch inside
spatialCodegenTransform.ts declare a variable (_exhaustiveCheck) without a
block, which risks hoisting and binding conflicts; wrap each default: case body
in a block ({ ... }) so the const _exhaustiveCheck: never = child and the
context.onError(...) call are scoped to the case. Update both occurrences
referenced by the code that calls
context.onError(createSpatialCompilerError(SpatialErrorCodes.X_SPATIAL_INVALID_AST_NODE,
(child as any).loc)) and the subsequent const _exhaustiveCheck declarations to
be inside their own {} blocks.

In `@packages/compiler-spatial/src/transforms/spatialTransformElement.ts`:
- Around line 165-183: processDirectiveProp currently stores v-bind results only
in CONSTRUCTOR_PROPS/MODIFIER_PROPS (via constructorArgs and modifiers) so
downstream emitters that call findAttr lose bound values; update the handling so
bound attrs are discoverable by findAttr or provide a shared resolver.
Specifically, in processDirectiveProp (the code branch checking prop.name ===
'bind', isStaticExp, getExpContent) make bound values available as attribute
equivalents (e.g., add a synthesized prop entry onto the node.props/attrs or a
sidecar map) instead of only pushing into constructorArgs/modifiers, and
implement a single helper resolveStaticOrBoundAttr(name) that findAttr and all
specialized emitters call (replace direct findAttr uses) to return either the
static value or the bound expression from
CONSTRUCTOR_PROPS/MODIFIER_PROPS/constructorArgs/modifiers; ensure symbols
referenced include processDirectiveProp, CONSTRUCTOR_PROPS, MODIFIER_PROPS,
findAttr, constructorArgs, modifiers, getExpContent so emitters like
WindowGroup/ImmersiveSpace consume the bound inputs.

In `@packages/compiler-spatial/src/transforms/spatialVFor.ts`:
- Around line 39-43: The ForEach code creates a Swift local alias (the
`${valueName}` closure param) but the expression emitter still emits global
lookups via vm.get/ vm.getArray so loop body expressions never reference the
local; to fix, add a loop-local binding when emitting the ForEach (in
spatialVFor.ts around ForEach(vm.getArray(...), id: \\.${keyExpr}) {
${valueName} in and processChildren(node, context)) and update the expression
emitter logic (where vm.get is produced in spatialCodegenTransform.ts and used
by spatialVIf.ts and spatialTransformElement.ts) to consult the current codegen
scope/locals before emitting a vm.get — if a local binding for the root
identifier exists emit a direct local access (the `${valueName}`/property
lookup) instead of vm.get("..."); ensure the binding is pushed before calling
processChildren and popped after.

In `@packages/compiler-spatial/src/transforms/spatialVShow.ts`:
- Around line 19-22: The error report for a missing v-show expression omits the
directive location; update the call inside the if (!dir.exp) block so
context.onError invokes createDOMCompilerError with the location: pass dir.loc
as the second argument along with DOMErrorCodes.X_V_SHOW_NO_EXPRESSION (the same
pattern used in packages/compiler-dom/src/transforms/vShow.ts), ensuring the
call from context.onError(createDOMCompilerError(...)) includes the location to
improve diagnostic precision.

---

Nitpick comments:
In `@packages/compiler-spatial/__tests__/spatialElement.spec.ts`:
- Around line 67-74: The test "Button with `@tap` and children" currently only
asserts the action closure; update the test to also assert that child rendering
is emitted by checking for Text("Click") in the output from getSwiftLines — use
the existing lines variable (from getSwiftLines(...)) and add an expect that
lines.some(l => l.includes('Text("Click")')) or equivalent to ensure child
emission is validated alongside Button(action: { vm.emit("increment") }).

In `@packages/compiler-spatial/__tests__/spatialVIf.spec.ts`:
- Around line 22-29: Update the test 'v-if with v-else-if and v-else' so it not
only checks control-flow tokens but also asserts that the branch bodies are
rendered: after calling getSwiftLines(...) verify that generated lines include
the rendered branch contents like Text("B") for the v-else-if branch and
Text("C") for the v-else branch (in addition to the existing checks for if
vm.get("a"), } else if vm.get("b"), and } else {). This change targets the test
case in packages/compiler-spatial/__tests__/spatialVIf.spec.ts and ensures the
output contains the expected Text("B") and Text("C") strings.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: c6271979-2daa-4068-8f7b-f5a73b09c2bd

📥 Commits

Reviewing files that changed from the base of the PR and between 505aab6 and 2ef45b1.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (21)
  • packages/compiler-sfc/package.json
  • packages/compiler-sfc/src/index.ts
  • packages/compiler-spatial/LICENSE
  • packages/compiler-spatial/__tests__/spatialCodegen.spec.ts
  • packages/compiler-spatial/__tests__/spatialElement.spec.ts
  • packages/compiler-spatial/__tests__/spatialVFor.spec.ts
  • packages/compiler-spatial/__tests__/spatialVIf.spec.ts
  • packages/compiler-spatial/__tests__/spatialVModel.spec.ts
  • packages/compiler-spatial/__tests__/spatialVShow.spec.ts
  • packages/compiler-spatial/__tests__/utils.ts
  • packages/compiler-spatial/package.json
  • packages/compiler-spatial/src/errors.ts
  • packages/compiler-spatial/src/index.ts
  • packages/compiler-spatial/src/runtimeHelpers.ts
  • packages/compiler-spatial/src/spatialCodegenTransform.ts
  • packages/compiler-spatial/src/swiftCodegen.ts
  • packages/compiler-spatial/src/transforms/spatialTransformElement.ts
  • packages/compiler-spatial/src/transforms/spatialVFor.ts
  • packages/compiler-spatial/src/transforms/spatialVIf.ts
  • packages/compiler-spatial/src/transforms/spatialVModel.ts
  • packages/compiler-spatial/src/transforms/spatialVShow.ts
✅ Files skipped from review due to trivial changes (5)
  • packages/compiler-spatial/LICENSE
  • packages/compiler-sfc/package.json
  • packages/compiler-spatial/package.json
  • packages/compiler-spatial/tests/spatialCodegen.spec.ts
  • packages/compiler-spatial/tests/utils.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/compiler-sfc/src/index.ts

Comment on lines +18 to +25
export interface SpatialTransformContext {
root: RootNode
options: CompilerOptions
lines: string[]
indentLevel: number
events: Map<string, string>
bindings: string[]
spatialGestures: string[]
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Return the collected bridge metadata from codegen.

This context already tracks events, bindings, and spatialGestures, but spatialCodegenTransform() drops everything except lines. That leaves the caller no way to build a non-empty BridgeManifest, so templates using @tap, v-model, or spatial gesture directives will still surface an empty manifest.

Also applies to: 66-72

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/src/spatialCodegenTransform.ts` around lines 18 -
25, The transform currently discards the collected metadata (events, bindings,
spatialGestures) in SpatialTransformContext when returning from
spatialCodegenTransform; update spatialCodegenTransform to include and return
those context fields (events, bindings, spatialGestures) alongside lines so the
caller can build a BridgeManifest; locate the SpatialTransformContext interface
and the spatialCodegenTransform function (and the return at the second instance
around the lines noted) and modify the return value to propagate the
Map<string,string> events, string[] bindings and string[] spatialGestures
instead of only returning lines.

Comment on lines +112 to +121
default:
context.onError(
createSpatialCompilerError(
SpatialErrorCodes.X_SPATIAL_INVALID_AST_NODE,
(child as any).loc,
),
)
// make sure we exhaust all possible types
const _exhaustiveCheck: never = child
return _exhaustiveCheck
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

wc -l packages/compiler-spatial/src/spatialCodegenTransform.ts

Repository: vuejs/core

Length of output: 114


🏁 Script executed:

sed -n '100,170p' packages/compiler-spatial/src/spatialCodegenTransform.ts | cat -n

Repository: vuejs/core

Length of output: 2702


Wrap default: clauses in blocks.

Biome's noSwitchDeclarations rule is applicable here: variable declarations in switch cases without block wrappers are hoisted to the switch scope, creating potential binding conflicts. Both occurrences (lines 112–121 and 150–159) need to be wrapped.

Suggested fix
-          default:
+          default: {
             context.onError(
               createSpatialCompilerError(
                 SpatialErrorCodes.X_SPATIAL_INVALID_AST_NODE,
                 (child as any).loc,
               ),
             )
             // make sure we exhaust all possible types
             const _exhaustiveCheck: never = child
             return _exhaustiveCheck
+          }
@@
-      default:
+      default: {
         context.onError(
           createSpatialCompilerError(
             SpatialErrorCodes.X_SPATIAL_INVALID_AST_NODE,
             (child as any).loc,
           ),
         )
         // make sure we exhaust all possible types
         const _exhaustiveCheck2: never = child
         return _exhaustiveCheck2
+      }
🧰 Tools
🪛 Biome (2.4.7)

[error] 120-120: Other switch clauses can erroneously access this declaration.
Wrap the declaration in a block to restrict its access to the switch clause.

(lint/correctness/noSwitchDeclarations)

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/src/spatialCodegenTransform.ts` around lines 112 -
121, The default clauses in the switch inside spatialCodegenTransform.ts declare
a variable (_exhaustiveCheck) without a block, which risks hoisting and binding
conflicts; wrap each default: case body in a block ({ ... }) so the const
_exhaustiveCheck: never = child and the context.onError(...) call are scoped to
the case. Update both occurrences referenced by the code that calls
context.onError(createSpatialCompilerError(SpatialErrorCodes.X_SPATIAL_INVALID_AST_NODE,
(child as any).loc)) and the subsequent const _exhaustiveCheck declarations to
be inside their own {} blocks.

Comment on lines +165 to +183
if (prop.name === 'bind' && prop.arg && isStaticExp(prop.arg) && prop.exp) {
const attrName = prop.arg.content
const expr = getExpContent(prop.exp)

const modifierFn = MODIFIER_PROPS[attrName]
if (modifierFn) {
modifiers.push(modifierFn(`vm.get("${expr}")`))
return
}

const constructorPropsMap = CONSTRUCTOR_PROPS[swiftView] || {}
if (attrName in constructorPropsMap) {
const swiftParam = constructorPropsMap[attrName]
if (swiftParam) {
constructorArgs.push(`${swiftParam}: vm.get("${expr}")`)
} else {
constructorArgs.push(`vm.get("${expr}")`)
}
}
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Dynamic element attrs are dropped for the specialized emitters.

processDirectiveProp() only carries v-bind values through CONSTRUCTOR_PROPS/MODIFIER_PROPS, but these emitters later read only static attrs via findAttr(). That means :src, :name, :placeholder, :title, and :id collapse to empty strings, and even the constructorArgs collected for WindowGroup/ImmersiveSpace are ignored because those emitters never consume them. A shared "static-or-bound attr" resolver would avoid losing these inputs.

Also applies to: 279-315, 388-429

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/src/transforms/spatialTransformElement.ts` around
lines 165 - 183, processDirectiveProp currently stores v-bind results only in
CONSTRUCTOR_PROPS/MODIFIER_PROPS (via constructorArgs and modifiers) so
downstream emitters that call findAttr lose bound values; update the handling so
bound attrs are discoverable by findAttr or provide a shared resolver.
Specifically, in processDirectiveProp (the code branch checking prop.name ===
'bind', isStaticExp, getExpContent) make bound values available as attribute
equivalents (e.g., add a synthesized prop entry onto the node.props/attrs or a
sidecar map) instead of only pushing into constructorArgs/modifiers, and
implement a single helper resolveStaticOrBoundAttr(name) that findAttr and all
specialized emitters call (replace direct findAttr uses) to return either the
static value or the bound expression from
CONSTRUCTOR_PROPS/MODIFIER_PROPS/constructorArgs/modifiers; ensure symbols
referenced include processDirectiveProp, CONSTRUCTOR_PROPS, MODIFIER_PROPS,
findAttr, constructorArgs, modifiers, getExpContent so emitters like
WindowGroup/ImmersiveSpace consume the bound inputs.

Comment on lines +31 to +40
// Check for :key on the child
const keyAlias = node.keyAlias
const keyExpr = keyAlias
? typeof keyAlias !== 'string' && (keyAlias as any).content
? (keyAlias as any).content
: 'id'
: 'id'

context.pushLine(
`ForEach(vm.getArray("${sourceExpr}"), id: \\.${keyExpr}) { ${valueName} in`,
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -e
fd 'ast\.ts$|vFor\.ts$' packages | xargs rg -n -C4 'interface ForNode|keyAlias|objectIndexAlias|findProp\(|keyProp'

Repository: vuejs/core

Length of output: 9503


🏁 Script executed:

cat -n packages/compiler-spatial/src/transforms/spatialVFor.ts | head -100

Repository: vuejs/core

Length of output: 1651


🏁 Script executed:

rg -n "findProp|:key|keyProp" packages/compiler-spatial/src/transforms/

Repository: vuejs/core

Length of output: 145


🏁 Script executed:

rg -n "X_SPATIAL_MISSING_KEY_IN_FOR" packages/compiler-spatial/

Repository: vuejs/core

Length of output: 305


🏁 Script executed:

rg -n "X_SPATIAL_MISSING_KEY_IN_FOR" packages/compiler-spatial/ -A 3 -B 3

Repository: vuejs/core

Length of output: 1189


🏁 Script executed:

# Search for findProp usage in compiler-spatial to see if :key binding is extracted elsewhere
rg -n "findProp" packages/compiler-spatial/

Repository: vuejs/core

Length of output: 36


🏁 Script executed:

# Check how compiler-dom/core extracts :key from child elements in v-for
rg -n "findProp.*key" packages/compiler-core/src/transforms/vFor.ts | head -20

Repository: vuejs/core

Length of output: 162


🏁 Script executed:

# Search for any key validation or error emission in compiler-spatial
rg -n "createCompilerError|onError" packages/compiler-spatial/src/

Repository: vuejs/core

Length of output: 1006


🏁 Script executed:

# Check if there's a ForNode children inspection that should look for :key
rg -n "node\.children" packages/compiler-spatial/src/transforms/

Repository: vuejs/core

Length of output: 1170


🏁 Script executed:

# Check if X_SPATIAL_MISSING_KEY_IN_FOR is ever emitted
rg -rn "X_SPATIAL_MISSING_KEY_IN_FOR" packages/compiler-spatial/ --type ts

Repository: vuejs/core

Length of output: 245


🏁 Script executed:

# Check the full spatialVFor.ts file to see if there's any other key handling
cat -n packages/compiler-spatial/src/transforms/spatialVFor.ts

Repository: vuejs/core

Length of output: 1651


🏁 Script executed:

# Check spatialCodegenTransform.ts to see processChildren and overall context
rg -n "processChildren\|processFor" packages/compiler-spatial/src/spatialCodegenTransform.ts -A 5 -B 5

Repository: vuejs/core

Length of output: 36


🏁 Script executed:

# Check if there are any tests that might show expected behavior
find packages/compiler-spatial -name "*.spec.ts" -o -name "*.test.ts" | xargs rg -l "spatialProcessFor\|spatialVFor" 2>/dev/null || echo "No test files found"

Repository: vuejs/core

Length of output: 73


🏁 Script executed:

# Search for any validation logic that might check for :key in ForNode children
rg -n "node\.children" packages/compiler-spatial/src/transforms/spatialVFor.ts -A 10 -B 2

Repository: vuejs/core

Length of output: 36


🏁 Script executed:

# Verify: does compiler-spatial have any logic to validate/extract :key from child elements?
cat packages/compiler-spatial/src/transforms/spatialVFor.ts | grep -A 50 "spatialProcessFor"

Repository: vuejs/core

Length of output: 887


🏁 Script executed:

# Let's look at how compiler-dom's findProp is defined/exported
rg -n "export.*findProp\|function findProp" packages/compiler-core/src/ -A 3

Repository: vuejs/core

Length of output: 36


🏁 Script executed:

# Check if spatialVFor imports findProp and if it should be using it
head -15 packages/compiler-spatial/src/transforms/spatialVFor.ts

Repository: vuejs/core

Length of output: 455


🏁 Script executed:

# Verify the comment is misleading: check what node.children would contain
rg -n "node.children" packages/compiler-core/src/transforms/vFor.ts -B 2 -A 2 | head -30

Repository: vuejs/core

Length of output: 939


🏁 Script executed:

# Let's see how compiler-dom exports findProp and related functions
rg -n "^export.*findProp" packages/compiler-core/src/

Repository: vuejs/core

Length of output: 119


🏁 Script executed:

# Check what imports are available from compiler-dom in spatialVFor.ts
node -e "
const path = require('path');
const fs = require('fs');
const file = fs.readFileSync('packages/compiler-spatial/src/transforms/spatialVFor.ts', 'utf8');
console.log(file.split('\n').slice(0, 15).join('\n'));
"

Repository: vuejs/core

Length of output: 455


🏁 Script executed:

# Verify: Is findProp exported from compiler-dom?
rg -n "export.*findProp\|export {.*findProp" packages/compiler-dom/index.ts packages/compiler-core/src/

Repository: vuejs/core

Length of output: 198


🏁 Script executed:

# Check if findProp is exported from compiler-dom
rg -n "findProp" packages/compiler-dom/index.ts

Repository: vuejs/core

Length of output: 124


🏁 Script executed:

# Check the full export list from compiler-dom
cat packages/compiler-dom/index.ts | grep -A 100 "export"

Repository: vuejs/core

Length of output: 116


🏁 Script executed:

# Let's understand the correct behavior: check what node.children contains in a ForNode
rg -n "children:" packages/compiler-core/src/ast.ts | grep -i for -A 5 -B 5

Repository: vuejs/core

Length of output: 324


🏁 Script executed:

# Check the ForNode interface definition
rg -n "interface ForNode" packages/compiler-core/src/ast.ts -A 10

Repository: vuejs/core

Length of output: 407


🏁 Script executed:

# Let's look at how compiler-core validates or handles :key in v-for
rg -n "keyProp\|X_V_FOR.*KEY" packages/compiler-core/src/transforms/vFor.ts | head -20

Repository: vuejs/core

Length of output: 36


🏁 Script executed:

# Now let's check if there's any :key extraction logic we should be doing in spatial
cat packages/compiler-core/src/transforms/vFor.ts | sed -n '60,85p'

Repository: vuejs/core

Length of output: 907


🏁 Script executed:

# Check what is exported from compiler-dom
fd "index\\.ts$" packages/compiler-dom/dist/ | head -5

Repository: vuejs/core

Length of output: 168


🏁 Script executed:

# Find the main entry point for compiler-dom
ls -la packages/compiler-dom/

Repository: vuejs/core

Length of output: 521


🏁 Script executed:

# Check if findProp is exported from compiler-dom package
rg -n "findProp" packages/compiler-dom/

Repository: vuejs/core

Length of output: 206


🏁 Script executed:

# Verify the imports available from `@vue/compiler-dom`
cat packages/compiler-dom/package.json | grep -A 5 "\"exports\""

Repository: vuejs/core

Length of output: 248


🏁 Script executed:

# Check the compiler-dom index.js to see what's exported
cat packages/compiler-dom/index.js

Repository: vuejs/core

Length of output: 242


🏁 Script executed:

# Check if findProp is re-exported from compiler-core in compiler-dom
rg -n "findProp" packages/compiler-dom/src/ -l

Repository: vuejs/core

Length of output: 100


🏁 Script executed:

# Look at the compiler-dom src structure
ls -la packages/compiler-dom/src/

Repository: vuejs/core

Length of output: 609


🏁 Script executed:

# Check what compiler-dom exports
cat packages/compiler-dom/src/index.ts

Repository: vuejs/core

Length of output: 2456


🏁 Script executed:

# Check the usage pattern: if spatialVFor imports from `@vue/compiler-dom`, what can it access?
rg -n "export.*from.*compiler-core" packages/compiler-dom/src/index.ts

Repository: vuejs/core

Length of output: 91


Extract the actual :key binding from child elements instead of using node.keyAlias.

node.keyAlias is the second loop alias from v-for="(value, key) in source", not the rendered child's :key binding. The code silently defaults to \.id without ever inspecting actual key bindings on the elements. Use findProp(node, 'key') to extract the rendered child's :key binding, similar to how compiler-core/vFor.ts does it. Currently, SpatialErrorCodes.X_SPATIAL_MISSING_KEY_IN_FOR in packages/compiler-spatial/src/errors.ts is unreachable.

Comment on lines +39 to +43
context.pushLine(
`ForEach(vm.getArray("${sourceExpr}"), id: \\.${keyExpr}) { ${valueName} in`,
)
context.indent()
processChildren(node, context)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

The ForEach alias never becomes usable inside the generated body.

This introduces a local Swift alias ({ ${valueName} in), but the downstream emitters still turn expressions into global lookups like vm.get("item.name") in packages/compiler-spatial/src/spatialCodegenTransform.ts:129-132, packages/compiler-spatial/src/transforms/spatialVIf.ts:28-35, and packages/compiler-spatial/src/transforms/spatialTransformElement.ts:165-183. As written, {{ item.name }}, v-if="item.visible", and :title="item.name" inside the loop will never read the local item.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/src/transforms/spatialVFor.ts` around lines 39 -
43, The ForEach code creates a Swift local alias (the `${valueName}` closure
param) but the expression emitter still emits global lookups via vm.get/
vm.getArray so loop body expressions never reference the local; to fix, add a
loop-local binding when emitting the ForEach (in spatialVFor.ts around
ForEach(vm.getArray(...), id: \\.${keyExpr}) { ${valueName} in and
processChildren(node, context)) and update the expression emitter logic (where
vm.get is produced in spatialCodegenTransform.ts and used by spatialVIf.ts and
spatialTransformElement.ts) to consult the current codegen scope/locals before
emitting a vm.get — if a local binding for the root identifier exists emit a
direct local access (the `${valueName}`/property lookup) instead of
vm.get("..."); ensure the binding is pushed before calling processChildren and
popped after.

Comment on lines +19 to +22
if (!dir.exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION),
)
Copy link

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify current repository patterns for DOM compiler error location propagation.
rg -nP --type=ts -C2 'createDOMCompilerError\('
rg -nP --type=ts -C2 'X_V_SHOW_NO_EXPRESSION'

Repository: vuejs/core

Length of output: 9688


Pass directive location when reporting missing v-show expressions.

The call to createDOMCompilerError() on line 21 omits the location parameter. Unlike the similar pattern in packages/compiler-dom/src/transforms/vShow.ts which passes loc, this reduces error diagnostic precision. Add dir.loc as the second argument to match established patterns.

Proposed fix
   if (!dir.exp) {
     context.onError(
-      createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION),
+      createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, dir.loc),
     )
   }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (!dir.exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION),
)
if (!dir.exp) {
context.onError(
createDOMCompilerError(DOMErrorCodes.X_V_SHOW_NO_EXPRESSION, dir.loc),
)
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/compiler-spatial/src/transforms/spatialVShow.ts` around lines 19 -
22, The error report for a missing v-show expression omits the directive
location; update the call inside the if (!dir.exp) block so context.onError
invokes createDOMCompilerError with the location: pass dir.loc as the second
argument along with DOMErrorCodes.X_V_SHOW_NO_EXPRESSION (the same pattern used
in packages/compiler-dom/src/transforms/vShow.ts), ensuring the call from
context.onError(createDOMCompilerError(...)) includes the location to improve
diagnostic precision.

@edison1105
Copy link
Member

Thank you for your enthusiasm for Vue visionOS support! This is an interesting idea, but we don't think platform-specific compilers like this belong in the core repository. For the spatial/visionOS use case, a better approach would be to maintain it as an independent community package (e.g. vue-spatial or @visionos/vue), which allows for a more flexible release cadence without adding maintenance overhead to Core.

If you find that core needs to provide certain extension points or API support during your implementation (e.g. extensibility of SFCDescriptor, handling of custom block types, etc.), feel free to open a separate issue to discuss — we are happy to provide the necessary support on the Core side.

@Amiya167
Copy link
Author

Hello @edison1105 , thank you for your interest in the Zixiao Labs Industries team. Indeed, we feel that including platform-specific compilers in the core repository might increase the burden on Evan You and the team, and could potentially lead to vendor lock-in (we don't want to become the next Vercel or Next.js). Therefore, the main repository will only contain a minimal number of hooks; compilation, packaging, and Apple's JavaScriptCore-specific handling will be handled by our Nasti (https://github.com/zixiao-labs/Nasti, which is also a general-purpose builder like Vite) (just add configuration).

If you have any questions, please open a new issue or contact amya167@zixiaolabs.com

@edison1105
Copy link
Member

Thanks for the clarification! The Nasti-based approach sounds like a much better fit — keeping Core lean while letting the platform-specific tooling live in its own ecosystem.

Since the main compilation logic will live in Nasti rather than Core, I'd suggest closing this PR for now. If you identify any specific extension points or hooks that Core needs to expose to better support this use case, feel free to open a dedicated issue and we'll be happy to discuss.

Looking forward to seeing Nasti take shape!

@Amiya167 Amiya167 closed this Mar 22, 2026
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