From c7f06189acc45ca31beba443f752ad810d9eee15 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Thu, 20 Apr 2023 22:07:47 +0300 Subject: [PATCH 1/4] fix(method-snippets): fix expanding method snippets in some edge-cases --- typescript/src/completions/functionCompletions.ts | 3 ++- typescript/src/constructMethodSnippet.ts | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/typescript/src/completions/functionCompletions.ts b/typescript/src/completions/functionCompletions.ts index 0d884391..7a5e13a6 100644 --- a/typescript/src/completions/functionCompletions.ts +++ b/typescript/src/completions/functionCompletions.ts @@ -7,7 +7,8 @@ export default (entries: ts.CompletionEntry[]) => { const { languageService, c, sourceFile, position } = sharedCompletionContext const methodSnippetInsertTextMode = c('methodSnippetsInsertText') - const enableResolvingInsertText = c('enableMethodSnippets') && methodSnippetInsertTextMode !== 'disable' + const nextChar = sourceFile.getFullText().slice(position, position + 1) + const enableResolvingInsertText = !['(', '.', '`'].includes(nextChar) && c('enableMethodSnippets') && methodSnippetInsertTextMode !== 'disable' const changeKindToFunction = c('experiments.changeKindToFunction') if (!enableResolvingInsertText && !changeKindToFunction) return diff --git a/typescript/src/constructMethodSnippet.ts b/typescript/src/constructMethodSnippet.ts index 7759cb9c..47150bee 100644 --- a/typescript/src/constructMethodSnippet.ts +++ b/typescript/src/constructMethodSnippet.ts @@ -19,7 +19,9 @@ export default ( if (!containerNode || isTypeNode(containerNode)) return const checker = languageService.getProgram()!.getTypeChecker()! - const type = symbol ? checker.getTypeOfSymbol(symbol) : checker.getTypeAtLocation(containerNode) + let type = symbol ? checker.getTypeOfSymbol(symbol) : checker.getTypeAtLocation(containerNode) + // give another chance + if (symbol && type['intrinsicName'] === 'error') type = checker.getTypeOfSymbolAtLocation(symbol, containerNode) if (ts.isIdentifier(containerNode)) containerNode = containerNode.parent if (ts.isPropertyAccessExpression(containerNode)) containerNode = containerNode.parent From 2a39444fb26887b9692fdf714d9701bed61d5fbf Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Sun, 30 Apr 2023 23:35:39 +0300 Subject: [PATCH 2/4] fix: fix method snippets for classes with implicit constructor and functions within constructor arguments e.g. `new A(foo())` --- typescript/src/constructMethodSnippet.ts | 6 ++++-- typescript/test/completions.spec.ts | 8 ++++++++ 2 files changed, 12 insertions(+), 2 deletions(-) diff --git a/typescript/src/constructMethodSnippet.ts b/typescript/src/constructMethodSnippet.ts index 47150bee..8b2b781c 100644 --- a/typescript/src/constructMethodSnippet.ts +++ b/typescript/src/constructMethodSnippet.ts @@ -26,7 +26,9 @@ export default ( if (ts.isIdentifier(containerNode)) containerNode = containerNode.parent if (ts.isPropertyAccessExpression(containerNode)) containerNode = containerNode.parent - const isNewExpression = ts.isNewExpression(containerNode) + const isNewExpression = + ts.isNewExpression(containerNode) && + ts.textSpanIntersectsWithPosition(ts.createTextSpanFromBounds(containerNode.expression.pos, containerNode.expression.end), position) if (!isNewExpression && (type.getProperties().length > 0 || type.getStringIndexType() || type.getNumberIndexType())) { resolveData.isAmbiguous = true } @@ -36,7 +38,7 @@ export default ( if (signatures.length === 0) return const signature = signatures[0]! // probably need to remove check as class can be instantiated inside another class, and don't really see a reason for this check - if (isNewExpression && hasPrivateOrProtectedModifier((signature.getDeclaration() as ts.ConstructorDeclaration).modifiers)) return + if (isNewExpression && hasPrivateOrProtectedModifier((signature.getDeclaration() as ts.ConstructorDeclaration | undefined)?.modifiers)) return if (signatures.length > 1 && c('methodSnippets.multipleSignatures') === 'empty') { return [''] } diff --git a/typescript/test/completions.spec.ts b/typescript/test/completions.spec.ts index 9f2b1302..5dc48a4a 100644 --- a/typescript/test/completions.spec.ts +++ b/typescript/test/completions.spec.ts @@ -137,6 +137,9 @@ describe('Method snippets', () => { function foo(this: {}) {} foo/*3*/ + // new class + new Something(foo/*301*/) + // contextual type declare const bar: { b: (a) => {} @@ -173,6 +176,7 @@ describe('Method snippets', () => { compareMethodSnippetAgainstMarker(markers, 1, null) compareMethodSnippetAgainstMarker(markers, 2, '()') compareMethodSnippetAgainstMarker(markers, 3, '(a)') + compareMethodSnippetAgainstMarker(markers, 301, '(a)') compareMethodSnippetAgainstMarker(markers, 4, '($b)') compareMethodSnippetAgainstMarker(markers, 5, '(a, b, { d, e: {} }, ...c)') compareMethodSnippetAgainstMarker(markers, 6, '(a, b, c)') @@ -188,13 +192,17 @@ describe('Method snippets', () => { protected constructor(a) {} } + class C {} + new A/*1*/ // not sure... new B/*2*/ + new C/*3*/ `) compareMethodSnippetAgainstMarker(markers, 1, ['a']) compareMethodSnippetAgainstMarker(markers, 2, null) + compareMethodSnippetAgainstMarker(markers, 3, []) }) test('Skip trailing void', () => { From 30384a0f42408811a5d31450cadd1265d9d3b1a2 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 3 May 2023 12:11:52 +0300 Subject: [PATCH 3/4] fix: update support for new volar --- package.json | 2 +- pnpm-lock.yaml | 39 ++++++++++++++++++++++++++++++++--- src/vueVolarSupport.ts | 15 ++++++-------- typescript/src/volarConfig.ts | 24 +++++++++++---------- 4 files changed, 56 insertions(+), 24 deletions(-) diff --git a/package.json b/package.json index 2fb94337..4502b198 100644 --- a/package.json +++ b/package.json @@ -146,7 +146,7 @@ "@types/mocha": "^9.1.1", "@types/pluralize": "^0.0.29", "@volar/language-server": "1.3.0-alpha.3", - "@volar/language-service": "1.3.0-alpha.3", + "@volar/language-service": "1.5.0", "@volar/vue-language-core": "^1.2.0-patch.2", "@vscode/emmet-helper": "^2.8.4", "@vscode/test-electron": "^2.1.5", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5c13694c..7a743f32 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -26,8 +26,8 @@ importers: specifier: 1.3.0-alpha.3 version: 1.3.0-alpha.3 '@volar/language-service': - specifier: 1.3.0-alpha.3 - version: 1.3.0-alpha.3 + specifier: 1.5.0 + version: 1.5.0 '@volar/vue-language-core': specifier: ^1.2.0-patch.2 version: 1.2.0-patch.2 @@ -927,6 +927,12 @@ packages: '@volar/source-map': 1.3.0-alpha.3 dev: false + /@volar/language-core@1.5.0: + resolution: {integrity: sha512-CZJjglaZRT4pgO8T6YRo7QGgQ7sxSkzcH9mV/4M/x751NffGoVVHz/Z1ht412XEYj4t/xrsB/z3fff0vYwjBTA==} + dependencies: + '@volar/source-map': 1.5.0 + dev: false + /@volar/language-server@1.3.0-alpha.3: resolution: {integrity: sha512-qFBb/nvZFD8DOLtBbTxk3y11+jtM+3zRYH3AxiKXlBlZESCGUgO8lQXeDZYd0zszRPQ3dBmtN+oBjxQfYpvlRw==} dependencies: @@ -957,6 +963,19 @@ packages: vscode-uri: 3.0.7 dev: false + /@volar/language-service@1.5.0: + resolution: {integrity: sha512-9HRgzTvlObcFutevwouoxVp3LyDWPiGV7d1bBlJj23NqwVJn5FuvAvdBBCdNW2d4XDgh3tRprC3kKtdO4sMsVg==} + dependencies: + '@volar/language-core': 1.5.0 + '@volar/source-map': 1.5.0 + typescript-auto-import-cache: 0.2.1 + vscode-html-languageservice: 5.0.4 + vscode-json-languageservice: 5.3.1 + vscode-languageserver-protocol: 3.17.3 + vscode-languageserver-textdocument: 1.0.8 + vscode-uri: 3.0.7 + dev: false + /@volar/shared@1.3.0-alpha.3: resolution: {integrity: sha512-laNURk/qkRJStxyNy0DVFMr8drqQv5ZXXuOHk/QCGI4/hiNfk94a3vIFtCIbtw/TOETcV6s9nJP7JMwd8xr2lw==} dependencies: @@ -976,6 +995,12 @@ packages: muggle-string: 0.2.2 dev: false + /@volar/source-map@1.5.0: + resolution: {integrity: sha512-Tkp8OEkKony48tawWlRJOyQ0aO0rU+cA0Jnn0mMwxhBIYbYTqrk3tCalw6ayhzGtZYB9dNqieFEq08+WMPK3sw==} + dependencies: + muggle-string: 0.2.2 + dev: false + /@volar/typescript-faster@1.3.0-alpha.3: resolution: {integrity: sha512-0iOUOyfaUJKDqU2Hd3xC1r1M6L4S+Yg8rNOR3AC8/hZ3PeGca3JzdFffOwfAZYbsQZcp+lHDYj9K8emku4zhIg==} dependencies: @@ -1038,7 +1063,7 @@ packages: koa-static: 5.0.0 minimist: 1.2.5 playwright: 1.14.1 - vscode-uri: 3.0.6 + vscode-uri: 3.0.7 transitivePeerDependencies: - bufferutil - supports-color @@ -5118,10 +5143,12 @@ packages: /semver@5.7.1: resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==} + hasBin: true dev: false /semver@6.3.0: resolution: {integrity: sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==} + hasBin: true dev: false /semver@7.3.8: @@ -5722,6 +5749,12 @@ packages: resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} dev: false + /typescript-auto-import-cache@0.2.1: + resolution: {integrity: sha512-FD5uYQSNkVTX4b3lvtifP+SR3bARWGmKe/uyp5BfuW2ZUCYG7vHKPddrteLU06Uh68woRaYIX+Sbs2nnySpGLw==} + dependencies: + semver: 7.3.8 + dev: false + /typescript-json-schema@0.51.0: resolution: {integrity: sha512-POhWbUNs2oaBti1W9k/JwS+uDsaZD9J/KQiZ/iXRQEOD0lTn9VmshIls9tn+A9X6O+smPjeEz5NEy6WTkCCzrQ==} dependencies: diff --git a/src/vueVolarSupport.ts b/src/vueVolarSupport.ts index 96f25230..fb69156a 100644 --- a/src/vueVolarSupport.ts +++ b/src/vueVolarSupport.ts @@ -6,15 +6,12 @@ export default () => { if (process.env.PLATFORM !== 'node') return const handler = () => { const config = vscode.workspace.getConfiguration('') - if ( - !getExtensionSetting('enableVueSupport') || - !vscode.extensions.getExtension('Vue.volar') || - isConfigValueChanged('volar.vueserver.configFilePath') - ) { + const VOLAR_CONFIG_FILE_SETTING = 'vue.server.configFilePath' + if (!getExtensionSetting('enableVueSupport') || !vscode.extensions.getExtension('Vue.volar') || isConfigValueChanged(VOLAR_CONFIG_FILE_SETTING)) { return } - void config.update('volar.vueserver.configFilePath', extensionCtx.asAbsolutePath('./volarConfig.js'), vscode.ConfigurationTarget.Global) + void config.update(VOLAR_CONFIG_FILE_SETTING, extensionCtx.asAbsolutePath('./volarConfig.js'), vscode.ConfigurationTarget.Global) } handler() @@ -22,11 +19,11 @@ export default () => { vscode.extensions.onDidChange(handler) } -const isConfigValueChanged = (id: string) => { +const isConfigValueChanged = (settingId: string) => { if (process.env.PLATFORM !== 'web') { const config = vscode.workspace.getConfiguration('') - const userValue = config.get(id) - if (userValue === config.inspect(id)!.defaultValue) return false + const userValue = config.get(settingId) + if (userValue === config.inspect(settingId)!.defaultValue) return false // means that value was set by us programmatically, let's update it // eslint-disable-next-line @typescript-eslint/no-require-imports if (userValue?.startsWith(require('path').join(extensionCtx.extensionPath, '../..'))) return false diff --git a/typescript/src/volarConfig.ts b/typescript/src/volarConfig.ts index 25a2f116..5070e3a5 100644 --- a/typescript/src/volarConfig.ts +++ b/typescript/src/volarConfig.ts @@ -2,10 +2,11 @@ // will be required from ./node_modules/typescript-essential-plugins/index.js const originalPluginFactory = require('typescript-essential-plugins') -const plugin = (context => { +const plugin = ((context, { typescript: tsModule } = {}) => { + if (!context) throw new Error('Not recieve context') const { typescript } = context - let configurationHost = context.configurationHost! - configurationHost ??= context['env'].configurationHost + let configurationHost = context.env + if (context['configurationHost']!) configurationHost = context['configurationHost']! const patchConfig = config => { return { ...config, @@ -17,13 +18,14 @@ const plugin = (context => { } if (typescript && configurationHost) { + const ts = tsModule ?? typescript['module'] const plugin = originalPluginFactory({ - typescript: typescript.module, + typescript: ts, }) // todo support vue-specific settings const originalLsMethods = { ...typescript.languageService } - void configurationHost.getConfiguration('tsEssentialPlugins').then(_configuration => { + void configurationHost.getConfiguration!('tsEssentialPlugins').then(_configuration => { // if (typescript.languageService[thisPluginMarker]) return const config = patchConfig(_configuration) if (!config.enablePlugin) return @@ -39,8 +41,8 @@ const plugin = (context => { } }) - configurationHost.onDidChangeConfiguration(() => { - void configurationHost.getConfiguration('tsEssentialPlugins').then(config => { + configurationHost.onDidChangeConfiguration!(() => { + void configurationHost.getConfiguration!('tsEssentialPlugins').then(config => { config = patchConfig(config) plugin.onConfigurationChanged?.(config) // temporary workaround @@ -54,17 +56,17 @@ const plugin = (context => { console.warn('Failed to activate tsEssentialPlugins, because of no typescript or configurationHost context') } return {} -}) satisfies import('@volar/language-service').LanguageServicePlugin +}) satisfies import('@volar/language-service').Service module.exports = { plugins: [ - c => { + (...args) => { try { - return plugin(c) + return plugin(...(args as [any])) } catch (err) { console.log('TS Essentials error', err) return {} } }, ], -} +} /* satisfies import('@volar/language-service').ServiceContext */ From 7c8879f78a8aa96aa209b05d48a645a0d5fc82f1 Mon Sep 17 00:00:00 2001 From: Vitaly Turovsky Date: Wed, 3 May 2023 12:25:10 +0300 Subject: [PATCH 4/4] fix test runner --- typescript/test/testing.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/typescript/test/testing.ts b/typescript/test/testing.ts index c0db7325..0aba35dc 100644 --- a/typescript/test/testing.ts +++ b/typescript/test/testing.ts @@ -138,7 +138,7 @@ export const fourslashLikeTester = (contents: string, fileName = entrypoint) => export const fileContentsSpecialPositions = (contents: string, fileName = entrypoint) => { const cursorPositions: [number[], number[], number[]] = [[], [], []] const cursorPositionsOnly: [number[], number[], number[]] = [[], [], []] - const replacement = /\/\*([tf\d]o?)\*\//g + const replacement = /\/\*((t|f|\d+)o?)\*\//g let currentMatch: RegExpExecArray | null | undefined while ((currentMatch = replacement.exec(contents))) { const offset = currentMatch.index