diff --git a/package.json b/package.json index 1c173d02..ee9e536b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,7 @@ { "name": "ts-essential-plugins", "displayName": "TypeScript Essential Plugins", + "description": "50+ features: TS extension for professionals", "version": "0.0.0-dev", "license": "MIT", "web": true, diff --git a/src/autoCompletionsTrigger.ts b/src/autoCompletionsTrigger.ts new file mode 100644 index 00000000..a8e81390 --- /dev/null +++ b/src/autoCompletionsTrigger.ts @@ -0,0 +1,23 @@ +import * as vscode from 'vscode' +import { defaultLanguageSupersets } from '@zardoy/vscode-utils/build/langs' +import { getExtensionSetting } from 'vscode-framework' +import { sendCommand } from './sendCommand' + +const jsxAttributesAutoTrigger = () => { + vscode.workspace.onDidChangeTextDocument(async ({ contentChanges, document, reason }) => { + const editor = vscode.window.activeTextEditor + if (document !== editor?.document || contentChanges.length === 0) return + if (contentChanges[0]!.text !== ' ') return + if (![...defaultLanguageSupersets.react, 'javascript'].includes(document.languageId)) return + if (!getExtensionSetting('completionsAutoTrigger.jsx')) return + const path = await sendCommand('getNodePath', { document, position: editor.selection.active }) + if (!path) return + if (['JsxSelfClosingElement', 'JsxOpeningElement'].includes(path.at(-1)?.kindName ?? '')) { + await vscode.commands.executeCommand('editor.action.triggerSuggest') + } + }) +} + +export default () => { + jsxAttributesAutoTrigger() +} diff --git a/src/configurationType.ts b/src/configurationType.ts index 93ae2d61..3511f83e 100644 --- a/src/configurationType.ts +++ b/src/configurationType.ts @@ -685,6 +685,11 @@ export type Configuration = { */ declareMissingPropertyQuickfixOtherFiles: boolean /** + * @recommended {".svg": { + * "importPath": "$path?react", + * "prefix": "Svg", + * "nameCasing": "pascal" + * }, * @default {} */ filesAutoImport: { @@ -708,6 +713,14 @@ export type Configuration = { iconPost?: string } } + /** + * @default true + */ + 'completionsAutoTrigger.jsx': boolean + /** + * @default false + */ + 'inlayHints.missingJsxAttributes.enabled': boolean } // scrapped using search editor. config: caseInsensitive, context lines: 0, regex: const fix\w+ = "[^ ]+" diff --git a/src/extension.ts b/src/extension.ts index a60488d6..0bacb075 100644 --- a/src/extension.ts +++ b/src/extension.ts @@ -17,6 +17,8 @@ import moreCompletions from './moreCompletions' import { mergeSettingsFromScopes } from './mergeSettings' import codeActionProvider from './codeActionProvider' import nonTsCommands from './nonTsCommands' +import inlayHints from './inlayHints' +import autoCompletionsTrigger from './autoCompletionsTrigger' let isActivated = false // let erroredStatusBarItem: vscode.StatusBarItem | undefined @@ -96,6 +98,8 @@ export const activateTsPlugin = (tsApi: { configurePlugin; onCompletionAccepted figIntegration() vueVolarSupport() + inlayHints() + autoCompletionsTrigger() if (process.env.PLATFORM === 'node' && process.env.NODE_ENV === 'development') { require('./autoPluginReload').default() diff --git a/src/inlayHints.ts b/src/inlayHints.ts new file mode 100644 index 00000000..570a8e9f --- /dev/null +++ b/src/inlayHints.ts @@ -0,0 +1,57 @@ +import * as vscode from 'vscode' +import { watchExtensionSetting } from '@zardoy/vscode-utils/build/settings' +import { getExtensionSetting, registerActiveDevelopmentCommand } from 'vscode-framework' + +// todo respect enabled setting, deactivate +export default () => { + const provider = new (class implements vscode.InlayHintsProvider { + eventEmitter = new vscode.EventEmitter() + onDidChangeInlayHints = this.eventEmitter.event + provideInlayHints(document: vscode.TextDocument, range: vscode.Range, token: vscode.CancellationToken): vscode.ProviderResult { + const diagnostics = vscode.languages.getDiagnostics(document.uri) + const jsxMissingAttributesErrors = diagnostics.filter(({ code, source }) => (code === 2740 || code === 2739) && source === 'ts') + return jsxMissingAttributesErrors + .flatMap(({ range, message }) => { + const regex = /: (?[\w, ]+)(?:, and (?\d+) more)?\.?$/ + const match = regex.exec(message) + if (!match) return null as never + const props = match.groups!.prop!.split(', ') + const { more } = match.groups! + let text = ` ${props.map(prop => `${prop}!`).join(', ')}` + if (more) text += `, and ${more} more` + return { + kind: vscode.InlayHintKind.Type, + label: text, + tooltip: `Inlay hint: Missing attributes`, + position: range.end, + paddingLeft: true, + } satisfies vscode.InlayHint + // return [...props, ...(more ? [more] : [])].map((prop) => ({ + // kind: vscode.InlayHintKind.Type, + // label: prop, + // tooltip: 'Missing attribute', + // position: + // })) + }) + .filter(Boolean) + } + })() + let disposables = [] as vscode.Disposable[] + + const manageEnablement = () => { + if (getExtensionSetting('inlayHints.missingJsxAttributes.enabled')) { + vscode.languages.registerInlayHintsProvider('typescriptreact,javascript,javascriptreact'.split(','), provider) + vscode.languages.onDidChangeDiagnostics(e => { + for (const uri of e.uris) { + if (uri === vscode.window.activeTextEditor?.document.uri) provider.eventEmitter.fire() + } + }) + } else { + for (const d of disposables) d.dispose() + disposables = [] + } + } + + manageEnablement() + watchExtensionSetting('inlayHints.missingJsxAttributes.enabled', manageEnablement) +} diff --git a/typescript/src/codeActions/extended/declareMissingAttributes.ts b/typescript/src/codeActions/extended/declareMissingAttributes.ts new file mode 100644 index 00000000..82ecbb4b --- /dev/null +++ b/typescript/src/codeActions/extended/declareMissingAttributes.ts @@ -0,0 +1,44 @@ +import { ExtendedCodeAction } from '../getCodeActions' + +const errorCodes = [ + // ts.Diagnostics.Property_0_does_not_exist_on_type_1.code, + // ts.Diagnostics.Property_0_does_not_exist_on_type_1_Did_you_mean_2.code, + // ts.Diagnostics.Property_0_is_missing_in_type_1_but_required_in_type_2.code, + // ts.Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2.code, + // ts.Diagnostics.Type_0_is_missing_the_following_properties_from_type_1_Colon_2_and_3_more.code, + // // ts.Diagnostics.Argument_of_type_0_is_not_assignable_to_parameter_of_type_1.code, + // // ts.Diagnostics.Cannot_find_name_0.code, + 2339, 2551, 2741, 2739, 2740 /* 2345, 2304, */, +] + +export default { + codes: errorCodes, + kind: 'quickfix', + title: 'Declare missing attributes', + tryToApply({ sourceFile, node, c, languageService, position, formatOptions, range }) { + // todo maybe cache from prev request? + if (!node) return + const codeFixes = languageService.getCodeFixesAtPosition( + sourceFile.fileName, + node.getStart(), + range?.end ?? node.getStart(), + errorCodes, + formatOptions ?? {}, + {}, + ) + const fix = codeFixes.find(codeFix => codeFix.fixName === 'fixMissingAttributes') + if (fix && fix.changes[0]?.textChanges.length === 1) { + const changes = fix.changes[0]!.textChanges + let i = 1 + return { + snippetEdits: [ + { + newText: changes[0]!.newText.replaceAll('$', '\\$').replaceAll('={undefined}', () => `={$${i++}}`), + span: fix.changes[0]!.textChanges[0]!.span, + }, + ], + } + } + return + }, +} as ExtendedCodeAction diff --git a/typescript/src/codeActions/functionExtractors.ts b/typescript/src/codeActions/functionExtractors.ts index b5c63bed..5d94ae87 100644 --- a/typescript/src/codeActions/functionExtractors.ts +++ b/typescript/src/codeActions/functionExtractors.ts @@ -100,14 +100,17 @@ export const handleFunctionRefactorEdits = ( const oldFunctionText = functionChange.newText const sourceFile = languageService.getProgram()!.getSourceFile(fileName)! if (actionName.endsWith('_jsx')) { + // refactor.extract.jsx implementation const lines = oldFunctionText.trimStart().split('\n') const oldFunctionSignature = lines[0]! const componentName = tsFull.getUniqueName('ExtractedComponent', sourceFile as unknown as FullSourceFile) - const newFunctionSignature = changeArgumentsToDestructured(oldFunctionSignature, formatOptions, sourceFile, componentName) - const insertChange = textChanges.at(-2)! - let args = insertChange.newText.slice(1, -2) - args = args.slice(args.indexOf('(') + 1) + const args = insertChange.newText.slice(insertChange.newText.indexOf('(') + 1, insertChange.newText.lastIndexOf(')')) + + const newFunctionSignature = changeArgumentsToDestructured(oldFunctionSignature, formatOptions, sourceFile, componentName).replace('{}: {}', '') + + const oldSpan = sourceFile.text.slice(0, functionChange.span.start).length + const fileEdits = [ { fileName, @@ -130,11 +133,17 @@ export const handleFunctionRefactorEdits = ( ], }, ] + const diff = fileEdits[0]!.textChanges.slice(0, -1).reduce((diff, { newText, span }) => { + const oldText = sourceFile.text.slice(span.start, span.start + span.length) + const newSpan = newText.length + const oldSpan = oldText.length + diff += newSpan - oldSpan + return diff + }, 0) return { edits: fileEdits, renameFilename, - renameLocation: insertChange.span.start + 1, - // renameLocation: tsFull.getRenameLocation(fileEdits, fileName, componentName, /*preferLastLocation*/ false), + renameLocation: functionChange.span.start + diff, } } diff --git a/typescript/src/codeActions/getCodeActions.ts b/typescript/src/codeActions/getCodeActions.ts index e69509f1..468f8a26 100644 --- a/typescript/src/codeActions/getCodeActions.ts +++ b/typescript/src/codeActions/getCodeActions.ts @@ -11,6 +11,7 @@ import { renameParameterToNameFromType, renameAllParametersToNameFromType } from import addDestructure_1 from './custom/addDestructure/addDestructure' import fromDestructure_1 from './custom/fromDestructure/fromDestructure' import fixClosingTagName from './custom/fixClosingTagName' +import declareMissingAttributes from './extended/declareMissingAttributes' const codeActions: CodeAction[] = [ addDestructure_1, @@ -22,7 +23,7 @@ const codeActions: CodeAction[] = [ renameAllParametersToNameFromType, fixClosingTagName, ] -const extendedCodeActions: ExtendedCodeAction[] = [declareMissingProperties] +const extendedCodeActions: ExtendedCodeAction[] = [declareMissingProperties, declareMissingAttributes] type SimplifiedRefactorInfo = | { diff --git a/typescript/src/codeFixes.ts b/typescript/src/codeFixes.ts index eff070c4..e89e7d94 100644 --- a/typescript/src/codeFixes.ts +++ b/typescript/src/codeFixes.ts @@ -5,7 +5,7 @@ import { findChildContainingPosition, getCancellationToken, getIndentFromPos, is import namespaceAutoImports from './namespaceAutoImports' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, languageServiceHost: ts.LanguageServiceHost, c: GetConfig) => { - proxy.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences) => { + proxy.getCodeFixesAtPosition = (fileName, start, end, errorCodes, formatOptions, preferences, ...args) => { const sourceFile = languageService.getProgram()!.getSourceFile(fileName)! const node = findChildContainingPosition(ts, sourceFile, start) @@ -72,7 +72,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, }, ) toUnpatch.push(unpatch) - prior = languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences) + prior = languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences, ...args) prior = [...addNamespaceImports, ...prior] prior = _.sortBy(prior, ({ fixName }) => { if (fixName.startsWith(importFixName)) { @@ -82,7 +82,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, }) prior = prior.filter(x => x.fixName !== 'IGNORE') } catch (err) { - prior = languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences) + prior = languageService.getCodeFixesAtPosition(fileName, start, end, errorCodes, formatOptions, preferences, ...args) setTimeout(() => { // make sure we still get code fixes, but error is still getting reported console.error(err) @@ -103,14 +103,14 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, // #endregion const semanticDiagnostics = languageService.getSemanticDiagnostics(fileName) - const syntacicDiagnostics = languageService.getSyntacticDiagnostics(fileName) + const syntacticDiagnostics = languageService.getSyntacticDiagnostics(fileName) // https://github.com/Microsoft/TypeScript/blob/v4.5.5/src/compiler/diagnosticMessages.json#L458 const findDiagnosticByCode = (codes: number[]) => { const errorCode = codes.find(code => errorCodes.includes(code)) if (!errorCode) return const diagnosticPredicate = ({ code, start: localStart }) => code === errorCode && localStart === start - return syntacicDiagnostics.find(diagnosticPredicate) || semanticDiagnostics.find(diagnosticPredicate) + return syntacticDiagnostics.find(diagnosticPredicate) || semanticDiagnostics.find(diagnosticPredicate) } const wrapBlockDiagnostics = findDiagnosticByCode([1156, 1157]) diff --git a/typescript/src/completionEntryDetails.ts b/typescript/src/completionEntryDetails.ts index 10f6c5b5..7126f8a3 100644 --- a/typescript/src/completionEntryDetails.ts +++ b/typescript/src/completionEntryDetails.ts @@ -16,7 +16,7 @@ export default function completionEntryDetails( c: GetConfig, { enableMethodCompletion, completionsSymbolMap }: PrevCompletionsAdditionalData, ): ts.CompletionEntryDetails | undefined { - const [fileName, position, entryName, formatOptions, source, preferences, data] = inputArgs + const [fileName, position, entryName, formatOptions, source, preferences, data, ...args] = inputArgs lastResolvedCompletion.value = { name: entryName, range: prevCompletionsMap[entryName]?.range } const program = languageService.getProgram() const sourceFile = program?.getSourceFile(fileName) @@ -54,6 +54,7 @@ export default function completionEntryDetails( source, preferences, data, + ...args, ) if (detailPrepend) { prior ??= { diff --git a/typescript/src/completions/filesAutoImport.ts b/typescript/src/completions/filesAutoImport.ts index 13b9d066..207e16a0 100644 --- a/typescript/src/completions/filesAutoImport.ts +++ b/typescript/src/completions/filesAutoImport.ts @@ -60,7 +60,8 @@ export default () => { const files = collected.filter(f => f.endsWith(ext)) for (const file of files) { const fullPath = nodeModules.path.join(root, file) - const relativeToFile = nodeModules.path.relative(nodeModules.path.dirname(sourceFile.fileName), fullPath).replaceAll('\\', '/') + let relativeToFile = nodeModules.path.relative(nodeModules.path.dirname(sourceFile.fileName), fullPath).replaceAll('\\', '/') + if (!relativeToFile.startsWith('.')) relativeToFile = `./${relativeToFile}` const lastModified = nodeModules.fs.statSync(fullPath).mtime const lastModifiedFormatted = timeDifference(Date.now(), lastModified.getTime()) const importPath = (item.importPath ?? '$path').replaceAll('$path', relativeToFile) diff --git a/typescript/src/completionsAtPosition.ts b/typescript/src/completionsAtPosition.ts index 4beb54bb..1b2cbd13 100644 --- a/typescript/src/completionsAtPosition.ts +++ b/typescript/src/completionsAtPosition.ts @@ -68,6 +68,7 @@ export const getCompletionsAtPosition = ( scriptSnapshot: ts.IScriptSnapshot, formatOptions: ts.FormatCodeSettings | undefined, additionalData: { scriptKind: ts.ScriptKind; compilerOptions: ts.CompilerOptions }, + ...args: any[] ): GetCompletionAtPositionReturnType | undefined => { const prevCompletionsMap: PrevCompletionMap = {} const program = languageService.getProgram() @@ -94,6 +95,8 @@ export const getCompletionsAtPosition = ( includeSymbol: true, }, formatOptions, + //@ts-expect-error + ...args, ) } finally { unpatch?.() diff --git a/typescript/src/decorateEditsForFileRename.ts b/typescript/src/decorateEditsForFileRename.ts index 00c03f5c..69458b20 100644 --- a/typescript/src/decorateEditsForFileRename.ts +++ b/typescript/src/decorateEditsForFileRename.ts @@ -4,8 +4,8 @@ import { GetConfig } from './types' import { approveCast, findChildContainingExactPosition } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, c: GetConfig) => { - proxy.getEditsForFileRename = (oldFilePath, newFilePath, formatOptions, preferences) => { - let edits = languageService.getEditsForFileRename(oldFilePath, newFilePath, formatOptions, preferences) + proxy.getEditsForFileRename = (oldFilePath, newFilePath, formatOptions, preferences, ...args) => { + let edits = languageService.getEditsForFileRename(oldFilePath, newFilePath, formatOptions, preferences, ...args) if (c('renameImportNameOfFileRename')) { const predictedNameFromPath = (p: string) => { const input = p.split(/[/\\]/g).pop()!.replace(/\..+/, '') diff --git a/typescript/src/decorateLinkedEditing.ts b/typescript/src/decorateLinkedEditing.ts index 244d8d7c..e0bf4c1e 100644 --- a/typescript/src/decorateLinkedEditing.ts +++ b/typescript/src/decorateLinkedEditing.ts @@ -10,7 +10,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, result: ts.LinkedEditingInfo } | undefined - proxy.getLinkedEditingRangeAtPosition = (fileName, position) => { + proxy.getLinkedEditingRangeAtPosition = (fileName, position, ...props) => { const scriptSnapshot = languageServiceHost.getScriptSnapshot(fileName)! const fileContent = scriptSnapshot.getText(0, scriptSnapshot.getLength()) const lastChar = fileContent[position - 1] @@ -37,7 +37,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, } lastLinkedEditingRangeRequest = undefined - const prior = languageService.getLinkedEditingRangeAtPosition(fileName, position) + const prior = languageService.getLinkedEditingRangeAtPosition(fileName, position, ...props) if (!prior) return lastLinkedEditingRangeRequest = { pos: position, diff --git a/typescript/src/decorateProxy.ts b/typescript/src/decorateProxy.ts index 0eebc464..079b5bb4 100644 --- a/typescript/src/decorateProxy.ts +++ b/typescript/src/decorateProxy.ts @@ -12,7 +12,7 @@ import decorateDefinitions from './definitions' import decorateDocumentHighlights from './documentHighlights' import completionEntryDetails from './completionEntryDetails' import { GetConfig, PluginCreateArg } from './types' -import decorateWorkspaceSymbolSearch from './workspaceSymbolSearch' +import decorateWorkspaceSymbolSearch from './decorateWorkspaceSymbolSearch' import decorateFormatFeatures from './decorateFormatFeatures' import libDomPatching from './libDomPatching' import decorateSignatureHelp from './decorateSignatureHelp' @@ -51,9 +51,9 @@ export const decorateLanguageService = ( let prevCompletionsMap: PrevCompletionMap let prevCompletionsAdditionalData: PrevCompletionsAdditionalData - proxy.getCompletionsAtPosition = (fileName, position, options, formatOptions) => { + proxy.getCompletionsAtPosition = (fileName, position, options, formatOptions, ...args) => { if (options?.triggerCharacter && typeof options.triggerCharacter !== 'string') { - return languageService.getCompletionsAtPosition(fileName, position, options) + return languageService.getCompletionsAtPosition(fileName, position, options, formatOptions, ...args) } const updateConfigCommand = 'updateConfig' if (options?.triggerCharacter?.startsWith(updateConfigCommand)) { @@ -87,10 +87,21 @@ export const decorateLanguageService = ( if (!scriptSnapshot) return const compilerOptions = languageServiceHost.getCompilationSettings() try { - const result = getCompletionsAtPosition(fileName, position, options, c, languageService, languageServiceHost, scriptSnapshot, formatOptions, { - scriptKind, - compilerOptions, - }) + const result = getCompletionsAtPosition( + fileName, + position, + options, + c, + languageService, + languageServiceHost, + scriptSnapshot, + formatOptions, + { + scriptKind, + compilerOptions, + }, + ...args, + ) if (!result) return prevCompletionsMap = result.prevCompletionsMap prevCompletionsAdditionalData = result.prevCompletionsAdditionalData diff --git a/typescript/src/decorateSignatureHelp.ts b/typescript/src/decorateSignatureHelp.ts index 9f83d933..475242ba 100644 --- a/typescript/src/decorateSignatureHelp.ts +++ b/typescript/src/decorateSignatureHelp.ts @@ -3,7 +3,7 @@ import { GetConfig } from './types' import { findChildContainingExactPosition } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, languageServiceHost: ts.LanguageServiceHost, c: GetConfig) => { - proxy.getSignatureHelpItems = (fileName, position, options) => { + proxy.getSignatureHelpItems = (fileName, position, options, ...props) => { const program = languageService.getProgram()! const sourceFile = program.getSourceFile(fileName)! let node: ts.Node | undefined @@ -40,7 +40,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, } if (!c('signatureHelp.excludeBlockScope') || options?.triggerReason?.kind !== 'invoked') { - return languageService.getSignatureHelpItems(fileName, position, options) + return languageService.getSignatureHelpItems(fileName, position, options, ...props) } node ??= findChildContainingExactPosition(sourceFile, position) @@ -59,6 +59,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, kind: 'retrigger', }, }, + ...props, ) } } diff --git a/typescript/src/workspaceSymbolSearch.ts b/typescript/src/decorateWorkspaceSymbolSearch.ts similarity index 91% rename from typescript/src/workspaceSymbolSearch.ts rename to typescript/src/decorateWorkspaceSymbolSearch.ts index 329ffce0..d74373b1 100644 --- a/typescript/src/workspaceSymbolSearch.ts +++ b/typescript/src/decorateWorkspaceSymbolSearch.ts @@ -2,10 +2,10 @@ import { GetConfig } from './types' import { getCancellationToken } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, c: GetConfig, languageServiceHost: ts.LanguageServiceHost) => { - proxy.getNavigateToItems = (searchValue, maxResultCount, fileName, excludeDtsFiles) => { + proxy.getNavigateToItems = (searchValue, maxResultCount, fileName, excludeDtsFiles, ...args) => { const workspaceSymbolSearchExcludePatterns = c('workspaceSymbolSearchExcludePatterns') if (workspaceSymbolSearchExcludePatterns.length === 0) { - return languageService.getNavigateToItems(searchValue, maxResultCount, fileName, excludeDtsFiles) + return languageService.getNavigateToItems(searchValue, maxResultCount, fileName, excludeDtsFiles, ...args) } const program = languageService.getProgram()! @@ -25,6 +25,7 @@ export default (proxy: ts.LanguageService, languageService: ts.LanguageService, searchValue, maxResultCount, excludeDtsFiles ?? false, + ...args, ) } } diff --git a/typescript/src/definitions.ts b/typescript/src/definitions.ts index 77bd7a4c..ef749b4d 100644 --- a/typescript/src/definitions.ts +++ b/typescript/src/definitions.ts @@ -3,8 +3,8 @@ import { GetConfig } from './types' import { findChildContainingExactPosition } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, languageServiceHost: ts.LanguageServiceHost, c: GetConfig) => { - proxy.getDefinitionAndBoundSpan = (fileName, position) => { - const prior = languageService.getDefinitionAndBoundSpan(fileName, position) + proxy.getDefinitionAndBoundSpan = (fileName, position, ...props) => { + const prior = languageService.getDefinitionAndBoundSpan(fileName, position, ...props) if (c('removeModuleFileDefinitions') && prior) { prior.definitions = prior.definitions?.filter(def => { diff --git a/typescript/src/documentHighlights.ts b/typescript/src/documentHighlights.ts index 33a91586..23e62d9f 100644 --- a/typescript/src/documentHighlights.ts +++ b/typescript/src/documentHighlights.ts @@ -2,8 +2,8 @@ import { GetConfig } from './types' import { findChildContainingPosition } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, c: GetConfig) => { - proxy.getDocumentHighlights = (fileName, position, filesToSearch) => { - const prior = languageService.getDocumentHighlights(fileName, position, filesToSearch) + proxy.getDocumentHighlights = (fileName, position, filesToSearch, ...props) => { + const prior = languageService.getDocumentHighlights(fileName, position, filesToSearch, ...props) if (!prior) return if (prior.length !== 1 || c('disableUselessHighlighting') === 'disable') return prior const node = findChildContainingPosition(ts, languageService.getProgram()!.getSourceFile(fileName)!, position) diff --git a/typescript/src/getPatchedNavTree.ts b/typescript/src/getPatchedNavTree.ts index 158d1b87..1c6ceac9 100644 --- a/typescript/src/getPatchedNavTree.ts +++ b/typescript/src/getPatchedNavTree.ts @@ -1,5 +1,5 @@ import { ensureArray } from '@zardoy/utils' -import { getCancellationToken, isTs5, nodeModules } from './utils' +import { getCancellationToken, isTs5, isTs5And5, nodeModules } from './utils' import { createLanguageService } from './dummyLanguageService' import { getCannotFindCodes } from './utils/cannotFindCodes' @@ -11,8 +11,9 @@ type AdditionalFeatures = Record<'arraysTuplesNumberedItems', boolean> const getPatchedNavModule = (additionalFeatures: AdditionalFeatures): { getNavigationTree(...args) } => { // what is happening here: grabbing & patching NavigationBar module contents from actual running JS const tsServerPath = typeof __TS_SEVER_PATH__ === 'undefined' ? require.main!.filename : __TS_SEVER_PATH__ + const typescriptFilePath = `${nodeModules!.path.dirname(tsServerPath)}/typescript.js` // current lib/tsserver.js - const mainScript = nodeModules!.fs.readFileSync(tsServerPath, 'utf8') + const mainScript = nodeModules!.fs.readFileSync(isTs5And5() ? typescriptFilePath : tsServerPath, 'utf8') type PatchData = { markerModuleStart: string skipStartMarker?: boolean @@ -173,7 +174,7 @@ export const getNavTreeItems = ( fileName: string, additionalFeatures: AdditionalFeatures, ) => { - if (!navModule) navModule = getPatchedNavModule(additionalFeatures) + navModule = getPatchedNavModule(additionalFeatures) const sourceFile = (languageService as unknown as import('typescript-full').LanguageService).getNonBoundSourceFile?.(fileName) ?? languageService.getProgram()!.getSourceFile(fileName) diff --git a/typescript/src/references.ts b/typescript/src/references.ts index 40210083..33245fc0 100644 --- a/typescript/src/references.ts +++ b/typescript/src/references.ts @@ -2,8 +2,8 @@ import { GetConfig } from './types' import { findChildContainingPositionMaxDepth, approveCast, findChildContainingExactPosition, matchParents } from './utils' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, c: GetConfig) => { - proxy.findReferences = (fileName, position) => { - let prior = languageService.findReferences(fileName, position) + proxy.findReferences = (fileName, position, ...props) => { + let prior = languageService.findReferences(fileName, position, ...props) if (!prior) return const program = languageService.getProgram()! if (c('removeDefinitionFromReferences')) { diff --git a/typescript/src/semanticDiagnostics.ts b/typescript/src/semanticDiagnostics.ts index cbdddccc..fe4f283e 100644 --- a/typescript/src/semanticDiagnostics.ts +++ b/typescript/src/semanticDiagnostics.ts @@ -1,8 +1,8 @@ import { GetConfig } from './types' export default (proxy: ts.LanguageService, languageService: ts.LanguageService, languageServiceHost: ts.LanguageServiceHost, c: GetConfig) => { - proxy.getSemanticDiagnostics = fileName => { - let prior = languageService.getSemanticDiagnostics(fileName) + proxy.getSemanticDiagnostics = (fileName, ...props) => { + let prior = languageService.getSemanticDiagnostics(fileName, ...props) if (c('supportTsDiagnosticDisableComment')) { const scriptSnapshot = languageServiceHost.getScriptSnapshot(fileName)! const firstLine = scriptSnapshot.getText(0, scriptSnapshot.getLength()).split(/\r?\n/)[0]! diff --git a/typescript/src/utils.ts b/typescript/src/utils.ts index 1aea5e65..bb3f9360 100644 --- a/typescript/src/utils.ts +++ b/typescript/src/utils.ts @@ -131,6 +131,7 @@ export const buildStringCompletion = (node: ts.StringLiteralLike, completion: Ex // semver: can't use compare as it incorrectly works with build postfix export const isTs5 = () => semver.major(ts.version) >= 5 +export const isTs5And5 = () => (semver.major(ts.version) === 5 && semver.minor(ts.version) >= 5) || semver.major(ts.version) > 5 export const isTsPatched = () => { try {