diff --git a/extensions/vscode/package.json b/extensions/vscode/package.json index 59f1f2a9e9..086a3066e3 100644 --- a/extensions/vscode/package.json +++ b/extensions/vscode/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "volar", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "repository": { "type": "git", "url": "https://github.com/vuejs/language-tools.git", @@ -507,9 +507,9 @@ "@types/vscode": "^1.82.0", "@volar/vscode": "~2.4.11", "@vscode/vsce": "^3.2.1", - "@vue/language-core": "3.0.0-alpha.0", - "@vue/language-server": "3.0.0-alpha.0", - "@vue/typescript-plugin": "3.0.0-alpha.0", + "@vue/language-core": "3.0.0-alpha.2", + "@vue/language-server": "3.0.0-alpha.2", + "@vue/typescript-plugin": "3.0.0-alpha.2", "esbuild": "^0.25.0", "esbuild-visualizer": "^0.7.0", "reactive-vscode": "^0.2.9", diff --git a/insiders.json b/insiders.json index 0cc11b289f..49058af022 100644 --- a/insiders.json +++ b/insiders.json @@ -1,6 +1,22 @@ { - "latest": "2.2.9", + "latest": "3.0.0-alpha.3", "versions": [ + { + "version": "3.0.0-alpha.3", + "date": "2025-03-17", + "downloads": { + "GitHub": "https://github.com/volarjs/insiders/releases/tag/v3.0.0-alpha.3", + "AFDIAN": "https://afdian.com/p/a9d56800028311f0b56952540025c377" + } + }, + { + "version": "3.0.0-alpha.1", + "date": "2025-03-08", + "downloads": { + "GitHub": "https://github.com/volarjs/insiders/releases/tag/v3.0.0-alpha.1", + "AFDIAN": "https://afdian.com/p/09694088fba011efa49c52540025c377" + } + }, { "version": "2.2.9", "date": "2025-03-02", diff --git a/lerna.json b/lerna.json index 93fc4f1722..5c54461211 100644 --- a/lerna.json +++ b/lerna.json @@ -6,5 +6,5 @@ "packages/*", "test-workspace" ], - "version": "3.0.0-alpha.0" + "version": "3.0.0-alpha.2" } diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index 98fdf489dc..33230b7eb6 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -581,9 +581,33 @@ function createSchemaResolvers( }; } function resolveEventSignature(call: ts.Signature): EventMeta { - const subtype = typeChecker.getTypeOfSymbolAtLocation(call.parameters[1], symbolNode); let schema: PropertyMetaSchema[]; let declarations: Declaration[]; + let subtype = undefined; + let subtypeStr = '[]'; + let getSchema = () => [] as PropertyMetaSchema[]; + + if (call.parameters.length >= 2) { + subtype = typeChecker.getTypeOfSymbolAtLocation(call.parameters[1], symbolNode); + if ((call.parameters[1].valueDeclaration as any)?.dotDotDotToken) { + subtypeStr = typeChecker.typeToString(subtype); + getSchema = () => typeChecker.getTypeArguments(subtype! as ts.TypeReference).map(resolveSchema); + } + else { + subtypeStr = '['; + for (let i = 1; i < call.parameters.length; i++) { + subtypeStr += typeChecker.typeToString(typeChecker.getTypeOfSymbolAtLocation(call.parameters[i], symbolNode)) + ', '; + } + subtypeStr = subtypeStr.slice(0, -2) + ']'; + getSchema = () => { + const result: PropertyMetaSchema[] = []; + for (let i = 1; i < call.parameters.length; i++) { + result.push(resolveSchema(typeChecker.getTypeOfSymbolAtLocation(call.parameters[i], symbolNode))); + } + return result; + }; + } + } return { name: (typeChecker.getTypeOfSymbolAtLocation(call.parameters[0], symbolNode) as ts.StringLiteralType).value, @@ -592,14 +616,14 @@ function createSchemaResolvers( name: tag.name, text: tag.text !== undefined ? ts.displayPartsToString(tag.text) : undefined, })), - type: typeChecker.typeToString(subtype), + type: subtypeStr, rawType: rawType ? subtype : undefined, signature: typeChecker.signatureToString(call), get declarations() { return declarations ??= call.declaration ? getDeclarations([call.declaration]) : []; }, get schema() { - return schema ??= typeChecker.getTypeArguments(subtype as ts.TypeReference).map(resolveSchema); + return schema ??= getSchema(); }, }; } diff --git a/packages/component-meta/package.json b/packages/component-meta/package.json index 6f2f0a74e9..f2304d26c7 100644 --- a/packages/component-meta/package.json +++ b/packages/component-meta/package.json @@ -1,6 +1,6 @@ { "name": "vue-component-meta", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", @@ -14,9 +14,9 @@ }, "dependencies": { "@volar/typescript": "~2.4.11", - "@vue/language-core": "3.0.0-alpha.0", + "@vue/language-core": "3.0.0-alpha.2", "path-browserify": "^1.0.1", - "vue-component-type-helpers": "3.0.0-alpha.0" + "vue-component-type-helpers": "3.0.0-alpha.2" }, "peerDependencies": { "typescript": "*" diff --git a/packages/component-meta/tests/index.spec.ts b/packages/component-meta/tests/index.spec.ts index acf31f7d35..4d86f4aeb0 100644 --- a/packages/component-meta/tests/index.spec.ts +++ b/packages/component-meta/tests/index.spec.ts @@ -531,7 +531,7 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ const onBaz = meta.events.find(event => event.name === 'baz'); expect(onFoo).toBeDefined(); - expect(onFoo?.type).toEqual('[data?: { foo: string; } | undefined]'); + expect(onFoo?.type).toEqual('[{ foo: string; } | undefined]'); expect(onFoo?.signature).toEqual('(event: "foo", data?: { foo: string; } | undefined): void'); expect(onFoo?.schema).toEqual([ { @@ -560,7 +560,7 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ ]); expect(onBar).toBeDefined(); - expect(onBar?.type).toEqual('[value: { arg1: number; arg2?: any; }]'); + expect(onBar?.type).toEqual('[{ arg1: number; arg2?: any; }]'); expect(onBar?.signature).toEqual('(event: "bar", value: { arg1: number; arg2?: any; }): void'); expect(onBar?.schema).toEqual([ { @@ -593,7 +593,7 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ expect(onBaz).toBeDefined(); expect(onBaz?.type).toEqual('[]'); - expect(onBaz?.signature).toEqual('(event: "baz"): void'); + expect(onBaz?.signature).toEqual('(e: "baz"): void'); expect(onBaz?.schema).toEqual([]); }); @@ -606,7 +606,7 @@ const worker = (checker: ComponentMetaChecker, withTsconfig: boolean) => describ const onBar = meta.events.find(event => event.name === 'bar'); expect(onBar).toBeDefined(); - expect(onBar?.type).toEqual('number'); + expect(onBar?.type).toEqual('[number]'); expect(onBar?.signature).toEqual('(e: "bar", data: number): void'); }); diff --git a/packages/component-type-helpers/package.json b/packages/component-type-helpers/package.json index fab2ab1841..5f7cf514ff 100644 --- a/packages/component-type-helpers/package.json +++ b/packages/component-type-helpers/package.json @@ -1,6 +1,6 @@ { "name": "vue-component-type-helpers", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", diff --git a/packages/language-core/lib/codegen/globalTypes.ts b/packages/language-core/lib/codegen/globalTypes.ts index b68942a112..3e9f012a62 100644 --- a/packages/language-core/lib/codegen/globalTypes.ts +++ b/packages/language-core/lib/codegen/globalTypes.ts @@ -131,10 +131,8 @@ export function generateGlobalTypes({ key: keyof T, index: number, ][]; - // @ts-ignore - function __VLS_getSlotParams(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>; - // @ts-ignore - function __VLS_getSlotParam(slot: T): Parameters<__VLS_PickNotAny, (...args: any[]) => any>>[0]; + function __VLS_getSlotParameters(slot: S, decl?: D): + __VLS_PickNotAny, (...args: any) => any> extends (...args: infer P) => any ? P : any[]; function __VLS_asFunctionalDirective(dir: T): T extends import('${lib}').ObjectDirective ? NonNullable : T extends (...args: any) => any diff --git a/packages/language-core/lib/codegen/script/component.ts b/packages/language-core/lib/codegen/script/component.ts index 2a732228b1..1800762a31 100644 --- a/packages/language-core/lib/codegen/script/component.ts +++ b/packages/language-core/lib/codegen/script/component.ts @@ -143,15 +143,23 @@ export function* generatePropsOption( }[] = []; if (ctx.generatedPropsType) { - codes.push({ - optionExp: [ - `{} as `, - scriptSetupRanges.withDefaults?.arg ? `${ctx.localTypes.WithDefaults}<` : '', - `${ctx.localTypes.TypePropsToOption}<__VLS_PublicProps>`, - scriptSetupRanges.withDefaults?.arg ? `, typeof __VLS_withDefaultsArg>` : '', - ].join(''), - typeOptionExp: `{} as __VLS_PublicProps`, - }); + if (options.vueCompilerOptions.target >= 3.6) { + codes.push({ + optionExp: '{}', + typeOptionExp: `{} as __VLS_PublicProps`, + }); + } + else { + codes.push({ + optionExp: [ + `{} as `, + scriptSetupRanges.withDefaults?.arg ? `${ctx.localTypes.WithDefaults}<` : '', + `${ctx.localTypes.TypePropsToOption}<__VLS_PublicProps>`, + scriptSetupRanges.withDefaults?.arg ? `, typeof __VLS_withDefaultsArg>` : '', + ].join(''), + typeOptionExp: `{} as __VLS_PublicProps`, + }); + } } if (scriptSetupRanges.defineProps?.arg) { const { arg } = scriptSetupRanges.defineProps; @@ -180,6 +188,12 @@ export function* generatePropsOption( const useOption = !useTypeOption || scriptSetupRanges.withDefaults; if (useTypeOption) { + if ( + options.vueCompilerOptions.target >= 3.6 + && scriptSetupRanges.withDefaults?.arg + ) { + yield `__defaults: __VLS_withDefaultsArg,${newLine}`; + } if (codes.length === 1) { yield `__typeProps: `; yield codes[0].typeOptionExp!; diff --git a/packages/language-core/lib/codegen/script/index.ts b/packages/language-core/lib/codegen/script/index.ts index c94bbdea5f..74f7caa315 100644 --- a/packages/language-core/lib/codegen/script/index.ts +++ b/packages/language-core/lib/codegen/script/index.ts @@ -45,7 +45,7 @@ export function* generateScript(options: ScriptCodegenOptions): Generator`; } if (options.sfc.script?.src) { diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index 4d69385426..d886f8ee5d 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -97,15 +97,6 @@ function* generateSetupFunction( syntax: 'return' | 'export default' | undefined ): Generator { let setupCodeModifies: [Code[], number, number][] = []; - for (const { comments } of scriptSetupRanges.defineProp) { - if (comments) { - setupCodeModifies.push([ - [``], - comments.start, - comments.end, - ]); - } - } if (scriptSetupRanges.defineProps) { const { name, statement, callExp, typeArg } = scriptSetupRanges.defineProps; setupCodeModifies.push(...generateDefineWithType( @@ -506,7 +497,7 @@ function* generateComponentProps( const [propName, localName] = getPropAndLocalName(scriptSetup, defineProp); if (defineProp.comments) { - yield generateSfcBlockSection(scriptSetup, defineProp.comments.start, defineProp.comments.end, codeFeatures.all); + yield scriptSetup.content.slice(defineProp.comments.start, defineProp.comments.end); yield newLine; } diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 60d54a1a1a..0ef5884796 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -1,4 +1,4 @@ -import type * as CompilerDOM from '@vue/compiler-dom'; +import * as CompilerDOM from '@vue/compiler-dom'; import type { Code, VueCodeInformation } from '../../types'; import { codeFeatures } from '../codeFeatures'; import { InlayHintInfo } from '../inlayHints'; @@ -8,6 +8,8 @@ import type { TemplateCodegenOptions } from './index'; export type TemplateCodegenContext = ReturnType; +const commentDirectiveRegex = /^$/; + /** * Creates and returns a Context object used for generating type-checkable TS code * from the template section of a .vue file. @@ -106,20 +108,12 @@ export type TemplateCodegenContext = ReturnType) { - let ignoredError = false; - let expectErrorToken: { - errors: number; - node: CompilerDOM.CommentNode; - } | undefined; - let lastGenericComment: { - content: string; - offset: number; - } | undefined; let variableId = 0; function resolveCodeFeatures(features: VueCodeInformation) { - if (features.verification) { - if (ignoredError) { + if (features.verification && stack.length) { + const data = stack[stack.length - 1]; + if (data.ignoreError) { // We are currently in a region of code covered by a @vue-ignore directive, so don't // even bother performing any type-checking: set verification to false. return { @@ -127,17 +121,16 @@ export function createTemplateCodegenContext(options: Pick { - token.errors++; + data.expectError!.token++; return false; }, }, @@ -175,9 +168,25 @@ export function createTemplateCodegenContext(options: Pick(); + }[]>(); + + const stack: { + ignoreError?: boolean; + expectError?: { + token: number; + node: CompilerDOM.CommentNode; + }; + generic?: { + content: string; + offset: number; + }, + }[] = []; + const commentBuffer: CompilerDOM.CommentNode[] = []; return { + get currentInfo() { + return stack[stack.length - 1]; + }, codeFeatures: new Proxy(codeFeatures, { get(target, key: keyof typeof codeFeatures) { const data = target[key]; @@ -189,7 +198,6 @@ export function createTemplateCodegenContext(options: Pick(), + addTemplateRef(name: string, typeExp: string, offset: number) { + let refs = templateRefs.get(name); + if (!refs) { + templateRefs.set(name, refs = []); + } + refs.push({ typeExp, offset }); + }, accessExternalVariable(name: string, offset?: number) { let arr = accessExternalVariables.get(name); if (!arr) { @@ -212,26 +227,26 @@ export function createTemplateCodegenContext(options: Pick { + hasLocalVariable(name: string) { return !!localVars.get(name); }, - addLocalVariable: (name: string) => { + addLocalVariable(name: string) { localVars.set(name, (localVars.get(name) ?? 0) + 1); }, - removeLocalVariable: (name: string) => { + removeLocalVariable(name: string) { localVars.set(name, localVars.get(name)! - 1); }, - getInternalVariable: () => { + getInternalVariable() { return `__VLS_${variableId++}`; }, - getHoistVariable: (originalVar: string) => { + getHoistVariable(originalVar: string) { let name = hoistVars.get(originalVar); if (name === undefined) { hoistVars.set(originalVar, name = `__VLS_${variableId++}`); } return name; }, - generateHoistVariables: function* () { + * generateHoistVariables() { // trick to avoid TS 4081 (#5186) if (hoistVars.size) { yield `// @ts-ignore${newLine}`; @@ -242,52 +257,12 @@ export function createTemplateCodegenContext(options: Pick { - if (!ignoredError) { - ignoredError = true; - yield `// @vue-ignore start${newLine}`; - } - }, - expectError: function* (prevNode: CompilerDOM.CommentNode): Generator { - if (!expectErrorToken) { - expectErrorToken = { - errors: 0, - node: prevNode, - }; - yield `// @vue-expect-error start${newLine}`; - } - }, - resetDirectiveComments: function* (endStr: string): Generator { - if (expectErrorToken) { - const token = expectErrorToken; - yield* wrapWith( - expectErrorToken.node.loc.start.offset, - expectErrorToken.node.loc.end.offset, - { - verification: { - // If no errors/warnings/diagnostics were reported within the region of code covered - // by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error` - // diagnostics to be reported upward. - shouldReport: () => token.errors === 0, - }, - }, - `// @ts-expect-error __VLS_TS_EXPECT_ERROR` - ); - yield `${newLine}${endOfLine}`; - expectErrorToken = undefined; - yield `// @vue-expect-error ${endStr}${newLine}`; - } - if (ignoredError) { - ignoredError = false; - yield `// @vue-ignore ${endStr}${newLine}`; - } - }, - generateAutoImportCompletion: function* (): Generator { + * generateAutoImportCompletion(): Generator { const all = [...accessExternalVariables.entries()]; if (!all.some(([_, offsets]) => offsets.size)) { return; @@ -321,6 +296,71 @@ export function createTemplateCodegenContext(options: Pick { + const data = stack.pop()!; + commentBuffer.length = 0; + if (data.expectError !== undefined) { + yield* wrapWith( + data.expectError.node.loc.start.offset, + data.expectError.node.loc.end.offset, + { + verification: { + // If no errors/warnings/diagnostics were reported within the region of code covered + // by the @vue-expect-error directive, then we should allow any `unused @ts-expect-error` + // diagnostics to be reported upward. + shouldReport: () => data.expectError!.token === 0, + }, + }, + `// @ts-expect-error` + ); + yield `${newLine}${endOfLine}`; + } + }, }; } diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index d651ad6eb3..e1ee400307 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -264,10 +264,7 @@ export function* generateComponent( yield `${endOfLine}`; if (refName && offset) { - ctx.templateRefs.set(refName, { - typeExp: `typeof ${ctx.getHoistVariable(componentInstanceVar)}`, - offset - }); + ctx.addTemplateRef(refName, `typeof ${ctx.getHoistVariable(componentInstanceVar)}`, offset); } if (isRootNode) { ctx.singleRootElTypes.push(`NonNullable['$el']`); @@ -355,10 +352,7 @@ export function* generateElement( if (isVForChild) { typeExp += `[]`; } - ctx.templateRefs.set(refName, { - typeExp, - offset - }); + ctx.addTemplateRef(refName, typeExp, offset); } if (ctx.singleRootNodes.has(node)) { ctx.singleRootElTypes.push(`__VLS_NativeElements['${node.tag}']`); @@ -431,8 +425,8 @@ function* generateCanonicalComponentName(tagText: string, offset: number, featur function* generateComponentGeneric( ctx: TemplateCodegenContext ): Generator { - if (ctx.lastGenericComment) { - const { content, offset } = ctx.lastGenericComment; + if (ctx.currentInfo.generic) { + const { content, offset } = ctx.currentInfo.generic; yield* wrapWith( offset, offset + content.length, @@ -447,7 +441,6 @@ function* generateComponentGeneric( `>` ); } - ctx.lastGenericComment = undefined; } function* generateElementReference( diff --git a/packages/language-core/lib/codegen/template/elementChildren.ts b/packages/language-core/lib/codegen/template/elementChildren.ts index 65de04b9ce..ea7a8a16b8 100644 --- a/packages/language-core/lib/codegen/template/elementChildren.ts +++ b/packages/language-core/lib/codegen/template/elementChildren.ts @@ -9,11 +9,8 @@ export function* generateElementChildren( ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode ): Generator { - yield* ctx.resetDirectiveComments('end of element children start'); - let prev: CompilerDOM.TemplateChildNode | undefined; for (const childNode of node.children) { - yield* generateTemplateChild(options, ctx, childNode, prev); - prev = childNode; + yield* generateTemplateChild(options, ctx, childNode); } yield* ctx.generateAutoImportCompletion(); } diff --git a/packages/language-core/lib/codegen/template/elementDirectives.ts b/packages/language-core/lib/codegen/template/elementDirectives.ts index e91c8d904c..da663f5095 100644 --- a/packages/language-core/lib/codegen/template/elementDirectives.ts +++ b/packages/language-core/lib/codegen/template/elementDirectives.ts @@ -72,9 +72,7 @@ function* generateIdentifier( 'template', prop.loc.start.offset, ctx.resolveCodeFeatures({ - ...codeFeatures.withoutHighlight, - // fix https://github.com/vuejs/language-tools/issues/1905 - ...codeFeatures.additionalCompletion, + ...codeFeatures.withoutHighlightAndCompletion, verification: options.vueCompilerOptions.checkUnknownDirectives && !builtInDirectives.has(prop.name), }) ) diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts index 6015c2621a..38dcca3050 100644 --- a/packages/language-core/lib/codegen/template/elementProps.ts +++ b/packages/language-core/lib/codegen/template/elementProps.ts @@ -141,13 +141,18 @@ export function* generateElementProps( ) ), `: `, - ...generatePropExp( - options, - ctx, - prop, - prop.exp, - ctx.codeFeatures.all, - enableCodeFeatures + ...wrapWith( + prop.arg?.loc.start.offset ?? prop.loc.start.offset, + prop.arg?.loc.end.offset ?? prop.loc.end.offset, + ctx.codeFeatures.verification, + ...generatePropExp( + options, + ctx, + prop, + prop.exp, + ctx.codeFeatures.all, + enableCodeFeatures + ) ) )]; if (enableCodeFeatures) { diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 75acd647a7..747f9f8119 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -50,7 +50,7 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { - yield `type __VLS_TemplateRefs = {${newLine}`; - for (const [name, { typeExp, offset }] of ctx.templateRefs) { - yield* generateObjectProperty( - options, - ctx, - name, - offset, - ctx.codeFeatures.navigationAndCompletion - ); - yield `: ${typeExp},${newLine}`; - } - yield `}${endOfLine}`; + yield `type __VLS_TemplateRefs = {}`; + for (const [name, refs] of ctx.templateRefs) { + yield `${newLine}& `; + if (refs.length >= 2) { + yield `(`; + } + for (let i = 0; i < refs.length; i++) { + const { typeExp, offset } = refs[i]; + if (i) { + yield ` | `; + } + yield `{ `; + yield* generateObjectProperty( + options, + ctx, + name, + offset, + ctx.codeFeatures.navigation + ); + yield `: ${typeExp} }`; + } + if (refs.length >= 2) { + yield `)`; + } + } + yield endOfLine; return `__VLS_TemplateRefs`; } diff --git a/packages/language-core/lib/codegen/template/interpolation.ts b/packages/language-core/lib/codegen/template/interpolation.ts index b46e4d5c07..7881d88236 100644 --- a/packages/language-core/lib/codegen/template/interpolation.ts +++ b/packages/language-core/lib/codegen/template/interpolation.ts @@ -1,10 +1,13 @@ -import { isGloballyAllowed } from '@vue/shared'; +import { isGloballyAllowed, makeMap } from '@vue/shared'; import type * as ts from 'typescript'; import type { Code, VueCodeInformation } from '../../types'; import { getNodeText, getStartEnd } from '../../utils/shared'; -import { collectVars, createTsAst } from '../utils'; +import { collectVars, createTsAst, identifierRegex } from '../utils'; import type { TemplateCodegenContext } from './context'; +// https://github.com/vuejs/core/blob/fb0c3ca519f1fccf52049cd6b8db3a67a669afe9/packages/compiler-core/src/transforms/transformExpression.ts#L47 +const isLiteralWhitelisted = /*@__PURE__*/ makeMap('true,false,null,this'); + export function* generateInterpolation( options: { ts: typeof ts, @@ -14,22 +17,22 @@ export function* generateInterpolation( ctx: TemplateCodegenContext, source: string, data: VueCodeInformation | ((offset: number) => VueCodeInformation) | undefined, - _code: string, + code: string, start: number | undefined, astHolder: any = {}, prefix: string = '', suffix: string = '' ): Generator { - const code = prefix + _code + suffix; - const ast = createTsAst(options.ts, astHolder, code); for (let [section, offset, type] of forEachInterpolationSegment( options.ts, options.destructuredPropNames, options.templateRefNames, ctx, code, - start !== undefined ? start - prefix.length : undefined, - ast + start, + astHolder, + prefix, + suffix )) { if (offset === undefined) { yield section; @@ -37,7 +40,7 @@ export function* generateInterpolation( else { offset -= prefix.length; let addSuffix = ''; - const overLength = offset + section.length - _code.length; + const overLength = offset + section.length - code.length; if (overLength > 0) { addSuffix = section.slice(section.length - overLength); section = section.slice(0, -overLength); @@ -73,80 +76,71 @@ export function* generateInterpolation( interface CtxVar { text: string; - isShorthand: boolean; offset: number; + isShorthand?: boolean; }; +type Segment = [ + fragment: string, + offset: number | undefined, + type?: 'errorMappingOnly' | 'startText' | 'endText', +]; + function* forEachInterpolationSegment( ts: typeof import('typescript'), destructuredPropNames: Set | undefined, templateRefNames: Set | undefined, ctx: TemplateCodegenContext, - code: string, - offset: number | undefined, - ast: ts.SourceFile -): Generator<[fragment: string, offset: number | undefined, type?: 'errorMappingOnly' | 'startText' | 'endText']> { + originalCode: string, + start: number | undefined, + astHolder: any, + prefix: string, + suffix: string +): Generator { + const code = prefix + originalCode + suffix; + const offset = start !== undefined ? start - prefix.length : undefined; let ctxVars: CtxVar[] = []; - const varCb = (id: ts.Identifier, isShorthand: boolean) => { - const text = getNodeText(ts, id, ast); - if ( - ctx.hasLocalVariable(text) - // https://github.com/vuejs/core/blob/245230e135152900189f13a4281302de45fdcfaa/packages/compiler-core/src/transforms/transformExpression.ts#L342-L352 - || isGloballyAllowed(text) - || text === 'require' - || text.startsWith('__VLS_') - ) { - // localVarOffsets.push(localVar.getStart(ast)); - } - else { - ctxVars.push({ - text, - isShorthand: isShorthand, - offset: getStartEnd(ts, id, ast).start, - }); - if (destructuredPropNames?.has(text)) { - return; - } - if (offset !== undefined) { - ctx.accessExternalVariable(text, offset + getStartEnd(ts, id, ast).start); - } - else { - ctx.accessExternalVariable(text); + if (identifierRegex.test(originalCode) && !shouldIdentifierSkipped(ctx, originalCode, destructuredPropNames)) { + ctxVars.push({ + text: originalCode, + offset: prefix.length, + }); + } + else { + const ast = createTsAst(ts, astHolder, code); + const varCb = (id: ts.Identifier, isShorthand: boolean) => { + const text = getNodeText(ts, id, ast); + if (!shouldIdentifierSkipped(ctx, text, destructuredPropNames)) { + ctxVars.push({ + text, + offset: getStartEnd(ts, id, ast).start, + isShorthand, + }); } - } - }; - ts.forEachChild(ast, node => walkIdentifiers(ts, node, ast, varCb, ctx)); + }; + ts.forEachChild(ast, node => walkIdentifiers(ts, node, ast, varCb, ctx)); + } ctxVars = ctxVars.sort((a, b) => a.offset - b.offset); if (ctxVars.length) { - - if (ctxVars[0].isShorthand) { - yield [code.slice(0, ctxVars[0].offset + ctxVars[0].text.length), 0]; - yield [': ', undefined]; - } - else if (ctxVars[0].offset > 0) { - yield [code.slice(0, ctxVars[0].offset), 0, 'startText']; - } - - for (let i = 0; i < ctxVars.length - 1; i++) { + for (let i = 0; i < ctxVars.length; i++) { + const lastVar = ctxVars[i - 1]; const curVar = ctxVars[i]; - const nextVar = ctxVars[i + 1]; - - yield* generateVar(code, ctx.dollarVars, destructuredPropNames, templateRefNames, curVar); + const lastVarEnd = lastVar ? lastVar.offset + lastVar.text.length : 0; - if (nextVar.isShorthand) { - yield [code.slice(curVar.offset + curVar.text.length, nextVar.offset + nextVar.text.length), curVar.offset + curVar.text.length]; + if (curVar.isShorthand) { + yield [code.slice(lastVarEnd, curVar.offset + curVar.text.length), lastVarEnd]; yield [': ', undefined]; } else { - yield [code.slice(curVar.offset + curVar.text.length, nextVar.offset), curVar.offset + curVar.text.length]; + yield [code.slice(lastVarEnd, curVar.offset), lastVarEnd, i ? undefined : 'startText']; } + yield* generateVar(templateRefNames, ctx, code, offset, curVar); } const lastVar = ctxVars.at(-1)!; - yield* generateVar(code, ctx.dollarVars, destructuredPropNames, templateRefNames, lastVar); if (lastVar.offset + lastVar.text.length < code.length) { yield [code.slice(lastVar.offset + lastVar.text.length), lastVar.offset + lastVar.text.length, 'endText']; } @@ -157,17 +151,16 @@ function* forEachInterpolationSegment( } function* generateVar( - code: string, - dollarVars: Set, - destructuredPropNames: Set | undefined, templateRefNames: Set | undefined, + ctx: TemplateCodegenContext, + code: string, + offset: number | undefined, curVar: CtxVar -): Generator<[fragment: string, offset: number | undefined, type?: 'errorMappingOnly']> { +): Generator { // fix https://github.com/vuejs/language-tools/issues/1205 // fix https://github.com/vuejs/language-tools/issues/1264 yield ['', curVar.offset, 'errorMappingOnly']; - const isDestructuredProp = destructuredPropNames?.has(curVar.text) ?? false; const isTemplateRef = templateRefNames?.has(curVar.text) ?? false; if (isTemplateRef) { yield [`__VLS_unref(`, undefined]; @@ -175,12 +168,17 @@ function* generateVar( yield [`)`, undefined]; } else { - if (dollarVars.has(curVar.text)) { - yield [`__VLS_dollars.`, undefined]; + if (offset !== undefined) { + ctx.accessExternalVariable(curVar.text, offset + curVar.offset); } - else if (!isDestructuredProp) { - yield [`__VLS_ctx.`, undefined]; + else { + ctx.accessExternalVariable(curVar.text); + } + + if (ctx.dollarVars.has(curVar.text)) { + yield [`__VLS_dollars.`, undefined]; } + yield [`__VLS_ctx.`, undefined]; yield [code.slice(curVar.offset, curVar.offset + curVar.text.length), curVar.offset]; } } @@ -305,3 +303,17 @@ function walkIdentifiersInTypeReference( ts.forEachChild(node, node => walkIdentifiersInTypeReference(ts, node, cb)); } } + +function shouldIdentifierSkipped( + ctx: TemplateCodegenContext, + text: string, + destructuredPropNames: Set | undefined +) { + return ctx.hasLocalVariable(text) + // https://github.com/vuejs/core/blob/245230e135152900189f13a4281302de45fdcfaa/packages/compiler-core/src/transforms/transformExpression.ts#L342-L352 + || isGloballyAllowed(text) + || isLiteralWhitelisted(text) + || text === 'require' + || text.startsWith('__VLS_') + || destructuredPropNames?.has(text); +} diff --git a/packages/language-core/lib/codegen/template/templateChild.ts b/packages/language-core/lib/codegen/template/templateChild.ts index 8d3bb6518e..444d75269e 100644 --- a/packages/language-core/lib/codegen/template/templateChild.ts +++ b/packages/language-core/lib/codegen/template/templateChild.ts @@ -1,7 +1,7 @@ import * as CompilerDOM from '@vue/compiler-dom'; import type { Code } from '../../types'; import { hyphenateTag } from '../../utils/shared'; -import { endOfLine, newLine } from '../utils'; +import { endOfLine } from '../utils'; import type { TemplateCodegenContext } from './context'; import { generateComponent, generateElement } from './element'; import type { TemplateCodegenOptions } from './index'; @@ -11,8 +11,6 @@ import { generateVFor } from './vFor'; import { generateVIf } from './vIf'; import { generateVSlot } from './vSlot'; -const commentDirectiveRegex = /^$/; - // @ts-ignore const transformContext: CompilerDOM.TransformContext = { onError: () => { }, @@ -33,38 +31,11 @@ export function* generateTemplateChild( options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.RootNode | CompilerDOM.TemplateChildNode | CompilerDOM.SimpleExpressionNode, - prevNode: CompilerDOM.TemplateChildNode | undefined, + enterNode: boolean = true, isVForChild: boolean = false ): Generator { - if (prevNode?.type === CompilerDOM.NodeTypes.COMMENT) { - const match = prevNode.loc.source.match(commentDirectiveRegex); - if (match) { - const { name, content } = match.groups!; - switch (name) { - case 'skip': { - yield `// @vue-skip${newLine}`; - return; - } - case 'ignore': { - yield* ctx.ignoreError(); - break; - } - case 'expect-error': { - yield* ctx.expectError(prevNode); - break; - } - case 'generic': { - const text = content.trim(); - if (text.startsWith('{') && text.endsWith('}')) { - ctx.lastGenericComment = { - content: text.slice(1, -1), - offset: prevNode.loc.start.offset + prevNode.loc.source.indexOf('{') + 1, - }; - } - break; - } - } - } + if (enterNode && !ctx.enter(node)) { + return; } const cur = node as CompilerDOM.ElementNode | CompilerDOM.IfNode | CompilerDOM.ForNode; @@ -76,12 +47,9 @@ export function* generateTemplateChild( for (const item of collectSingleRootNodes(options, node.children)) { ctx.singleRootNodes.add(item); } - let prev: CompilerDOM.TemplateChildNode | undefined; for (const childNode of node.children) { - yield* generateTemplateChild(options, ctx, childNode, prev); - prev = childNode; + yield* generateTemplateChild(options, ctx, childNode); } - yield* ctx.resetDirectiveComments('end of root'); } else if (node.type === CompilerDOM.NodeTypes.ELEMENT) { const vForNode = getVForNode(node); @@ -119,13 +87,13 @@ export function* generateTemplateChild( } else if (node.type === CompilerDOM.NodeTypes.TEXT_CALL) { // {{ var }} - yield* generateTemplateChild(options, ctx, node.content, undefined); + yield* generateTemplateChild(options, ctx, node.content, false); } else if (node.type === CompilerDOM.NodeTypes.COMPOUND_EXPRESSION) { // {{ ... }} {{ ... }} for (const childNode of node.children) { if (typeof childNode === 'object') { - yield* generateTemplateChild(options, ctx, childNode, undefined); + yield* generateTemplateChild(options, ctx, childNode, false); } } } @@ -143,7 +111,6 @@ export function* generateTemplateChild( `(`, `)${endOfLine}` ); - yield* ctx.resetDirectiveComments('end of INTERPOLATION'); } else if (node.type === CompilerDOM.NodeTypes.IF) { // v-if / v-else-if / v-else @@ -156,6 +123,10 @@ export function* generateTemplateChild( else if (node.type === CompilerDOM.NodeTypes.TEXT) { // not needed progress } + + if (enterNode) { + yield* ctx.exit(); + } } function* collectSingleRootNodes( diff --git a/packages/language-core/lib/codegen/template/vFor.ts b/packages/language-core/lib/codegen/template/vFor.ts index 41ce8dced3..23002ab020 100644 --- a/packages/language-core/lib/codegen/template/vFor.ts +++ b/packages/language-core/lib/codegen/template/vFor.ts @@ -81,13 +81,8 @@ export function* generateVFor( } } } - if (isFragment) { - yield* ctx.resetDirectiveComments('end of v-for start'); - } - let prev: CompilerDOM.TemplateChildNode | undefined; for (const childNode of node.children) { - yield* generateTemplateChild(options, ctx, childNode, prev, true); - prev = childNode; + yield* generateTemplateChild(options, ctx, childNode, isFragment, true); } for (const varName of forBlockVars) { ctx.removeLocalVariable(varName); diff --git a/packages/language-core/lib/codegen/template/vIf.ts b/packages/language-core/lib/codegen/template/vIf.ts index 21c03fe767..bff60bad8e 100644 --- a/packages/language-core/lib/codegen/template/vIf.ts +++ b/packages/language-core/lib/codegen/template/vIf.ts @@ -50,13 +50,8 @@ export function* generateVIf( } yield `{${newLine}`; - if (isFragment(node)) { - yield* ctx.resetDirectiveComments('end of v-if start'); - } - let prev: CompilerDOM.TemplateChildNode | undefined; for (const childNode of branch.children) { - yield* generateTemplateChild(options, ctx, childNode, prev); - prev = childNode; + yield* generateTemplateChild(options, ctx, childNode, isFragment(node)); } yield* ctx.generateAutoImportCompletion(); yield `}${newLine}`; diff --git a/packages/language-core/lib/codegen/template/vSlot.ts b/packages/language-core/lib/codegen/template/vSlot.ts index 974209daf2..078edc31d0 100644 --- a/packages/language-core/lib/codegen/template/vSlot.ts +++ b/packages/language-core/lib/codegen/template/vSlot.ts @@ -1,4 +1,5 @@ import * as CompilerDOM from '@vue/compiler-dom'; +import type * as ts from 'typescript'; import type { Code } from '../../types'; import { collectVars, createTsAst, endOfLine, newLine } from '../utils'; import { wrapWith } from '../utils/wrapWith'; @@ -41,43 +42,20 @@ export function* generateVSlot( `default` ); } - yield `: __VLS_thisSlot } = ${ctx.currentComponent.ctxVar}.slots!${endOfLine}`; + yield `: __VLS_slot } = ${ctx.currentComponent.ctxVar}.slots!${endOfLine}`; if (slotDir.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { const slotAst = createTsAst(options.ts, slotDir, `(${slotDir.exp.content}) => {}`); collectVars(options.ts, slotAst, slotAst, slotBlockVars); - if (!slotDir.exp.content.includes(':')) { - yield `const [`; - yield [ - slotDir.exp.content, - 'template', - slotDir.exp.loc.start.offset, - ctx.codeFeatures.all, - ]; - yield `] = __VLS_getSlotParams(__VLS_thisSlot)${endOfLine}`; - } - else { - yield `const `; - yield [ - slotDir.exp.content, - 'template', - slotDir.exp.loc.start.offset, - ctx.codeFeatures.all, - ]; - yield ` = __VLS_getSlotParam(__VLS_thisSlot)${endOfLine}`; - } + yield* generateSlotParameters(options, ctx, slotAst, slotDir.exp); } for (const varName of slotBlockVars) { ctx.addLocalVariable(varName); } - yield* ctx.resetDirectiveComments('end of slot children start'); - - let prev: CompilerDOM.TemplateChildNode | undefined; for (const childNode of node.children) { - yield* generateTemplateChild(options, ctx, childNode, prev); - prev = childNode; + yield* generateTemplateChild(options, ctx, childNode); } for (const varName of slotBlockVars) { @@ -109,6 +87,71 @@ export function* generateVSlot( yield `}${newLine}`; } +function* generateSlotParameters( + options: TemplateCodegenOptions, + ctx: TemplateCodegenContext, + ast: ts.SourceFile, + exp: CompilerDOM.SimpleExpressionNode +): Generator { + const { ts } = options; + + const statement = ast.statements[0]; + if (!ts.isExpressionStatement(statement) || !ts.isArrowFunction(statement.expression)) { + return; + } + + const { expression } = statement; + const startOffset = exp.loc.start.offset - 1; + const modifies: [Code[], number, number][] = []; + const types: (Code | null)[] = []; + + for (const { name, type } of expression.parameters) { + if (type) { + modifies.push([ + [``], + name.end, + type.end, + ]); + types.push(chunk(type.getStart(ast), type.end)); + } + else { + types.push(null); + } + } + + yield `const [`; + let nextStart = 1; + for (const [codes, start, end] of modifies) { + yield chunk(nextStart, start); + yield* codes; + nextStart = end; + } + yield chunk(nextStart, expression.equalsGreaterThanToken.pos - 1); + yield `] = __VLS_getSlotParameters(__VLS_slot`; + + if (types.some(t => t)) { + yield `, `; + yield* wrapWith( + exp.loc.start.offset, + exp.loc.end.offset, + ctx.codeFeatures.verification, + `(`, + ...types.flatMap(type => type ? [`_: `, type, `, `] : `_, `), + `) => [] as any` + ); + } + yield `)${endOfLine}`; + + function chunk(start: number, end: number): Code { + return [ + ast.text.slice(start, end), + 'template', + startOffset + start, + ctx.codeFeatures.all, + ]; + } +} + export function* generateImplicitDefaultSlot( ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode diff --git a/packages/language-core/lib/parsers/scriptSetupRanges.ts b/packages/language-core/lib/parsers/scriptSetupRanges.ts index 54200873f5..790ffd38c3 100644 --- a/packages/language-core/lib/parsers/scriptSetupRanges.ts +++ b/packages/language-core/lib/parsers/scriptSetupRanges.ts @@ -249,7 +249,7 @@ export function parseScriptSetupRanges( defaultValue, required, isModel: isDefineModel, - comments: getCommentsRange(ts, node, parents, ast), + comments: getClosestMultiLineCommentRange(ts, node, parents, ast), argNode: options, }); } @@ -537,7 +537,7 @@ function getStatementRange( return statementRange; } -function getCommentsRange( +function getClosestMultiLineCommentRange( ts: typeof import('typescript'), node: ts.Node, parents: ts.Node[], @@ -549,11 +549,14 @@ function getCommentsRange( } node = parents[i]; } - const comments = ts.getLeadingCommentRanges(ast.text, node.pos); - if (comments?.length) { + const comment = ts.getLeadingCommentRanges(ast.text, node.pos) + ?.reverse() + .find(range => range.kind === 3 satisfies ts.SyntaxKind.MultiLineCommentTrivia); + + if (comment) { return { - start: comments[0].pos, - end: comments.at(-1)!.end, + start: comment.pos, + end: comment.end, }; } } diff --git a/packages/language-core/lib/plugins/vue-tsx.ts b/packages/language-core/lib/plugins/vue-tsx.ts index ae63e109ac..7a3fb5d44d 100644 --- a/packages/language-core/lib/plugins/vue-tsx.ts +++ b/packages/language-core/lib/plugins/vue-tsx.ts @@ -12,6 +12,8 @@ import { CompilerOptionsResolver } from '../utils/ts'; export const tsCodegen = new WeakMap>(); +const validLangs = new Set(['js', 'jsx', 'ts', 'tsx']); + const plugin: VueLanguagePlugin = ctx => { let appendedGlobalTypes = false; @@ -27,14 +29,10 @@ const plugin: VueLanguagePlugin = ctx => { getEmbeddedCodes(fileName, sfc) { const codegen = useCodegen(fileName, sfc); - const files: { - id: string; - lang: string; - }[] = []; - if (['js', 'ts', 'jsx', 'tsx'].includes(codegen.getLang())) { - files.push({ id: 'script_' + codegen.getLang(), lang: codegen.getLang() }); - } - return files; + return [{ + id: 'script_' + codegen.getLang(), + lang: codegen.getLang(), + }]; }, resolveEmbeddedCode(fileName, sfc, embeddedFile) { @@ -71,11 +69,24 @@ function createTsx( ) { const ts = ctx.modules.typescript; + const getRawLang = computed(() => { + if (sfc.script && sfc.scriptSetup) { + if (sfc.scriptSetup.lang !== 'js') { + return sfc.scriptSetup.lang; + } + else { + return sfc.script.lang; + } + } + return sfc.scriptSetup?.lang ?? sfc.script?.lang; + }); + const getLang = computed(() => { - return !sfc.script && !sfc.scriptSetup ? 'ts' - : sfc.scriptSetup && sfc.scriptSetup.lang !== 'js' ? sfc.scriptSetup.lang - : sfc.script && sfc.script.lang !== 'js' ? sfc.script.lang - : 'js'; + const rawLang = getRawLang(); + if (rawLang && validLangs.has(rawLang)) { + return rawLang; + } + return 'ts'; }); const getResolvedOptions = computed(() => { @@ -89,71 +100,63 @@ function createTsx( }); const getScriptRanges = computed(() => - sfc.script + sfc.script && validLangs.has(sfc.script.lang) ? parseScriptRanges(ts, sfc.script.ast, !!sfc.scriptSetup, false) : undefined ); const getScriptSetupRanges = computed(() => - sfc.scriptSetup + sfc.scriptSetup && validLangs.has(sfc.scriptSetup.lang) ? parseScriptSetupRanges(ts, sfc.scriptSetup.ast, getResolvedOptions()) : undefined ); - const getSetupBindingNames = computedSet( - computed(() => { - const newNames = new Set(); - const bindings = getScriptSetupRanges()?.bindings; - if (sfc.scriptSetup && bindings) { - for (const { range } of bindings) { - newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); - } + const getSetupBindingNames = computedSet(() => { + const newNames = new Set(); + const bindings = getScriptSetupRanges()?.bindings; + if (sfc.scriptSetup && bindings) { + for (const { range } of bindings) { + newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); } - return newNames; - }) - ); + } + return newNames; + }); - const getSetupImportComponentNames = computedSet( - computed(() => { - const newNames = new Set(); - const bindings = getScriptSetupRanges()?.bindings; - if (sfc.scriptSetup && bindings) { - for (const { range, moduleName, isDefaultImport, isNamespace } of bindings) { - if ( - moduleName - && isDefaultImport - && !isNamespace - && ctx.vueCompilerOptions.extensions.some(ext => moduleName.endsWith(ext)) - ) { - newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); - } + const getSetupImportComponentNames = computedSet(() => { + const newNames = new Set(); + const bindings = getScriptSetupRanges()?.bindings; + if (sfc.scriptSetup && bindings) { + for (const { range, moduleName, isDefaultImport, isNamespace } of bindings) { + if ( + moduleName + && isDefaultImport + && !isNamespace + && ctx.vueCompilerOptions.extensions.some(ext => moduleName.endsWith(ext)) + ) { + newNames.add(sfc.scriptSetup.content.slice(range.start, range.end)); } } - return newNames; - }) - ); + } + return newNames; + }); - const getSetupDestructuredPropNames = computedSet( - computed(() => { - const newNames = new Set(getScriptSetupRanges()?.defineProps?.destructured?.keys()); - const rest = getScriptSetupRanges()?.defineProps?.destructuredRest; - if (rest) { - newNames.add(rest); - } - return newNames; - }) - ); + const getSetupDestructuredPropNames = computedSet(() => { + const newNames = new Set(getScriptSetupRanges()?.defineProps?.destructured?.keys()); + const rest = getScriptSetupRanges()?.defineProps?.destructuredRest; + if (rest) { + newNames.add(rest); + } + return newNames; + }); - const getSetupTemplateRefNames = computedSet( - computed(() => { - const newNames = new Set( - getScriptSetupRanges()?.useTemplateRef - .map(({ name }) => name) - .filter(name => name !== undefined) - ); - return newNames; - }) - ); + const getSetupTemplateRefNames = computedSet(() => { + const newNames = new Set( + getScriptSetupRanges()?.useTemplateRef + .map(({ name }) => name) + .filter(name => name !== undefined) + ); + return newNames; + }); const setupHasDefineSlots = computed(() => !!getScriptSetupRanges()?.defineSlots); diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 623052da6d..6ad9c6619d 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -11,7 +11,7 @@ export { VueEmbeddedCode }; export type RawVueCompilerOptions = Partial> & { strictTemplates?: boolean; - target?: 'auto' | 2 | 2.7 | 3 | 3.3 | 3.5 | 99 | number; + target?: 'auto' | 2 | 2.7 | 3 | 3.3 | 3.5 | 3.6 | 99 | number; plugins?: string[]; }; diff --git a/packages/language-core/package.json b/packages/language-core/package.json index da5f56f150..6ea3ee603f 100644 --- a/packages/language-core/package.json +++ b/packages/language-core/package.json @@ -1,6 +1,6 @@ { "name": "@vue/language-core", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", diff --git a/packages/language-core/schemas/vue-tsconfig.schema.json b/packages/language-core/schemas/vue-tsconfig.schema.json index 8a59428080..9f776497b0 100644 --- a/packages/language-core/schemas/vue-tsconfig.schema.json +++ b/packages/language-core/schemas/vue-tsconfig.schema.json @@ -12,7 +12,9 @@ 2.7, 3, 3.3, - 3.5 + 3.5, + 3.6, + 99 ], "markdownDescription": "Target version of Vue." }, @@ -43,12 +45,12 @@ "strictTemplates": { "type": "boolean", "default": false, - "markdownDescription": "Strict props, component type-checking in templates." + "markdownDescription": "Enables strict templates. When set to `true`, all `checkUnknown*` options will be enabled." }, "strictVModel": { "type": "boolean", "default": false, - "markdownDescription": "Strict `v-model` type-checking. If not set, uses the 'strictTemplates' value." + "markdownDescription": "Strict type constraints of `v-model`. If not set, uses the 'strictTemplates' value." }, "checkUnknownProps": { "type": "boolean", diff --git a/packages/language-plugin-pug/package.json b/packages/language-plugin-pug/package.json index 25f18fba3a..2d03b892e7 100644 --- a/packages/language-plugin-pug/package.json +++ b/packages/language-plugin-pug/package.json @@ -1,6 +1,6 @@ { "name": "@vue/language-plugin-pug", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", @@ -19,6 +19,6 @@ "devDependencies": { "@types/node": "^22.10.4", "@vue/compiler-dom": "^3.5.0", - "@vue/language-core": "3.0.0-alpha.0" + "@vue/language-core": "3.0.0-alpha.2" } } diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index 551f5d653b..a892205b7b 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -53,7 +53,7 @@ connection.onInitialize(params => { { file: fileName, needFileNameList: false, - } + } satisfies ts.server.protocol.ProjectInfoRequestArgs ); file2ProjectInfo.set(fileName, projectInfoPromise); } @@ -115,8 +115,26 @@ connection.onInitialize(params => { getPropertiesAtLocation(...args) { return sendTsRequest('vue:getPropertiesAtLocation', args); }, - getQuickInfoAtPosition(...args) { - return sendTsRequest('vue:getQuickInfoAtPosition', args); + getDocumentHighlights(fileName, position) { + return sendTsRequest( + 'documentHighlights-full', // internal command + { + file: fileName, + ...{ position } as unknown as { line: number; offset: number; }, + filesToSearch: [fileName], + } satisfies ts.server.protocol.DocumentHighlightsRequestArgs + ); + }, + async getQuickInfoAtPosition(fileName, { line, character }) { + const result = await sendTsRequest( + ts.server.protocol.CommandTypes.Quickinfo, + { + file: fileName, + line: line + 1, + offset: character + 1, + } satisfies ts.server.protocol.FileLocationRequestArgs + ); + return ts.displayPartsToString(result?.displayParts ?? []); }, } : undefined) ); diff --git a/packages/language-server/package.json b/packages/language-server/package.json index 434b4945af..4e5a39ade1 100644 --- a/packages/language-server/package.json +++ b/packages/language-server/package.json @@ -1,6 +1,6 @@ { "name": "@vue/language-server", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", @@ -16,14 +16,16 @@ "directory": "packages/language-server" }, "dependencies": { - "@typescript/server-harness": "latest", "@volar/language-core": "~2.4.11", "@volar/language-server": "~2.4.11", "@volar/test-utils": "~2.4.11", - "@vue/language-core": "3.0.0-alpha.0", - "@vue/language-service": "3.0.0-alpha.0", - "@vue/typescript-plugin": "3.0.0-alpha.0", + "@vue/language-core": "3.0.0-alpha.2", + "@vue/language-service": "3.0.0-alpha.2", + "@vue/typescript-plugin": "3.0.0-alpha.2", "vscode-languageserver-protocol": "^3.17.5", "vscode-uri": "^3.0.8" + }, + "devDependencies": { + "@typescript/server-harness": "latest" } } diff --git a/packages/language-service/index.ts b/packages/language-service/index.ts index 123476a697..01cd1f94df 100644 --- a/packages/language-service/index.ts +++ b/packages/language-service/index.ts @@ -22,6 +22,7 @@ import { create as createVueCompilerDomErrorsPlugin } from './lib/plugins/vue-co import { create as createVueCompleteDefineAssignmentPlugin } from './lib/plugins/vue-complete-define-assignment'; import { create as createVueDirectiveCommentsPlugin } from './lib/plugins/vue-directive-comments'; import { create as createVueDocumentDropPlugin } from './lib/plugins/vue-document-drop'; +import { create as createVueDocumentHighlightsPlugin } from './lib/plugins/vue-document-highlights'; import { create as createVueDocumentLinksPlugin } from './lib/plugins/vue-document-links'; import { create as createVueExtractFilePlugin } from './lib/plugins/vue-extract-file'; import { create as createVueInlayHintsPlugin } from './lib/plugins/vue-inlayhints'; @@ -142,8 +143,7 @@ export function getFullLanguageServicePlugins(ts: typeof import('typescript')) { if (!sourceScript) { return; } - const document = context.documents.get(uri, sourceScript.languageId, sourceScript.snapshot); - const hover = await languageService.getHover(uri, document.positionAt(position)); + const hover = await languageService.getHover(uri, position); let text = ''; if (typeof hover?.contents === 'string') { text = hover.contents; @@ -172,15 +172,22 @@ export function getFullLanguageServicePlugins(ts: typeof import('typescript')) { } } +import type * as ts from 'typescript'; + export function getHybridModeLanguageServicePlugins( ts: typeof import('typescript'), - getTsPluginClient: import('@vue/typescript-plugin/lib/requests').Requests | undefined + tsPluginClient: import('@vue/typescript-plugin/lib/requests').Requests & { + getDocumentHighlights: (fileName: string, position: number) => Promise; + } | undefined ) { const plugins = [ createTypeScriptSyntacticPlugin(ts), createTypeScriptDocCommentTemplatePlugin(ts), - ...getCommonLanguageServicePlugins(ts, () => getTsPluginClient) + ...getCommonLanguageServicePlugins(ts, () => tsPluginClient) ]; + if (tsPluginClient) { + plugins.push(createVueDocumentHighlightsPlugin(tsPluginClient.getDocumentHighlights)); + } for (const plugin of plugins) { // avoid affecting TS plugin delete plugin.capabilities.semanticTokensProvider; @@ -203,8 +210,8 @@ function getCommonLanguageServicePlugins( createVueCompilerDomErrorsPlugin(), createVueSfcPlugin(), createVueTwoslashQueriesPlugin(getTsPluginClient), - createVueDocumentLinksPlugin(), createVueDocumentDropPlugin(ts, getTsPluginClient), + createVueDocumentLinksPlugin(), createVueCompleteDefineAssignmentPlugin(), createVueAutoDotValuePlugin(ts, getTsPluginClient), createVueAutoAddSpacePlugin(), diff --git a/packages/language-service/lib/plugins/vue-document-highlights.ts b/packages/language-service/lib/plugins/vue-document-highlights.ts new file mode 100644 index 0000000000..991b7476cf --- /dev/null +++ b/packages/language-service/lib/plugins/vue-document-highlights.ts @@ -0,0 +1,50 @@ +import type { DocumentHighlightKind, LanguageServicePlugin } from '@volar/language-service'; +import { VueVirtualCode } from '@vue/language-core'; +import type * as ts from 'typescript'; +import { URI } from 'vscode-uri'; + +export function create( + getDocumentHighlights: (fileName: string, position: number) => Promise +): LanguageServicePlugin { + return { + name: 'vue-document-highlights', + capabilities: { + documentHighlightProvider: true, + }, + create(context) { + return { + async provideDocumentHighlights(document, position) { + const uri = URI.parse(document.uri); + const decoded = context.decodeEmbeddedDocumentUri(uri); + const sourceScript = decoded && context.language.scripts.get(decoded[0]); + const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]); + if (!sourceScript?.generated || virtualCode?.id !== 'main') { + return; + } + + const root = sourceScript.generated.root; + if (!(root instanceof VueVirtualCode)) { + return; + } + + const result = await getDocumentHighlights(root.fileName, document.offsetAt(position)); + + return result + ?.filter(({ fileName }) => fileName === root.fileName) + .flatMap(({ highlightSpans }) => highlightSpans) + .map(({ textSpan, kind }) => ({ + range: { + start: document.positionAt(textSpan.start), + end: document.positionAt(textSpan.start + textSpan.length), + }, + kind: kind === 'reference' + ? 2 satisfies typeof DocumentHighlightKind.Read + : kind === 'writtenReference' + ? 3 satisfies typeof DocumentHighlightKind.Write + : 1 satisfies typeof DocumentHighlightKind.Text, + })); + }, + }; + }, + }; +} diff --git a/packages/language-service/lib/plugins/vue-twoslash-queries.ts b/packages/language-service/lib/plugins/vue-twoslash-queries.ts index 014660bd56..2f9cc2ab19 100644 --- a/packages/language-service/lib/plugins/vue-twoslash-queries.ts +++ b/packages/language-service/lib/plugins/vue-twoslash-queries.ts @@ -46,7 +46,7 @@ export function create( for (const [pointerPosition, hoverOffset] of hoverOffsets) { const map = context.language.maps.get(virtualCode, sourceScript); for (const [sourceOffset] of map.toSourceLocation(hoverOffset)) { - const quickInfo = await tsPluginClient?.getQuickInfoAtPosition(root.fileName, sourceOffset); + const quickInfo = await tsPluginClient?.getQuickInfoAtPosition(root.fileName, document.positionAt(sourceOffset)); if (quickInfo) { inlayHints.push({ position: { line: pointerPosition.line, character: pointerPosition.character + 2 }, diff --git a/packages/language-service/package.json b/packages/language-service/package.json index 6fb6d973f3..91ab6b5e46 100644 --- a/packages/language-service/package.json +++ b/packages/language-service/package.json @@ -1,6 +1,6 @@ { "name": "@vue/language-service", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "data", @@ -21,9 +21,9 @@ "@volar/language-service": "~2.4.11", "@volar/typescript": "~2.4.11", "@vue/compiler-dom": "^3.5.0", - "@vue/language-core": "3.0.0-alpha.0", + "@vue/language-core": "3.0.0-alpha.2", "@vue/shared": "^3.5.0", - "@vue/typescript-plugin": "3.0.0-alpha.0", + "@vue/typescript-plugin": "3.0.0-alpha.2", "alien-signals": "^1.0.3", "path-browserify": "^1.0.1", "volar-service-css": "0.0.62", diff --git a/packages/tsc/package.json b/packages/tsc/package.json index a71f022002..83c4baf083 100644 --- a/packages/tsc/package.json +++ b/packages/tsc/package.json @@ -1,6 +1,6 @@ { "name": "vue-tsc", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "bin", @@ -21,7 +21,7 @@ }, "dependencies": { "@volar/typescript": "~2.4.11", - "@vue/language-core": "3.0.0-alpha.0" + "@vue/language-core": "3.0.0-alpha.2" }, "devDependencies": { "@types/node": "^22.10.4" diff --git a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap index 25d198fabd..e1c250a3f8 100644 --- a/packages/tsc/tests/__snapshots__/dts.spec.ts.snap +++ b/packages/tsc/tests/__snapshots__/dts.spec.ts.snap @@ -44,23 +44,83 @@ export default _default; `; exports[`vue-tsc-dts > Input: empty-component/component.vue, Output: empty-component/component.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: empty-component/custom-extension-component.cext, Output: empty-component/custom-extension-component.cext.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: events/component-class.vue, Output: events/component-class.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { - foo: (value: string) => any; -}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{ - onFoo?: (value: string) => any; -}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"type __VLS_Emit = { + /** Emitted when foo... */ + (evt: "foo", value: string): void; +}; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: __VLS_Emit; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; @@ -145,7 +205,27 @@ type __VLS_PrettifyLocal = { `; exports[`vue-tsc-dts > Input: generic/main.vue, Output: generic/main.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; @@ -167,102 +247,87 @@ exports[`vue-tsc-dts > Input: options-api/component.ts, Output: options-api/comp */ password: string; } -declare const _default: import("vue").DefineComponent { - foo: string; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: { + /** + * Default number + */ + numberDefault: { + type: NumberConstructor; + default: number; }; - }; - /** - * Default function Array - */ - arrayDefault: { - type: ArrayConstructor; - default: () => number[]; - }; - /** - * Default function more complex - */ - complexDefault: { - type: ArrayConstructor; - default: (props: any) => any[]; - }; -}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, { - submit: ({ email, password }: SubmitPayload) => boolean; -}, string, import("vue").PublicProps, Readonly { - foo: string; + /** + * Default function Object + */ + objectDefault: { + type: ObjectConstructor; + default: () => { + foo: string; + }; + }; + /** + * Default function Array + */ + arrayDefault: { + type: ArrayConstructor; + default: () => number[]; + }; + /** + * Default function more complex + */ + complexDefault: { + type: ArrayConstructor; + default: (props: any) => any[]; }; }; - /** - * Default function Array - */ - arrayDefault: { - type: ArrayConstructor; - default: () => number[]; - }; - /** - * Default function more complex - */ - complexDefault: { - type: ArrayConstructor; - default: (props: any) => any[]; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: { + submit: ({ email, password }: SubmitPayload) => boolean; }; -}>> & Readonly<{ - onSubmit?: (args_0: SubmitPayload) => any; -}>, { - numberDefault: number; - objectDefault: Record; - arrayDefault: unknown[]; - complexDefault: unknown[]; -}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: reference-type-events/component.vue, Output: reference-type-events/component.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & { - foo: (data?: { - foo: string; - }) => any; - bar: (value: { - arg1: number; - arg2?: any; - }) => any; - baz: () => any; -}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{ - onFoo?: (data?: { - foo: string; - }) => any; - onBar?: (value: { - arg1: number; - arg2?: any; - }) => any; - onBaz?: () => any; -}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"import { MyEvents } from './my-events'; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: MyEvents; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; @@ -287,12 +352,32 @@ export {}; `; exports[`vue-tsc-dts > Input: reference-type-exposed/component.vue, Output: reference-type-exposed/component.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent<{}, { - /** - * a counter string - */ - counter: import("vue").Ref; -}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +"declare const _default: import("vue").DefineComponent2<{ + setup(): { + /** + * a counter string + */ + counter: import("vue").Ref; + }; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; @@ -313,25 +398,62 @@ exports[`vue-tsc-dts > Input: reference-type-model/component.vue, Output: refere 'bar'?: string; 'barModifiers'?: Partial>; }; -declare const _default: import("vue").DefineComponent<__VLS_PublicProps, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, { - "update:modelValue": (value: number) => any; - "update:foo": (value: boolean) => any; - "update:bar": (value: string) => any; -}, string, import("vue").PublicProps, Readonly<__VLS_PublicProps> & Readonly<{ - "onUpdate:modelValue"?: (value: number) => any; - "onUpdate:foo"?: (value: boolean) => any; - "onUpdate:bar"?: (value: string) => any; -}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; +type __VLS_ModelEmit = { + 'update:modelValue': [value: number]; + 'update:foo': [value: boolean]; + 'update:bar': [value: string | undefined]; +}; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: __VLS_PublicProps; + __typeEmits: __VLS_ModelEmit; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: reference-type-props/component.vue, Output: reference-type-props/component.vue.d.ts 1`] = ` "import { MyProps } from './my-props'; -declare const _default: import("vue").DefineComponent & Readonly<{}>, { - bar: number; - baz: string[]; -}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: MyProps; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: { + bar: number; + baz: () => string[]; + }; +}>; export default _default; " `; @@ -340,152 +462,142 @@ exports[`vue-tsc-dts > Input: reference-type-props/component-destructure.vue, Ou "type __VLS_Props = { text: string; }; -declare const _default: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>; +declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: __VLS_Props; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: reference-type-props/component-js.vue, Output: reference-type-props/component-js.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly> & Readonly<{}>, { - bar: string; -}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; exports[`vue-tsc-dts > Input: reference-type-props/component-js-setup.vue, Output: reference-type-props/component-js-setup.vue.d.ts 1`] = ` -"declare const _default: import("vue").DefineComponent number[]; - }; -}>, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly number[]; +"declare const _default: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: { + foo: { + type: StringConstructor; + required: true; + }; + bar: { + type: StringConstructor; + default: string; + }; + baz: { + type: StringConstructor; + }; + xfoo: { + readonly type: StringConstructor; + readonly required: true; + }; + xbar: { + readonly type: StringConstructor; + readonly value: ""; + }; + xbaz: { + readonly type: StringConstructor; + }; + /** + * The hello property. + * + * @since v1.0.0 + */ + hello: { + type: StringConstructor; + default: string; + }; + numberOrStringProp: { + type: (NumberConstructor | StringConstructor)[]; + default: number; + }; + arrayProps: { + type: ArrayConstructor; + default: () => number[]; + }; }; -}>> & Readonly<{}>, { - bar: string; - hello: string; - numberOrStringProp: string | number; - arrayProps: unknown[]; -}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; export default _default; " `; @@ -612,7 +724,27 @@ type __VLS_Slots = {} & { } & { vbind?: (props: typeof __VLS_7) => any; }; -declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +declare const __VLS_component: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; declare const _default: __VLS_WithSlots; export default _default; type __VLS_WithSlots = T & { @@ -638,7 +770,27 @@ type __VLS_Slots = { }) => VNode[]; 'no-bind': () => VNode[]; }; -declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +declare const __VLS_component: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; declare const _default: __VLS_WithSlots; export default _default; type __VLS_WithSlots = T & { @@ -655,7 +807,27 @@ exports[`vue-tsc-dts > Input: template-slots/component-destructuring.vue, Output num: number; }) => any[]; }; -declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +declare const __VLS_component: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; declare const _default: __VLS_WithSlots; export default _default; type __VLS_WithSlots = T & { @@ -684,7 +856,27 @@ type __VLS_Slots = {} & { } & { vbind?: (props: typeof __VLS_7) => any; }; -declare const __VLS_component: import("vue").DefineComponent<{}, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<{}> & Readonly<{}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, true, {}, any>; +declare const __VLS_component: import("vue").DefineComponent2<{ + setup(): {}; + data(): {}; + props: {}; + computed: {}; + methods: {}; + mixins: {}[]; + extends: {}; + emits: string[]; + slots: {}; + inject: {}; + components: {}; + directives: {}; + provide: {}; + expose: string; + __typeProps: unknown; + __typeEmits: unknown; + __typeRefs: {}; + __typeEl: any; + __defaults: unknown; +}>; declare const _default: __VLS_WithSlots; export default _default; type __VLS_WithSlots = T & { @@ -716,13 +908,17 @@ exports[`vue-tsc-dts > Input: ts-component/component.tsx, Output: ts-component/c exports[`vue-tsc-dts > Input: ts-named-export/component.ts, Output: ts-named-export/component.d.ts 1`] = ` "export declare const Foo: import("vue").DefineSetupFnComponent<{ foo: string; -}, {}, {}, { +}, string[], {}, { foo: string; -} & {}, import("vue").PublicProps>; +} & { + [x: \`on\${Capitalize}\`]: (...args: any[]) => any; +}, import("vue").PublicProps>; export declare const Bar: import("vue").DefineSetupFnComponent<{ bar?: number; -}, {}, {}, { +}, string[], {}, { bar?: number; -} & {}, import("vue").PublicProps>; +} & { + [x: \`on\${Capitalize}\`]: (...args: any[]) => any; +}, import("vue").PublicProps>; " `; diff --git a/packages/tsc/tests/typecheck.spec.ts b/packages/tsc/tests/typecheck.spec.ts index 8ed14447e2..a312f84ba3 100644 --- a/packages/tsc/tests/typecheck.spec.ts +++ b/packages/tsc/tests/typecheck.spec.ts @@ -16,8 +16,8 @@ describe(`vue-tsc`, () => { "test-workspace/tsc/failureFixtures/#5071/withScript.vue(1,19): error TS1005: ';' expected.", "test-workspace/tsc/failureFixtures/#5071/withoutScript.vue(2,26): error TS1005: ';' expected.", "test-workspace/tsc/failureFixtures/directives/main.vue(12,2): error TS2578: Unused '@ts-expect-error' directive.", - "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>'.", - "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>'.", + "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, ... 13 more ..., {}>'.", + "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, ... 13 more ..., {}>'.", ] `); }); @@ -37,8 +37,8 @@ describe(`vue-tsc`, () => { "test-workspace/tsc/failureFixtures/#5071/withScript.vue(1,19): error TS1005: ';' expected.", "test-workspace/tsc/failureFixtures/#5071/withoutScript.vue(2,26): error TS1005: ';' expected.", "test-workspace/tsc/failureFixtures/directives/main.vue(12,2): error TS2578: Unused '@ts-expect-error' directive.", - "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>'.", - "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, ComponentOptionsMixin, ComponentOptionsMixin, ... 18 more ..., {}>'.", + "test-workspace/tsc/failureFixtures/directives/main.vue(4,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, ... 13 more ..., {}>'.", + "test-workspace/tsc/failureFixtures/directives/main.vue(9,6): error TS2339: Property 'notExist' does not exist on type 'CreateComponentPublicInstanceWithMixins, { exist: typeof exist; }, {}, {}, {}, {}, {}, {}, PublicProps, {}, true, {}, {}, GlobalComponents, ... 13 more ..., {}>'.", ] `); }); diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index aac8d4ab16..f164f4d77b 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -11,7 +11,6 @@ import { getElementAttrs } from './lib/requests/getElementAttrs'; import { getElementNames } from './lib/requests/getElementNames'; import { getImportPathForFile } from './lib/requests/getImportPathForFile'; import { getPropertiesAtLocation } from './lib/requests/getPropertiesAtLocation'; -import { getQuickInfoAtPosition } from './lib/requests/getQuickInfoAtPosition'; import type { RequestContext } from './lib/requests/types'; const windowsPathReg = /\\/g; @@ -92,11 +91,6 @@ export = createLanguageServicePlugin( response: getPropertiesAtLocation.apply(getRequestContext(args[0]), args), }; }); - session.addProtocolHandler('vue:getQuickInfoAtPosition', ({ arguments: args }) => { - return { - response: getQuickInfoAtPosition.apply(getRequestContext(args[0]), args), - }; - }); session.addProtocolHandler('vue:getComponentNames', ({ arguments: args }) => { return { response: getComponentNames.apply(getRequestContext(args[0]), args) ?? [], diff --git a/packages/typescript-plugin/lib/requests/getQuickInfoAtPosition.ts b/packages/typescript-plugin/lib/requests/getQuickInfoAtPosition.ts deleted file mode 100644 index 0b28c5f339..0000000000 --- a/packages/typescript-plugin/lib/requests/getQuickInfoAtPosition.ts +++ /dev/null @@ -1,10 +0,0 @@ -import type { RequestContext } from './types'; - -export function getQuickInfoAtPosition( - this: RequestContext, - fileName: string, - position: number -) { - const { typescript: ts, languageService } = this; - return ts.displayPartsToString(languageService.getQuickInfoAtPosition(fileName, position)?.displayParts ?? []); -} diff --git a/packages/typescript-plugin/lib/requests/index.ts b/packages/typescript-plugin/lib/requests/index.ts index 9b8fa5bd8e..78cabc6a5f 100644 --- a/packages/typescript-plugin/lib/requests/index.ts +++ b/packages/typescript-plugin/lib/requests/index.ts @@ -4,11 +4,11 @@ export type Requests = { collectExtractProps: ToRequest; getImportPathForFile: ToRequest; getPropertiesAtLocation: ToRequest; - getQuickInfoAtPosition: ToRequest; getComponentNames: ToRequest; getComponentProps: ToRequest; getComponentEvents: ToRequest; getComponentDirectives: ToRequest; getElementAttrs: ToRequest; getElementNames: ToRequest; + getQuickInfoAtPosition: ToRequest<(fileName: string, position: { line: number; character: number; }) => string>; }; diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json index b884e93b76..6b2f2ccf6d 100644 --- a/packages/typescript-plugin/package.json +++ b/packages/typescript-plugin/package.json @@ -1,6 +1,6 @@ { "name": "@vue/typescript-plugin", - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "license": "MIT", "files": [ "**/*.js", @@ -14,7 +14,7 @@ }, "dependencies": { "@volar/typescript": "~2.4.11", - "@vue/language-core": "3.0.0-alpha.0", + "@vue/language-core": "3.0.0-alpha.2", "@vue/shared": "^3.5.0" }, "devDependencies": { diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 2f19fe3176..efad299057 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -48,13 +48,13 @@ importers: specifier: ^3.2.1 version: 3.2.1 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../../packages/language-core '@vue/language-server': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../../packages/language-server '@vue/typescript-plugin': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../../packages/typescript-plugin esbuild: specifier: ^0.25.0 @@ -81,7 +81,7 @@ importers: specifier: ~2.4.11 version: 2.4.11 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core path-browserify: specifier: ^1.0.1 @@ -90,7 +90,7 @@ importers: specifier: '*' version: 5.7.2 vue-component-type-helpers: - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../component-type-helpers devDependencies: '@types/node': @@ -164,14 +164,11 @@ importers: specifier: ^3.5.0 version: 3.5.13 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core packages/language-server: dependencies: - '@typescript/server-harness': - specifier: latest - version: 0.3.5 '@volar/language-core': specifier: ~2.4.11 version: 2.4.11 @@ -182,13 +179,13 @@ importers: specifier: ~2.4.11 version: 2.4.11 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core '@vue/language-service': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-service '@vue/typescript-plugin': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../typescript-plugin vscode-languageserver-protocol: specifier: ^3.17.5 @@ -196,6 +193,10 @@ importers: vscode-uri: specifier: ^3.0.8 version: 3.0.8 + devDependencies: + '@typescript/server-harness': + specifier: latest + version: 0.3.5 packages/language-service: dependencies: @@ -212,13 +213,13 @@ importers: specifier: ^3.5.0 version: 3.5.13 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core '@vue/shared': specifier: ^3.5.0 version: 3.5.13 '@vue/typescript-plugin': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../typescript-plugin alien-signals: specifier: ^1.0.3 @@ -282,7 +283,7 @@ importers: specifier: ~2.4.11 version: 2.4.11 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core typescript: specifier: '>=5.0.0' @@ -298,7 +299,7 @@ importers: specifier: ~2.4.11 version: 2.4.11 '@vue/language-core': - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../language-core '@vue/shared': specifier: ^3.5.0 @@ -317,10 +318,10 @@ importers: specifier: npm:typescript@~5.6.0 version: typescript@5.6.3 vue: - specifier: ^3.5.0 - version: 3.5.13(typescript@5.7.2) + specifier: https://pkg.pr.new/vue@12935 + version: https://pkg.pr.new/vue@12935(typescript@5.7.2) vue-component-type-helpers: - specifier: 3.0.0-alpha.0 + specifier: 3.0.0-alpha.2 version: link:../packages/component-type-helpers vue2: specifier: npm:vue@2.7.16 @@ -1336,12 +1337,20 @@ packages: '@vue/compiler-core@3.5.13': resolution: {integrity: sha512-oOdAkwqUfW1WqpwSYJce06wvt6HljgY3fGeM9NcVA1HaYOij3mZG9Rkysn0OHuyUAGMbEbARIpsG+LPVlBJ5/Q==} + '@vue/compiler-core@https://pkg.pr.new/vuejs/core/@vue/compiler-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/compiler-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 + '@vue/compiler-dom@3.4.38': resolution: {integrity: sha512-Osc/c7ABsHXTsETLgykcOwIxFktHfGSUDkb05V61rocEfsFDcjDLH/IHJSNJP+/Sv9KeN2Lx1V6McZzlSb9EhQ==} '@vue/compiler-dom@3.5.13': resolution: {integrity: sha512-ZOJ46sMOKUjO3e94wPdCzQ6P1Lx/vhp2RSvfaab88Ajexs0AHeV0uasYhi99WPaogmBlRHNRuly8xV75cNTMDA==} + '@vue/compiler-dom@https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 + '@vue/compiler-sfc@2.7.16': resolution: {integrity: sha512-KWhJ9k5nXuNtygPU7+t1rX6baZeqOYLEforUPjgNDBnLicfHCoi48H87Q8XyLZOrNNsmhuwKqtpDQWjEFe6Ekg==} @@ -1351,40 +1360,53 @@ packages: '@vue/compiler-sfc@3.5.13': resolution: {integrity: sha512-6VdaljMpD82w6c2749Zhf5T9u5uLBWKnVue6XWxprDobftnletJ8+oel7sexFfM3qIxNmVE7LSFGTpv6obNyaQ==} + '@vue/compiler-sfc@https://pkg.pr.new/vuejs/core/@vue/compiler-sfc@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/compiler-sfc@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 + '@vue/compiler-ssr@3.4.38': resolution: {integrity: sha512-YXznKFQ8dxYpAz9zLuVvfcXhc31FSPFDcqr0kyujbOwNhlmaNvL2QfIy+RZeJgSn5Fk54CWoEUeW+NVBAogGaw==} '@vue/compiler-ssr@3.5.13': resolution: {integrity: sha512-wMH6vrYHxQl/IybKJagqbquvxpWCuVYpoUJfCqFZwa/JY1GdATAQ+TgVtgrwwMZ0D07QhA99rs/EAAWfvG6KpA==} + '@vue/compiler-ssr@https://pkg.pr.new/vuejs/core/@vue/compiler-ssr@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/compiler-ssr@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 + '@vue/compiler-vue2@2.7.16': resolution: {integrity: sha512-qYC3Psj9S/mfu9uVi5WvNZIzq+xnXMhOwbTFKKDD7b1lhpnn71jXSFdTQ+WsIEk0ONCd7VV2IMm7ONl6tbQ86A==} '@vue/reactivity@3.4.38': resolution: {integrity: sha512-4vl4wMMVniLsSYYeldAKzbk72+D3hUnkw9z8lDeJacTxAkXeDAP1uE9xr2+aKIN0ipOL8EG2GPouVTH6yF7Gnw==} - '@vue/reactivity@3.5.13': - resolution: {integrity: sha512-NaCwtw8o48B9I6L1zl2p41OHo/2Z4wqYGGIK1Khu5T7yxrn+ATOixn/Udn2m+6kZKB/J7cuT9DbWWhRxqixACg==} + '@vue/reactivity@https://pkg.pr.new/vuejs/core/@vue/reactivity@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/reactivity@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 '@vue/runtime-core@3.4.38': resolution: {integrity: sha512-21z3wA99EABtuf+O3IhdxP0iHgkBs1vuoCAsCKLVJPEjpVqvblwBnTj42vzHRlWDCyxu9ptDm7sI2ZMcWrQqlA==} - '@vue/runtime-core@3.5.13': - resolution: {integrity: sha512-Fj4YRQ3Az0WTZw1sFe+QDb0aXCerigEpw418pw1HBUKFtnQHWzwojaukAs2X/c9DQz4MQ4bsXTGlcpGxU/RCIw==} + '@vue/runtime-core@https://pkg.pr.new/vuejs/core/@vue/runtime-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/runtime-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 '@vue/runtime-dom@3.4.38': resolution: {integrity: sha512-afZzmUreU7vKwKsV17H1NDThEEmdYI+GCAK/KY1U957Ig2NATPVjCROv61R19fjZNzMmiU03n79OMnXyJVN0UA==} - '@vue/runtime-dom@3.5.13': - resolution: {integrity: sha512-dLaj94s93NYLqjLiyFzVs9X6dWhTdAlEAciC3Moq7gzAc13VJUdCnjjRurNM6uTLFATRHexHCTu/Xp3eW6yoog==} + '@vue/runtime-dom@https://pkg.pr.new/vuejs/core/@vue/runtime-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/runtime-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 '@vue/server-renderer@3.4.38': resolution: {integrity: sha512-NggOTr82FbPEkkUvBm4fTGcwUY8UuTsnWC/L2YZBmvaQ4C4Jl/Ao4HHTB+l7WnFCt5M/dN3l0XLuyjzswGYVCA==} + version: 3.4.38 peerDependencies: vue: 3.4.38 - '@vue/server-renderer@3.5.13': - resolution: {integrity: sha512-wAi4IRJV/2SAW3htkTlB+dHeRmpTiVIK1OGLWV1yeStVSebSQQOwGwIq0D3ZIoBj2C2qpgz5+vX9iEBkTdk5YA==} + '@vue/server-renderer@https://pkg.pr.new/vuejs/core/@vue/server-renderer@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/server-renderer@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 peerDependencies: vue: 3.5.13 @@ -1394,6 +1416,10 @@ packages: '@vue/shared@3.5.13': resolution: {integrity: sha512-/hnE/qP5ZoGpol0a5mDi45bOd7t3tjYJBjsgCsivow7D48cJeV5l05RD82lPqi7gRiphZM37rnhW1l6ZoCNNnQ==} + '@vue/shared@https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + resolution: {tarball: https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72} + version: 3.5.13 + JSONStream@1.3.5: resolution: {integrity: sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==} hasBin: true @@ -3622,8 +3648,9 @@ packages: typescript: optional: true - vue@3.5.13: - resolution: {integrity: sha512-wmeiSMxkZCSc+PM2w2VRsOYAZC8GdipNFRTsLSfodVqI9mbejKeXEGr8SckuLnrQPGe3oJN5c3K0vpoU9q/wCQ==} + vue@https://pkg.pr.new/vue@12935: + resolution: {tarball: https://pkg.pr.new/vue@12935} + version: 3.5.13 peerDependencies: typescript: '*' peerDependenciesMeta: @@ -4941,6 +4968,14 @@ snapshots: estree-walker: 2.0.2 source-map-js: 1.2.1 + '@vue/compiler-core@https://pkg.pr.new/vuejs/core/@vue/compiler-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + dependencies: + '@babel/parser': 7.26.3 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.1 + '@vue/compiler-dom@3.4.38': dependencies: '@vue/compiler-core': 3.4.38 @@ -4951,6 +4986,11 @@ snapshots: '@vue/compiler-core': 3.5.13 '@vue/shared': 3.5.13 + '@vue/compiler-dom@https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + dependencies: + '@vue/compiler-core': https://pkg.pr.new/vuejs/core/@vue/compiler-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/compiler-sfc@2.7.16': dependencies: '@babel/parser': 7.26.3 @@ -4983,6 +5023,18 @@ snapshots: postcss: 8.4.49 source-map-js: 1.2.1 + '@vue/compiler-sfc@https://pkg.pr.new/vuejs/core/@vue/compiler-sfc@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + dependencies: + '@babel/parser': 7.26.3 + '@vue/compiler-core': https://pkg.pr.new/vuejs/core/@vue/compiler-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/compiler-dom': https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/compiler-ssr': https://pkg.pr.new/vuejs/core/@vue/compiler-ssr@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + estree-walker: 2.0.2 + magic-string: 0.30.17 + postcss: 8.5.2 + source-map-js: 1.2.1 + '@vue/compiler-ssr@3.4.38': dependencies: '@vue/compiler-dom': 3.4.38 @@ -4993,6 +5045,11 @@ snapshots: '@vue/compiler-dom': 3.5.13 '@vue/shared': 3.5.13 + '@vue/compiler-ssr@https://pkg.pr.new/vuejs/core/@vue/compiler-ssr@e1bc0eb02e22bc0c236e1471c11d96a368764b72': + dependencies: + '@vue/compiler-dom': https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/compiler-vue2@2.7.16': dependencies: de-indent: 1.0.2 @@ -5002,19 +5059,19 @@ snapshots: dependencies: '@vue/shared': 3.4.38 - '@vue/reactivity@3.5.13': + '@vue/reactivity@https://pkg.pr.new/vuejs/core/@vue/reactivity@e1bc0eb02e22bc0c236e1471c11d96a368764b72': dependencies: - '@vue/shared': 3.5.13 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 '@vue/runtime-core@3.4.38': dependencies: '@vue/reactivity': 3.4.38 '@vue/shared': 3.4.38 - '@vue/runtime-core@3.5.13': + '@vue/runtime-core@https://pkg.pr.new/vuejs/core/@vue/runtime-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/reactivity': https://pkg.pr.new/vuejs/core/@vue/reactivity@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 '@vue/runtime-dom@3.4.38': dependencies: @@ -5023,29 +5080,31 @@ snapshots: '@vue/shared': 3.4.38 csstype: 3.1.3 - '@vue/runtime-dom@3.5.13': + '@vue/runtime-dom@https://pkg.pr.new/vuejs/core/@vue/runtime-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72': dependencies: - '@vue/reactivity': 3.5.13 - '@vue/runtime-core': 3.5.13 - '@vue/shared': 3.5.13 + '@vue/reactivity': https://pkg.pr.new/vuejs/core/@vue/reactivity@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/runtime-core': https://pkg.pr.new/vuejs/core/@vue/runtime-core@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 csstype: 3.1.3 - '@vue/server-renderer@3.4.38(vue@3.5.13(typescript@5.7.2))': + '@vue/server-renderer@3.4.38(vue@https://pkg.pr.new/vue@12935(typescript@5.7.2))': dependencies: '@vue/compiler-ssr': 3.4.38 '@vue/shared': 3.4.38 - vue: 3.5.13(typescript@5.7.2) + vue: https://pkg.pr.new/vue@12935(typescript@5.7.2) - '@vue/server-renderer@3.5.13(vue@3.5.13(typescript@5.7.2))': + '@vue/server-renderer@https://pkg.pr.new/vuejs/core/@vue/server-renderer@e1bc0eb02e22bc0c236e1471c11d96a368764b72(vue@https://pkg.pr.new/vue@12935(typescript@5.7.2))': dependencies: - '@vue/compiler-ssr': 3.5.13 - '@vue/shared': 3.5.13 - vue: 3.5.13(typescript@5.7.2) + '@vue/compiler-ssr': https://pkg.pr.new/vuejs/core/@vue/compiler-ssr@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + vue: https://pkg.pr.new/vue@12935(typescript@5.7.2) '@vue/shared@3.4.38': {} '@vue/shared@3.5.13': {} + '@vue/shared@https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72': {} + JSONStream@1.3.5: dependencies: jsonparse: 1.3.1 @@ -7359,18 +7418,18 @@ snapshots: '@vue/compiler-dom': 3.4.38 '@vue/compiler-sfc': 3.4.38 '@vue/runtime-dom': 3.4.38 - '@vue/server-renderer': 3.4.38(vue@3.5.13(typescript@5.7.2)) + '@vue/server-renderer': 3.4.38(vue@https://pkg.pr.new/vue@12935(typescript@5.7.2)) '@vue/shared': 3.4.38 optionalDependencies: typescript: 5.7.2 - vue@3.5.13(typescript@5.7.2): + vue@https://pkg.pr.new/vue@12935(typescript@5.7.2): dependencies: - '@vue/compiler-dom': 3.5.13 - '@vue/compiler-sfc': 3.5.13 - '@vue/runtime-dom': 3.5.13 - '@vue/server-renderer': 3.5.13(vue@3.5.13(typescript@5.7.2)) - '@vue/shared': 3.5.13 + '@vue/compiler-dom': https://pkg.pr.new/vuejs/core/@vue/compiler-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/compiler-sfc': https://pkg.pr.new/vuejs/core/@vue/compiler-sfc@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/runtime-dom': https://pkg.pr.new/vuejs/core/@vue/runtime-dom@e1bc0eb02e22bc0c236e1471c11d96a368764b72 + '@vue/server-renderer': https://pkg.pr.new/vuejs/core/@vue/server-renderer@e1bc0eb02e22bc0c236e1471c11d96a368764b72(vue@https://pkg.pr.new/vue@12935(typescript@5.7.2)) + '@vue/shared': https://pkg.pr.new/vuejs/core/@vue/shared@e1bc0eb02e22bc0c236e1471c11d96a368764b72 optionalDependencies: typescript: 5.7.2 diff --git a/test-workspace/package.json b/test-workspace/package.json index 50ee98bfc3..a2b8c5eca4 100644 --- a/test-workspace/package.json +++ b/test-workspace/package.json @@ -1,11 +1,11 @@ { "private": true, - "version": "3.0.0-alpha.0", + "version": "3.0.0-alpha.2", "devDependencies": { "typescript-next": "npm:typescript@5.7.0-dev.20240926", "typescript-stable": "npm:typescript@~5.6.0", - "vue": "^3.5.0", - "vue-component-type-helpers": "3.0.0-alpha.0", + "vue": "https://pkg.pr.new/vue@12935", + "vue-component-type-helpers": "3.0.0-alpha.2", "vue2": "npm:vue@2.7.16", "vue3.4": "npm:vue@3.4.38" } diff --git a/test-workspace/tsc/passedFixtures/vue3/#4433/main.vue b/test-workspace/tsc/passedFixtures/vue3/#4433/main.vue new file mode 100644 index 0000000000..4fc0836139 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/#4433/main.vue @@ -0,0 +1,12 @@ + + + diff --git a/test-workspace/tsc/passedFixtures/vue3/#5262/comp.vue b/test-workspace/tsc/passedFixtures/vue3/#5262/comp.vue new file mode 100644 index 0000000000..379bf4e2c0 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/#5262/comp.vue @@ -0,0 +1,5 @@ + diff --git a/test-workspace/tsc/passedFixtures/vue3/#5262/main.vue b/test-workspace/tsc/passedFixtures/vue3/#5262/main.vue new file mode 100644 index 0000000000..f768a90378 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/#5262/main.vue @@ -0,0 +1,8 @@ + + + diff --git a/test-workspace/tsc/passedFixtures/vue3/#5267/main.vue b/test-workspace/tsc/passedFixtures/vue3/#5267/main.vue new file mode 100644 index 0000000000..311e7a2f29 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/#5267/main.vue @@ -0,0 +1,13 @@ + + + diff --git a/test-workspace/tsc/passedFixtures/vue3/components/main.vue b/test-workspace/tsc/passedFixtures/vue3/components/main.vue index 7813b763f4..dd53d4f7cf 100644 --- a/test-workspace/tsc/passedFixtures/vue3/components/main.vue +++ b/test-workspace/tsc/passedFixtures/vue3/components/main.vue @@ -51,13 +51,9 @@ const ScriptSetupDefaultPropsExact = defineComponent({ msg?: string; labels?: string[]; }, - props: { - msg: { - default: 'hello' - }, - labels: { - default: () => ['one', 'two'] - } + __defaults: { + msg: 'hello', + labels: () => ['one', 'two'] }, setup() { return {}; diff --git a/test-workspace/tsc/passedFixtures/vue3/components/script-setup-expose.vue b/test-workspace/tsc/passedFixtures/vue3/components/script-setup-expose.vue index 0186f94f29..e7f9c519a9 100644 --- a/test-workspace/tsc/passedFixtures/vue3/components/script-setup-expose.vue +++ b/test-workspace/tsc/passedFixtures/vue3/components/script-setup-expose.vue @@ -1,5 +1,5 @@ - @@ -41,4 +46,8 @@ useTemplateRef('unknown'); {{ exactType(comp4?.[0]?.href, {} as string | undefined) }} + + +
+ {{ exactType(comp5, {} as HTMLAnchorElement | HTMLDivElement | null) }} diff --git a/test-workspace/tsconfig.base.json b/test-workspace/tsconfig.base.json index e9bf65f158..7cbc5df598 100644 --- a/test-workspace/tsconfig.base.json +++ b/test-workspace/tsconfig.base.json @@ -15,5 +15,8 @@ "jsx": "preserve", "baseUrl": ".", }, + "vueCompilerOptions": { + "target": 99, + }, "include": [ ], } \ No newline at end of file