Skip to content

Commit

Permalink
feat(volar): support unified defineModel
Browse files Browse the repository at this point in the history
  • Loading branch information
sxzz committed Oct 16, 2022
1 parent 7877ac7 commit e1db377
Show file tree
Hide file tree
Showing 3 changed files with 50 additions and 20 deletions.
5 changes: 5 additions & 0 deletions .changeset/lovely-eagles-suffer.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@vue-macros/volar': minor
---

support unified defineModel
60 changes: 41 additions & 19 deletions packages/volar/src/define-model.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,19 @@ import type {
VueLanguagePlugin,
} from '@volar/vue-language-core'

function transformDefineModel(
codes: SegmentWithData<PositionCapabilities>[],
sfc: Sfc,
typeArg: ts.TypeNode,
function transformDefineModel({
codes,
sfc,
typeArg,
vueLibName,
unified,
}: {
codes: SegmentWithData<PositionCapabilities>[]
sfc: Sfc
typeArg: ts.TypeNode
vueLibName: string
) {
unified: boolean
}) {
const source = sfc.scriptSetup!.content.slice(typeArg.pos, typeArg.end)
const seg: Segment<PositionCapabilities> = [
source,
Expand All @@ -26,24 +33,34 @@ function transformDefineModel(
mergeProps() || addProps()
mergeEmits() || addEmits()

codes.push(
`type __VLS_GetPropKey<K> = K extends 'modelValue'${
unified ? '' : ' & never'
} ? 'value' : K
type __VLS_ModelToProps<T> = {
[K in keyof T as __VLS_GetPropKey<K>]: T[K]
}
type __VLS_GetEventKey<K extends string | number> = K extends 'modelValue'${
unified ? '' : ' & never'
} ? 'input' : \`update:\${K}\`
type __VLS_ModelToEmits<T> = T extends Record<string | number, any> ? { [K in keyof T & (string | number) as __VLS_GetEventKey<K>]: (value: T[K]) => void } : T`
)

function mergeProps() {
const idx = codes.indexOf('__VLS_TypePropsToRuntimeProps<')
if (idx === -1) return false

codes.splice(idx + 2, 0, ' & ', seg)
codes.splice(idx + 2, 0, ' & __VLS_ModelToProps<', seg, '>')
return true
}

function addProps() {
const idx = codes.indexOf('setup() {\n')
if (idx === -1) return false
const segs: Segment<PositionCapabilities>[] = [
'props: (',
'{} as ',
'__VLS_TypePropsToRuntimeProps<',
'props: ({} as __VLS_TypePropsToRuntimeProps<__VLS_ModelToProps<',
seg,
'>',
'),\n',
'>>),\n',
]
codes.splice(idx, 0, ...segs)

Expand All @@ -61,9 +78,6 @@ function transformDefineModel(
if (idx === -1) return false

codes.splice(idx + 2, 1, '>> & __VLS_ModelToEmits<', seg, '>),\n')
codes.push(
`type __VLS_ModelToEmits<T> = T extends Record<string | number, any> ? { [K in keyof T & (string | number) as \`update:\${K}\`]: (value: T[K]) => void } : T`
)
return true
}

Expand All @@ -77,9 +91,6 @@ function transformDefineModel(
'>),\n',
]
codes.splice(idx, 0, ...segs)
codes.push(
`type __VLS_ModelToEmits<T> = T extends Record<string | number, any> ? { [K in keyof T & (string | number) as \`update:\${K}\`]: (value: T[K]) => void } : T`
)
return true
}
}
Expand Down Expand Up @@ -135,8 +146,19 @@ function resolve({
const typeArg = getTypeArg(ts, sfc)
if (!typeArg) return

const vueLibName = getVueLibraryName(vueCompilerOptions.target ?? 3)
transformDefineModel(embeddedFile.content, sfc, typeArg, vueLibName)
const vueVersion = vueCompilerOptions.target ?? 3
const vueLibName = getVueLibraryName(vueVersion)
const unified =
(vueVersion < 3 && (vueCompilerOptions as any)?.defineModel?.unified) ??
true

transformDefineModel({
codes: embeddedFile.content,
sfc,
typeArg,
vueLibName,
unified,
})
}

const plugin: VueLanguagePlugin = ({
Expand Down
5 changes: 4 additions & 1 deletion playground/vue2/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@
},
"vueCompilerOptions": {
"target": 2.7,
"plugins": ["@vue-macros/volar/define-model"]
"plugins": ["@vue-macros/volar/define-model"],
"defineModel": {
"unified": true
}
},
"include": ["src", "*"]
}

0 comments on commit e1db377

Please sign in to comment.