Skip to content

Commit 529f808

Browse files
authored
fix(cli): generate web-types with real props and update events for v-model bindings (#2001)
WebStorm's newer Vue schema validates `v-model:show` against a component's declared prop and matching `update:*` event instead of accepting a literal `v-model:show` attribute, so it warned that bindings such as `v-model:show` were invalid (showDialog is not a valid value for v-model:show). Translate `v-model` / `v-model:xxx` documentation entries into the underlying prop name (`model-value` / `xxx`) and emit the companion `update:modelValue` / `update:xxx` event in the generated web-types, so editors recognize the binding. close #1935
1 parent e04e888 commit 529f808

1 file changed

Lines changed: 42 additions & 9 deletions

File tree

packages/varlet-cli/src/node/compiler/compileTemplateHighlight.ts

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,22 @@ export const replaceVersion = (s: string) => s.replace(/\*\*\*.+\*\*\*/g, '').tr
3838

3939
export const replaceUnderline = (s: string) => s.replace(/_/g, '')
4040

41+
export const camelize = (s: string) => s.replace(/-(\w)/g, (_, c) => (c ? c.toUpperCase() : ''))
42+
43+
export function parseVModelName(name: string): { attribute: string; event: string } | null {
44+
if (name === 'v-model') {
45+
return { attribute: 'model-value', event: 'update:modelValue' }
46+
}
47+
48+
const matched = name.match(/^v-model:(.+)$/)
49+
if (matched) {
50+
const arg = matched[1]
51+
return { attribute: arg, event: `update:${camelize(arg)}` }
52+
}
53+
54+
return null
55+
}
56+
4157
export function parseTable(table: string) {
4258
const rows = table.split('\n').filter(Boolean)
4359
return rows.map((row) => {
@@ -84,21 +100,38 @@ export function compileWebTypes(
84100
) {
85101
const { attributesTable, eventsTable, slotsTable } = table
86102

87-
const attributes = attributesTable.map((row: any) => ({
88-
name: replaceVersion(replaceDot(row[0])),
89-
description: row[1],
90-
default: replaceDot(row[3]),
91-
value: {
92-
type: replaceUnderline(row[2]),
93-
kind: 'expression',
94-
},
95-
}))
103+
const modelEvents: Array<{ name: string; description: string }> = []
104+
105+
const attributes = attributesTable.map((row: any) => {
106+
const name = replaceVersion(replaceDot(row[0]))
107+
const vModel = parseVModelName(name)
108+
109+
if (vModel) {
110+
modelEvents.push({ name: vModel.event, description: row[1] })
111+
}
112+
113+
return {
114+
name: vModel ? vModel.attribute : name,
115+
description: row[1],
116+
default: replaceDot(row[3]),
117+
value: {
118+
type: replaceUnderline(row[2]),
119+
kind: 'expression',
120+
},
121+
}
122+
})
96123

97124
const events = eventsTable.map((row: any) => ({
98125
name: replaceVersion(replaceDot(row[0])),
99126
description: row[1],
100127
}))
101128

129+
modelEvents.forEach((modelEvent) => {
130+
if (!events.some((event: { name: string }) => event.name === modelEvent.name)) {
131+
events.push(modelEvent)
132+
}
133+
})
134+
102135
const slots = slotsTable.map((row: any) => ({
103136
name: replaceVersion(replaceDot(row[0])),
104137
description: row[1],

0 commit comments

Comments
 (0)