Skip to content

Conversation

edison1105
Copy link
Member

@edison1105 edison1105 commented Jun 5, 2025

close #13169
close #13170
close #11321
close #12298
close #12828

use tests from #13170 and #12298 and #12828

The current handing logic for v-bind shorthand is rather scattered, which results in many edge cases where transformBindShorthand needs to be called additionally. these cases occur because vbind shorthand has not been processed when reading properties from props.

This PR introduces a dedicated transform specifically for handling v-bind shorthand, and makes it the first transform to be called. This ensures that vbind shorthand has already been processed before any subsequent logic read from props


Special handling is required for double bind in vue-macros. PR vue-macros/vue-macros#960

Summary by CodeRabbit

  • New Features

    • Shorthand v-bind (e.g., :prop, :key, :tag) is now consistently supported across compiler, DOM, and SSR.
  • Bug Fixes

    • Consistent handling and error behavior for same-name shorthand bindings across v-if, v-for, and v-model scenarios.
  • Tests

    • Added/updated tests covering shorthand v-bind in dynamic tags, v-model, conditional branches, and loops.
  • Chores

    • Exposed a compiler utility constant for broader use.

Copy link

coderabbitai bot commented Jun 5, 2025

Walkthrough

Added a new NodeTransform transformVBindShorthand that expands same-name shorthand v-bind directives and integrated it into compiler-core, compiler-dom tests, and SSR compile pipelines; removed inline same-name shorthand handling from vBind/vFor; updated tests and exported a utility regex used by the new transform.

Changes

Cohort / File(s) Change Summary
New transform
packages/compiler-core/src/transforms/transformVBindShorthand.ts
Added transformVBindShorthand NodeTransform to expand same-name shorthand v-bind (e.g. :type) into explicit expressions, camelize args, and report invalid-arg errors.
Core integration & export
packages/compiler-core/src/compile.ts, packages/compiler-core/src/index.ts
Imported and added transformVBindShorthand as the first node transform in the base preset; exported it from core index.
vBind refactor
packages/compiler-core/src/transforms/vBind.ts
Removed previous same-name shorthand helper/logic (transformBindShorthand); adjusted empty-expression handling and emission paths for v-bind.
vFor adjustments
packages/compiler-core/src/transforms/vFor.ts
Removed import/use of removed transformBindShorthand for resolving shorthand :key.
Utilities export
packages/compiler-core/src/utils.ts
Exported validFirstIdentCharRE with explicit RegExp type annotation.
SSR integration
packages/compiler-ssr/src/index.ts
Imported and added transformVBindShorthand to SSR compile nodeTransforms (first).
Tests — include transform
packages/compiler-core/__tests__/transforms/vBind.spec.ts, packages/compiler-core/__tests__/transforms/vFor.spec.ts, packages/compiler-core/__tests__/transforms/vIf.spec.ts, packages/compiler-dom/__tests__/transforms/vModel.spec.ts
Test helpers updated to include transformVBindShorthand in nodeTransforms; new/updated tests for shorthand :key, v-model + shorthand :type, and related cases.
Tests — SSR
packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts
Added test "with dynamic tag shorthand" asserting SSR output for shorthand dynamic :tag.

Sequence Diagram(s)

sequenceDiagram
    participant Parser
    participant AST
    participant transformVBindShorthand as ShorthandTransform
    participant OtherTransforms

    Parser->>AST: parse template → AST
    AST->>ShorthandTransform: apply same-name v-bind expansion (first)
    ShorthandTransform-->>AST: attach expression / report errors
    AST->>OtherTransforms: continue with v-if, v-for, v-model, element transforms
    OtherTransforms-->>AST: further node mutations (userKey, key resolution, helpers)
    note right of ShorthandTransform #dff0d8: Shorthand handled before other transforms
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Suggested labels

ready to merge, :broom: p1-chore

Suggested reviewers

  • yyx990803

Poem

"I’m a rabbit with a tiny hop, turning :type into a line,
I camel-case the whispered name and make the bindings fine.
Tests clap paws, SSR sings, v-if finds its key—
A nimble change, a tidy leap, bindings happy as can be. 🥕"

Pre-merge checks and finishing touches

✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Linked Issues Check ✅ Passed The PR centralizes same-name v-bind shorthand processing by adding transformVBindShorthand, adding it to the base transform preset and SSR pipeline, removing the old inline shorthand handling, and updating tests in compiler-core, compiler-dom, and compiler-ssr; the changes introduce the shorthand expansion, validation, and camelization logic and add tests for v-model/type, :key on v-if, and SSR dynamic tag cases, which correspond to the linked issues for radio/v-model type fixes [#13169,#13170], v-if :key parsing [#11321,#12298], and SSR shorthand handling [#12828].
Out of Scope Changes Check ✅ Passed All modified files and additions are directly related to centralizing v-bind shorthand handling: new transform implementation, integrating it into core/dom/ssr pipelines, removing the old helper usage, and updating tests; the only ancillary change is exporting a regex utility used for argument validation, which supports the new transform and is in-scope.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.
Title Check ✅ Passed The title succinctly and accurately summarizes the primary change: adding a dedicated v-bind shorthand transform to the compiler, which matches the PR's additions of transformVBindShorthand and related test/compile updates. It is concise, scoped with a conventional-commit prefix, and specific enough for reviewers to understand the main change at a glance.
✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch edison/refactor/vBindShorthand

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

Copy link

github-actions bot commented Jun 5, 2025

Size Report

Bundles

File Size Gzip Brotli
runtime-dom.global.prod.js 102 kB 38.6 kB 34.7 kB
vue.global.prod.js 160 kB (+66 B) 58.7 kB (+14 B) 52.2 kB (-51 B)

Usages

Name Size Gzip Brotli
createApp (CAPI only) 46.7 kB 18.3 kB 16.7 kB
createApp 54.7 kB 21.3 kB 19.5 kB
createSSRApp 58.9 kB 23 kB 21 kB
defineCustomElement 60 kB 23 kB 20.9 kB
overall 68.8 kB 26.5 kB 24.2 kB

Copy link

pkg-pr-new bot commented Jun 5, 2025

Open in StackBlitz

@vue/compiler-core

npm i https://pkg.pr.new/@vue/compiler-core@13438

@vue/compiler-dom

npm i https://pkg.pr.new/@vue/compiler-dom@13438

@vue/compiler-sfc

npm i https://pkg.pr.new/@vue/compiler-sfc@13438

@vue/compiler-ssr

npm i https://pkg.pr.new/@vue/compiler-ssr@13438

@vue/reactivity

npm i https://pkg.pr.new/@vue/reactivity@13438

@vue/runtime-core

npm i https://pkg.pr.new/@vue/runtime-core@13438

@vue/runtime-dom

npm i https://pkg.pr.new/@vue/runtime-dom@13438

@vue/server-renderer

npm i https://pkg.pr.new/@vue/server-renderer@13438

@vue/shared

npm i https://pkg.pr.new/@vue/shared@13438

vue

npm i https://pkg.pr.new/vue@13438

@vue/compat

npm i https://pkg.pr.new/@vue/compat@13438

commit: ecd1d8b

@edison1105 edison1105 changed the title refactor(compile): add independent transform for VBindShorthand refactor(compiler): add independent transform for VBindShorthand Jun 5, 2025
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: 0

🧹 Nitpick comments (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)

19-19: Consider safer handling of directive argument access.

The non-null assertion prop.arg! assumes the argument will always exist for bind directives without expressions. While this may be valid for shorthand syntax, consider adding a guard check for robustness.

-        const arg = prop.arg!
+        const arg = prop.arg
+        if (!arg) continue
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a47832e and fd7d6cf.

⛔ Files ignored due to path filters (1)
  • packages/compiler-dom/__tests__/transforms/__snapshots__/vModel.spec.ts.snap is excluded by !**/*.snap
📒 Files selected for processing (11)
  • packages/compiler-core/__tests__/transforms/vBind.spec.ts (2 hunks)
  • packages/compiler-core/__tests__/transforms/vFor.spec.ts (2 hunks)
  • packages/compiler-core/__tests__/transforms/vIf.spec.ts (3 hunks)
  • packages/compiler-core/src/compile.ts (2 hunks)
  • packages/compiler-core/src/index.ts (1 hunks)
  • packages/compiler-core/src/transforms/transformVBindShorthand.ts (1 hunks)
  • packages/compiler-core/src/transforms/vBind.ts (2 hunks)
  • packages/compiler-core/src/transforms/vFor.ts (0 hunks)
  • packages/compiler-dom/__tests__/transforms/vModel.spec.ts (3 hunks)
  • packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts (1 hunks)
  • packages/compiler-ssr/src/index.ts (2 hunks)
💤 Files with no reviewable changes (1)
  • packages/compiler-core/src/transforms/vFor.ts
🧰 Additional context used
🧬 Code Graph Analysis (6)
packages/compiler-core/src/compile.ts (2)
packages/compiler-core/src/index.ts (1)
  • transformVBindShorthand (69-69)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)
  • transformVBindShorthand (10-36)
packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts (1)
packages/compiler-ssr/src/index.ts (1)
  • compile (32-94)
packages/compiler-ssr/src/index.ts (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)
  • transformVBindShorthand (10-36)
packages/compiler-core/__tests__/transforms/vBind.spec.ts (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)
  • transformVBindShorthand (10-36)
packages/compiler-core/src/transforms/vBind.ts (1)
packages/compiler-core/src/ast.ts (1)
  • createObjectProperty (673-683)
packages/compiler-core/__tests__/transforms/vFor.spec.ts (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)
  • transformVBindShorthand (10-36)
⏰ Context from checks skipped due to timeout of 90000ms (3)
  • GitHub Check: Redirect rules
  • GitHub Check: Header rules
  • GitHub Check: Pages changed
🔇 Additional comments (17)
packages/compiler-core/__tests__/transforms/vBind.spec.ts (1)

20-20: LGTM! Proper integration of transformVBindShorthand into test pipeline.

The import and placement as the first transform in the test pipeline is correct, ensuring that shorthand v-bind syntax is properly expanded before other transforms process the AST.

Also applies to: 29-29

packages/compiler-core/src/index.ts (1)

69-69: LGTM! Proper public API exposure.

Adding the export for transformVBindShorthand correctly exposes the new transform as part of the compiler-core public API, consistent with other transform exports.

packages/compiler-core/src/compile.ts (1)

25-25: LGTM! Correct integration into core compilation pipeline.

The import and placement as the first transform in getBaseTransformPreset is architecturally correct. This ensures shorthand v-bind directives are expanded before other transforms process them, maintaining the proper transformation order.

Also applies to: 37-37

packages/compiler-ssr/src/index.ts (1)

16-16: LGTM! Consistent SSR pipeline integration.

The import from @vue/compiler-dom and placement as the first transform in the SSR nodeTransforms array ensures consistent handling of shorthand v-bind syntax between client-side and server-side rendering pipelines.

Also applies to: 59-59

packages/compiler-ssr/__tests__/ssrTransitionGroup.spec.ts (1)

104-125: LGTM! Well-structured test for SSR shorthand v-bind handling.

The test correctly verifies that shorthand :tag syntax is properly transformed to use _ctx.tag in SSR compilation output. The inline snapshot expectation captures both the dynamic opening tag <${_ctx.tag} and closing tag </${_ctx.tag}> rendering, ensuring complete SSR functionality.

packages/compiler-core/__tests__/transforms/vFor.spec.ts (2)

24-24: Import addition looks good.

The transformVBindShorthand import is correctly added to support shorthand v-bind processing in v-for tests.


36-36: Correct transform order placement.

Adding transformVBindShorthand as the first node transform ensures that shorthand v-bind syntax (like :key) is expanded before the v-for transform processes it. This maintains proper dependency order in the transform pipeline.

packages/compiler-dom/__tests__/transforms/vModel.spec.ts (3)

6-6: Import addition is correct.

The transformVBindShorthand import enables shorthand v-bind processing in v-model tests.


22-22: Proper transform integration.

Adding transformVBindShorthand to the nodeTransforms ensures shorthand v-bind syntax is processed before element transformation, maintaining the correct pipeline order.


67-74: Excellent test case for edge case handling.

This test addresses issue #13169 and correctly verifies that shorthand :type binding after v-model triggers dynamic model behavior (V_MODEL_DYNAMIC helper). This is crucial because the input type affects which v-model transformation is applied, and shorthand syntax should be properly recognized.

packages/compiler-core/__tests__/transforms/vIf.spec.ts (3)

20-25: Clean import restructuring.

The import statement is properly restructured to include transformVBindShorthand along with other necessary imports.


43-48: Consistent transform pipeline setup.

The addition of transformVBindShorthand as the first node transform maintains consistency with other test suites and ensures proper processing order for shorthand v-bind syntax.


223-232: Thorough test for shorthand key binding.

This test correctly verifies that shorthand :key syntax on v-if elements is properly processed. The expectation that both arg.content and exp.content equal 'key' confirms that the shorthand is expanded to :key="key" as intended. This addresses issue #11321 and ensures proper key handling in conditional rendering.

packages/compiler-core/src/transforms/transformVBindShorthand.ts (3)

20-28: Error handling for invalid shorthand arguments is well-implemented.

The validation correctly restricts shorthand syntax to static simple expressions only, and provides appropriate error reporting with fallback to an empty expression.


30-31: Camelization logic is correct for JavaScript property naming conventions.

Converting the argument content to camelCase and creating a non-static expression properly handles the shorthand expansion (e.g., :foo-bar:foo-bar="fooBar").


10-36: Well-structured transform that effectively modularizes shorthand v-bind handling.

This dedicated transform cleanly separates the shorthand expansion logic from other bind-related transforms, improving maintainability and reducing complexity in other parts of the codebase.

packages/compiler-core/src/transforms/vBind.ts (1)

71-71: Non-null assertion on expression is safe in this context.

The exp! assertion is appropriate here since the earlier logic (lines 22-38) handles empty expressions, and at this point exp should be a valid expression node.

@edison1105 edison1105 changed the title refactor(compiler): add independent transform for VBindShorthand refactor(compiler): add dedicated transform for same-name shorthand Jun 5, 2025
@edison1105 edison1105 added scope: compiler 🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. labels Jun 5, 2025
@edison1105 edison1105 changed the title refactor(compiler): add dedicated transform for same-name shorthand refactor(compiler): add dedicated transform for vbind shorthand Jun 5, 2025
@vuejs vuejs deleted a comment from edison1105 Jun 13, 2025
@edison1105 edison1105 force-pushed the edison/refactor/vBindShorthand branch from b68fcd1 to 503b4b5 Compare June 13, 2025 09:14
@vuejs vuejs deleted a comment from edison1105 Jun 13, 2025
@vuejs vuejs deleted a comment from edison1105 Sep 24, 2025
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 (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (1)

32-38: Consider extracting validation logic to a helper function.

The identifier validation logic (including the special hyphen case) could be extracted to improve readability and reusability, especially since it combines standard identifier validation with Vue-specific rules.

+function isValidPropIdentifier(name: string): boolean {
+  return name.length > 0 && (
+    validFirstIdentCharRE.test(name[0]) ||
+    // allow hyphen first char for https://github.com/vuejs/language-tools/pull/3424
+    name[0] === '-'
+  )
+}
+
 const propName = camelize((arg as SimpleExpressionNode).content)
-if (
-  validFirstIdentCharRE.test(propName[0]) ||
-  // allow hyphen first char for https://github.com/vuejs/language-tools/pull/3424
-  propName[0] === '-'
-) {
+if (isValidPropIdentifier(propName)) {
   prop.exp = createSimpleExpression(propName, false, arg.loc)
 }
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between fbfc668 and ecd1d8b.

📒 Files selected for processing (1)
  • packages/compiler-core/src/transforms/transformVBindShorthand.ts (1 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (3)
packages/compiler-core/src/index.ts (4)
  • transformVBindShorthand (69-69)
  • NodeTransform (20-20)
  • createCompilerError (34-34)
  • ErrorCodes (32-32)
packages/compiler-core/src/ast.ts (2)
  • createSimpleExpression (685-698)
  • SimpleExpressionNode (225-247)
packages/compiler-core/src/utils.ts (1)
  • validFirstIdentCharRE (77-77)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: test / unit-test-windows
🔇 Additional comments (5)
packages/compiler-core/src/transforms/transformVBindShorthand.ts (5)

1-9: Clean and appropriate imports.

The imports are well-organized and include all necessary dependencies for the transform implementation.


11-19: Correct node and directive filtering logic.

The transform correctly identifies ELEMENT nodes and filters for bind directives without expressions, which is exactly what's needed for v-bind shorthand expansion.


20-29: Robust error handling for invalid arguments.

The validation properly restricts shorthand syntax to static simple expressions and provides appropriate error reporting with fallback to an empty expression. This prevents runtime issues from malformed shorthand.


11-43: Well-architected transform implementation.

The transform correctly implements the core logic for v-bind shorthand expansion:

  • Processes only relevant ELEMENT nodes with bind directives
  • Validates arguments appropriately
  • Creates proper expression nodes with correct static/dynamic flags
  • Handles edge cases with appropriate error reporting

This centralized approach should resolve the scattered handling issues mentioned in the PR objectives.


31-38: Keep the leading-hyphen special-case — it's intentional
Vue allows binding attribute names that start with '-' via dynamic arguments (v-bind:['-foo']); for CSS custom properties prefer :style or SFC v-bind(). This special-case aligns with Vue behavior — no change required.

@vuejs vuejs deleted a comment from edison1105 Sep 24, 2025
@edison1105 edison1105 changed the title refactor(compiler): add dedicated transform for vbind shorthand refactor(compiler): add separate transform for vbind shorthand Sep 24, 2025
@edison1105
Copy link
Member Author

/ecosystem-ci run

@vuejs vuejs deleted a comment from edison1105 Sep 24, 2025
@vue-bot
Copy link
Contributor

vue-bot commented Sep 24, 2025

📝 Ran ecosystem CI: Open

suite result latest scheduled
language-tools success success
nuxt success success
vite-plugin-vue success success
radix-vue success success
pinia success success
primevue success success
router success success
vue-i18n success success
vuetify failure failure
vue-macros failure success
test-utils success success
vue-simple-compiler success success
quasar success success
vitepress success success
vueuse success success
vant failure success

@edison1105 edison1105 merged commit 565741a into main Sep 24, 2025
16 checks passed
@edison1105 edison1105 deleted the edison/refactor/vBindShorthand branch September 24, 2025 13:23
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🔨 p3-minor-bug Priority 3: this fixes a bug, but is an edge case that only affects very specific usage. scope: compiler
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Same-name shorthand (:type) breaks radio group behavior CompilerDOM.compile incorrectly parsing <template v-if="true" :key>
5 participants