Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 9dc1d99

Browse filesBrowse files
authored
Add support for v-bind same-name shorthand (#215)
* Add support for v-bind same-name shorthand * fix * add test * fix
1 parent aa2de99 commit 9dc1d99
Copy full SHA for 9dc1d99

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Dismiss banner

48 files changed

+10904
-10
lines changed

‎src/script-setup/scope-analyzer.ts

Copy file name to clipboardExpand all lines: src/script-setup/scope-analyzer.ts
+1-9Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
isScriptElement,
1616
isScriptSetupElement,
1717
} from "../common/ast-utils"
18+
import { camelize } from "../utils/utils"
1819

1920
const BUILTIN_COMPONENTS = new Set([
2021
"template",
@@ -94,15 +95,6 @@ const COMPILER_MACROS_AT_ROOT = new Set([
9495
"defineModel",
9596
])
9697

97-
/**
98-
* `casing.camelCase()` converts the beginning to lowercase,
99-
* but does not convert the case of the beginning character when converting with Vue3.
100-
* @see https://github.com/vuejs/vue-next/blob/48de8a42b7fed7a03f7f1ff5d53d6a704252cafe/packages/shared/src/index.ts#L109
101-
*/
102-
function camelize(str: string) {
103-
return str.replace(/-(\w)/gu, (_, c) => (c ? c.toUpperCase() : ""))
104-
}
105-
10698
function capitalize(str: string) {
10799
return str[0].toUpperCase() + str.slice(1)
108100
}

‎src/template/index.ts

Copy file name to clipboardExpand all lines: src/template/index.ts
+71Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ import type { ParserOptions } from "../common/parser-options"
77
import { isSFCFile } from "../common/parser-options"
88
import type {
99
ESLintExpression,
10+
ESLintExtendedProgram,
11+
ESLintIdentifier,
1012
Reference,
1113
Token,
1214
VAttribute,
@@ -34,6 +36,7 @@ import {
3436
parseVOnExpression,
3537
parseSlotScopeExpression,
3638
parseGenericExpression,
39+
parseScriptFragment,
3740
} from "../script"
3841
import {
3942
createSimpleToken,
@@ -46,6 +49,7 @@ import {
4649
isTSLang,
4750
} from "../common/ast-utils"
4851
import { insertError } from "../common/error-utils"
52+
import { camelize } from "../utils/utils"
4953

5054
const shorthandSign = /^[.:@#]/u
5155
const shorthandNameMap = { ":": "bind", ".": "bind", "@": "on", "#": "slot" }
@@ -626,6 +630,14 @@ export function convertToDirective(
626630
}
627631

628632
if (node.value == null) {
633+
if (directive.key.name.name === "bind") {
634+
// v-bind same-name shorthand (Vue 3.4+)
635+
convertForVBindSameNameShorthandValue(
636+
directive,
637+
parserOptions,
638+
locationCalculator,
639+
)
640+
}
629641
return
630642
}
631643

@@ -677,6 +689,65 @@ export function convertToDirective(
677689
}
678690
}
679691

692+
function convertForVBindSameNameShorthandValue(
693+
directive: VDirective,
694+
parserOptions: ParserOptions,
695+
locationCalculator: LocationCalculatorForHtml,
696+
) {
697+
if (
698+
directive.key.name.name !== "bind" ||
699+
directive.key.argument == null ||
700+
directive.key.argument.type !== "VIdentifier"
701+
) {
702+
return
703+
}
704+
// v-bind same-name shorthand (Vue 3.4+)
705+
const vId = directive.key.argument
706+
const camelName = camelize(vId.name)
707+
let result: ESLintExtendedProgram | null = null
708+
try {
709+
result = parseScriptFragment(
710+
camelName,
711+
locationCalculator.getSubCalculatorAfter(vId.range[0]),
712+
parserOptions,
713+
)
714+
} catch (err) {
715+
debug("[template] Parse error: %s", err)
716+
}
717+
if (
718+
result == null ||
719+
result.ast.body.length !== 1 ||
720+
result.ast.body[0].type !== "ExpressionStatement" ||
721+
result.ast.body[0].expression.type !== "Identifier"
722+
) {
723+
return
724+
}
725+
const id: ESLintIdentifier = result.ast.body[0].expression
726+
id.range[1] = vId.range[1]
727+
id.loc.end = { ...vId.loc.end }
728+
if (id.end != null) {
729+
id.end = vId.end
730+
}
731+
directive.value = {
732+
type: "VExpressionContainer",
733+
range: [...vId.range],
734+
loc: {
735+
start: { ...vId.loc.start },
736+
end: { ...vId.loc.end },
737+
},
738+
parent: directive,
739+
expression: id,
740+
references: [
741+
{
742+
id,
743+
mode: "r",
744+
variable: null,
745+
},
746+
],
747+
}
748+
id.parent = directive.value
749+
}
750+
680751
/**
681752
* Parse the content of the given mustache.
682753
* @param parserOptions The parser options to parse expressions.

‎src/utils/utils.ts

Copy file name to clipboard
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
/**
2+
* @see https://github.com/vuejs/vue-next/blob/48de8a42b7fed7a03f7f1ff5d53d6a704252cafe/packages/shared/src/index.ts#L109
3+
*/
4+
export function camelize(str: string) {
5+
return str.replace(/-(\w)/gu, (_, c) => (c ? c.toUpperCase() : ""))
6+
}

‎test/fixtures/ast/directive-shorthands/ast.json

Copy file name to clipboardExpand all lines: test/fixtures/ast/directive-shorthands/ast.json
+61-1Lines changed: 61 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -207,7 +207,67 @@
207207
}
208208
]
209209
},
210-
"value": null
210+
"value": {
211+
"type": "VExpressionContainer",
212+
"range": [
213+
21,
214+
22
215+
],
216+
"loc": {
217+
"start": {
218+
"column": 10,
219+
"line": 2
220+
},
221+
"end": {
222+
"column": 11,
223+
"line": 2
224+
}
225+
},
226+
"expression": {
227+
"type": "Identifier",
228+
"start": 21,
229+
"loc": {
230+
"start": {
231+
"line": 2,
232+
"column": 10
233+
},
234+
"end": {
235+
"column": 11,
236+
"line": 2
237+
}
238+
},
239+
"range": [
240+
21,
241+
22
242+
],
243+
"name": "a"
244+
},
245+
"references": [
246+
{
247+
"id": {
248+
"type": "Identifier",
249+
"start": 21,
250+
"loc": {
251+
"start": {
252+
"line": 2,
253+
"column": 10
254+
},
255+
"end": {
256+
"column": 11,
257+
"line": 2
258+
}
259+
},
260+
"range": [
261+
21,
262+
22
263+
],
264+
"name": "a"
265+
},
266+
"mode": "r",
267+
"variable": null
268+
}
269+
]
270+
}
211271
}
212272
]
213273
},

‎test/fixtures/ast/directive-shorthands/tree.json

Copy file name to clipboardExpand all lines: test/fixtures/ast/directive-shorthands/tree.json
+11Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,17 @@
4545
"children": []
4646
}
4747
]
48+
},
49+
{
50+
"type": "VExpressionContainer",
51+
"text": "a",
52+
"children": [
53+
{
54+
"type": "Identifier",
55+
"text": "a",
56+
"children": []
57+
}
58+
]
4859
}
4960
]
5061
}

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.