Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(deps): update volarjs to v2 (major) #633

Merged
merged 9 commits into from May 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 1 addition & 2 deletions docs/guide/getting-started.md
Expand Up @@ -9,8 +9,7 @@ We assume you are already familiar with the basic usages of Vue before you conti
- Node.js 16.14.0 or higher.
- Vue >= 2.7 or Vue >= 3.0.
- Some features need Vue >= 3.2.25.
- VSCode installed the [Vue Language Features (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) **v1.8.27** (the latest v1) extension.
- ❌ Considering that v2 is not yet stable and some issues remain unresolved, plus adapting to 2.x would mean an almost irreversible upgrade for Vue Macros, we've decided not to support 2.x at this time. In other words, we will continue to support v1.
- VSCode installed the [Vue Language Features (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) **latest** extension.
- ❌ WebStorm is not supported.

## Creating a Vue Macros Project
Expand Down
3 changes: 1 addition & 2 deletions docs/zh-CN/guide/getting-started.md
Expand Up @@ -9,8 +9,7 @@ Vue Macros 是一个库,用于实现尚未被 Vue 正式实现的提案或想
- Node.js 16.14.0 或更高
- Vue >= 2.7 或 Vue >= 3.0
- 某些功能需要 Vue >= 3.2.25
- VSCode 安装了 [Vue Language Features (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) **v1.8.27**(最新的 v1)扩展
- ❌ 考虑到 2.x 版本尚未稳定,还有一些问题未被解决。并且适配 2.x 对 Vue Macros 几乎是不可逆的升级。所以我们决定目前不兼容 2.x,換而言之,我们依然支持 1.x。
- VSCode 安装了 [Vue Language Features (Volar)](https://marketplace.visualstudio.com/items?itemName=Vue.volar) **最新的**扩展
- ❌ 不支持 WebStorm

## 搭建第一个 Vue Macros 项目
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -65,7 +65,7 @@
"vite": "^5.2.10",
"vitest": "^1.5.2",
"vue": "^3.4.25",
"vue-tsc": "1.8.27",
"vue-tsc": "2.0.16",
"vue2": "npm:vue@^2.7.16",
"webpack": "^5.91.0"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/nuxt/package.json
Expand Up @@ -56,7 +56,7 @@
"devDependencies": {
"@nuxt/devtools": "^1.2.0",
"@nuxt/schema": "^3.11.2",
"@vue/language-core": "1.8.27"
"@vue/language-core": "2.0.16"
},
"engines": {
"node": ">=16.14.0"
Expand Down
6 changes: 3 additions & 3 deletions packages/volar/package.json
Expand Up @@ -40,7 +40,7 @@
"dev": "tsup --watch"
},
"peerDependencies": {
"vue-tsc": "^1.6.0"
"vue-tsc": "^2.0.0"
},
"peerDependenciesMeta": {
"vue-tsc": {
Expand All @@ -53,13 +53,13 @@
"@vue-macros/define-props": "workspace:*",
"@vue-macros/short-bind": "workspace:*",
"@vue-macros/short-vmodel": "workspace:*",
"@vue/language-core": "1.8.27",
"@vue/language-core": "2.0.16",
"@vue/shared": "^3.4.25"
},
"devDependencies": {
"@vue/compiler-dom": "^3.4.25",
"typescript": "~5.4.5",
"vue-tsc": "1.8.27"
"vue-tsc": "2.0.16"
},
"engines": {
"node": ">=16.14.0"
Expand Down
61 changes: 35 additions & 26 deletions packages/volar/src/common.ts
@@ -1,6 +1,5 @@
import {
type FileRangeCapabilities,
type Segment,
type Code,
type Sfc,
type VueCompilerOptions,
replaceAll,
Expand All @@ -11,11 +10,7 @@ export function getVueLibraryName(vueVersion: number) {
return vueVersion < 2.7 ? '@vue/runtime-dom' : 'vue'
}

export function addProps(
content: Segment<FileRangeCapabilities>[],
decl: Segment<FileRangeCapabilities>[],
vueLibName: string,
) {
export function addProps(content: Code[], decl: Code[]) {
replaceAll(
content,
/setup\(\) {/g,
Expand All @@ -24,17 +19,10 @@ export function addProps(
'),\n',
'setup() {',
)
content.push(
`type __VLS_NonUndefinedable<T> = T extends undefined ? never : T;\n`,
`type __VLS_TypePropsToRuntimeProps<T> = { [K in keyof T]-?: {} extends Pick<T, K> ? { type: import('${vueLibName}').PropType<__VLS_NonUndefinedable<T[K]>> } : { type: import('${vueLibName}').PropType<T[K]>, required: true } };\n`,
)
return true
}

export function addEmits(
content: Segment<FileRangeCapabilities>[],
decl: Segment<FileRangeCapabilities>[],
) {
export function addEmits(content: Code[], decl: Code[]) {
replaceAll(
content,
/setup\(\) {/g,
Expand All @@ -52,35 +40,56 @@ export function getVolarOptions(
return vueCompilerOptions.vueMacros
}

export function getImportNames(
ts: typeof import('typescript/lib/tsserverlibrary'),
sfc: Sfc,
) {
export function getImportNames(ts: typeof import('typescript'), sfc: Sfc) {
const names: string[] = []
const sourceFile = sfc.scriptSetup!.ast
sourceFile.forEachChild((node) => {
ts.forEachChild(sourceFile, (node) => {
if (
ts.isImportDeclaration(node) &&
node.assertClause?.elements.some(
node.attributes?.elements.some(
(el) =>
el.name.text === 'type' &&
getText(el.name, { ts, sfc, source: 'scriptSetup' }) === 'type' &&
ts.isStringLiteral(el.value) &&
el.value.text === 'macro',
getText(el.value, { ts, sfc, source: 'scriptSetup' }) === 'macro',
)
) {
const name = node.importClause?.name?.text
const name = node.importClause?.name?.escapedText
if (name) names.push(name)

if (node.importClause?.namedBindings) {
const bindings = node.importClause.namedBindings
if (ts.isNamespaceImport(bindings)) {
names.push(bindings.name.text)
names.push(bindings.name.escapedText!)
} else {
for (const el of bindings.elements) names.push(el.name.text)
for (const el of bindings.elements) names.push(el.name.escapedText!)
}
}
}
})

return names
}

interface Options {
sfc: Sfc
ts: typeof import('typescript')
source?: 'script' | 'scriptSetup'
}

export function getStart(
node: import('typescript').Node,
{ ts, sfc, source = 'scriptSetup' }: Options,
) {
return (ts as any).getTokenPosOfNode(node, sfc[source]!.ast)
}

export function getText(node: import('typescript').Node, options: Options) {
const { sfc, source = 'scriptSetup' } = options
return sfc[source]!.content.slice(getStart(node, options), node.end)
}

export function isJsxExpression(
node?: import('typescript').Node,
): node is import('typescript').JsxExpression {
return node?.kind === 294
}
54 changes: 24 additions & 30 deletions packages/volar/src/define-models.ts
@@ -1,10 +1,9 @@
import { DEFINE_MODELS, DEFINE_MODELS_DOLLAR } from '@vue-macros/common'
import {
FileKind,
FileRangeCapabilities,
type Segment,
type Code,
type Sfc,
type VueLanguagePlugin,
allCodeFeatures,
} from '@vue/language-core'
import {
addEmits,
Expand All @@ -17,28 +16,18 @@ function transformDefineModels({
codes,
sfc,
typeArg,
vueLibName,
unified,
}: {
codes: Segment<FileRangeCapabilities>[]
codes: Code[]
sfc: Sfc
typeArg: import('typescript/lib/tsserverlibrary').TypeNode
typeArg: import('typescript').TypeNode
vueLibName: string
unified: boolean
}) {
const source = sfc.scriptSetup!.content.slice(typeArg.pos, typeArg.end)
const seg: Segment<FileRangeCapabilities> = [
source,
'scriptSetup',
typeArg!.pos,
FileRangeCapabilities.full,
]
const seg: Code = [source, 'scriptSetup', typeArg!.pos, allCodeFeatures]
mergeProps() ||
addProps(
codes,
['__VLS_TypePropsToRuntimeProps<__VLS_ModelToProps<', seg, '>>'],
vueLibName,
)
addProps(codes, ['__VLS_TypePropsToOption<__VLS_ModelToProps<', seg, '>>'])
mergeEmits() || addEmits(codes, ['__VLS_ModelToEmits<', seg, '>'])

codes.push(
Expand All @@ -56,13 +45,19 @@ function transformDefineModels({

function mergeProps() {
const indexes = codes.reduce((res: number[], code, index) => {
if (code === '__VLS_TypePropsToRuntimeProps<') res.unshift(index)
if (code === '__VLS_TypePropsToOption<') res.unshift(index)
return res
}, [])
if (indexes.length === 0) return false

for (const idx of indexes)
codes.splice(idx + 2, 0, ' & __VLS_ModelToProps<', seg, '>')
codes.splice(
idx + 2,
0,
' & __VLS_TypePropsToOption<__VLS_ModelToProps<',
seg,
'>>',
)
return true
}

Expand All @@ -80,16 +75,15 @@ function transformDefineModels({
}
}

function getTypeArg(
ts: typeof import('typescript/lib/tsserverlibrary'),
sfc: Sfc,
) {
function getCallArg(node: import('typescript/lib/tsserverlibrary').Node) {
function getTypeArg(ts: typeof import('typescript'), sfc: Sfc) {
function getCallArg(node: import('typescript').Node) {
if (
!(
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
[DEFINE_MODELS, DEFINE_MODELS_DOLLAR].includes(node.expression.text) &&
[DEFINE_MODELS, DEFINE_MODELS_DOLLAR].includes(
node.expression.escapedText!,
) &&
node.typeArguments?.length === 1
)
)
Expand All @@ -98,11 +92,11 @@ function getTypeArg(
}

const sourceFile = sfc.scriptSetup!.ast
return sourceFile.forEachChild((node) => {
return ts.forEachChild(sourceFile, (node) => {
if (ts.isExpressionStatement(node)) {
return getCallArg(node.expression)
} else if (ts.isVariableStatement(node)) {
return node.declarationList.forEachChild((decl) => {
return ts.forEachChild(node.declarationList, (decl) => {
if (!ts.isVariableDeclaration(decl) || !decl.initializer) return
return getCallArg(decl.initializer)
})
Expand All @@ -116,10 +110,10 @@ const plugin: VueLanguagePlugin = ({
}) => {
return {
name: 'vue-macros-define-models',
version: 1,
resolveEmbeddedFile(fileName, sfc, embeddedFile) {
version: 2,
resolveEmbeddedCode(fileName, sfc, embeddedFile) {
if (
embeddedFile.kind !== FileKind.TypeScriptHostFile ||
!['ts', 'tsx'].includes(embeddedFile.lang) ||
!sfc.scriptSetup ||
!sfc.scriptSetup.ast
)
Expand Down
41 changes: 15 additions & 26 deletions packages/volar/src/define-options.ts
@@ -1,51 +1,45 @@
import { DEFINE_OPTIONS } from '@vue-macros/common'
import {
FileKind,
FileRangeCapabilities,
type Segment,
type Code,
type Sfc,
type VueLanguagePlugin,
replace,
allCodeFeatures,
replaceAll,
} from '@vue/language-core'

function transformDefineOptions({
codes,
sfc,
arg,
}: {
codes: Segment<FileRangeCapabilities>[]
codes: Code[]
sfc: Sfc
arg: import('typescript/lib/tsserverlibrary').Node
arg: import('typescript').Node
}) {
const source = sfc.scriptSetup!.content.slice(arg.pos, arg.end)
const seg: Segment<FileRangeCapabilities> = [
source,
'scriptSetup',
arg!.pos,
FileRangeCapabilities.full,
]
replace(codes, /setup\(\) {/, '...', seg, ',\nsetup() {')
const seg: Code = [source, 'scriptSetup', arg!.pos, allCodeFeatures]
replaceAll(codes, /setup\(\) {/g, '...', seg, ',\nsetup() {')
}

function getArg(ts: typeof import('typescript/lib/tsserverlibrary'), sfc: Sfc) {
function getCallArg(node: import('typescript/lib/tsserverlibrary').Node) {
function getArg(ts: typeof import('typescript'), sfc: Sfc) {
function getCallArg(node: import('typescript').Node) {
if (
!(
ts.isCallExpression(node) &&
ts.isIdentifier(node.expression) &&
node.expression.text === DEFINE_OPTIONS
node.expression.escapedText === DEFINE_OPTIONS
)
)
return undefined
return node.arguments[0]
}

const sourceFile = sfc.scriptSetup!.ast
return sourceFile.forEachChild((node) => {
return ts.forEachChild(sourceFile, (node) => {
if (ts.isExpressionStatement(node)) {
return getCallArg(node.expression)
} else if (ts.isVariableStatement(node)) {
return node.declarationList.forEachChild((decl) => {
return ts.forEachChild(node.declarationList, (decl) => {
if (!ts.isVariableDeclaration(decl) || !decl.initializer) return
return getCallArg(decl.initializer)
})
Expand All @@ -56,14 +50,9 @@ function getArg(ts: typeof import('typescript/lib/tsserverlibrary'), sfc: Sfc) {
const plugin: VueLanguagePlugin = ({ modules: { typescript: ts } }) => {
return {
name: 'vue-macros-define-options',
version: 1,
resolveEmbeddedFile(fileName, sfc, embeddedFile) {
if (
embeddedFile.kind !== FileKind.TypeScriptHostFile ||
!sfc.scriptSetup ||
!sfc.scriptSetup.ast
)
return
version: 2,
resolveEmbeddedCode(fileName, sfc, embeddedFile) {
if (!sfc.scriptSetup || !sfc.scriptSetup.ast) return

const arg = getArg(ts, sfc)
if (!arg) return
Expand Down
2 changes: 1 addition & 1 deletion packages/volar/src/define-props-refs.ts
Expand Up @@ -5,7 +5,7 @@ const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => {

return {
name: 'vue-macros-define-props-refs',
version: 1,
version: 2,
}
}

Expand Down
2 changes: 1 addition & 1 deletion packages/volar/src/define-props.ts
Expand Up @@ -5,7 +5,7 @@ const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => {

return {
name: 'vue-macros-define-props',
version: 1,
version: 2,
}
}

Expand Down