UNPKG

svelte-language-server

Version:
205 lines 10.6 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.CodeLensProviderImpl = void 0; const typescript_1 = __importDefault(require("typescript")); const vscode_languageserver_1 = require("vscode-languageserver"); const documents_1 = require("../../../lib/documents"); const utils_1 = require("../../../utils"); const utils_2 = require("../utils"); const utils_3 = require("./utils"); const svelte2tsx_1 = require("svelte2tsx"); class CodeLensProviderImpl { constructor(lsAndTsDocResolver, referenceProvider, implementationProvider, configManager) { this.lsAndTsDocResolver = lsAndTsDocResolver; this.referenceProvider = referenceProvider; this.implementationProvider = implementationProvider; this.configManager = configManager; } async getCodeLens(document) { if (!this.anyCodeLensEnabled('typescript') && !this.anyCodeLensEnabled('javascript')) { return null; } const { lang, tsDoc } = await this.lsAndTsDocResolver.getLsForSyntheticOperations(document); const results = []; const collectors = []; const clientTsConfig = this.configManager.getClientTsUserConfig(tsDoc.scriptKind === typescript_1.default.ScriptKind.TS ? 'typescript' : 'javascript'); if (clientTsConfig.referencesCodeLens?.enabled) { collectors.push({ type: 'reference', collect: (tsDoc, item, parent) => this.extractReferenceLocation(tsDoc, item, parent, clientTsConfig) }); if (!tsDoc.parserError) { // always add a reference code lens for the generated component results.push([ 'reference', { start: { line: 0, character: 0 }, // some client refused to resolve the code lens if the start is the same as the end end: { line: 0, character: 1 } } ]); } } if (tsDoc.scriptKind === typescript_1.default.ScriptKind.TS && clientTsConfig.implementationsCodeLens?.enabled) { collectors.push({ type: 'implementation', collect: (tsDoc, item, parent) => this.extractImplementationLocation(tsDoc, item, clientTsConfig, parent) }); } if (!collectors.length) { return null; } const navigationTree = lang.getNavigationTree(tsDoc.filePath); const renderFunction = navigationTree?.childItems?.find((item) => item.text === svelte2tsx_1.internalHelpers.renderName); if (renderFunction) { // pretty rare that there is anything to show in the template, so we skip it const notTemplate = renderFunction.childItems?.filter((item) => item.text !== '<function>'); renderFunction.childItems = notTemplate; } this.walkTree(tsDoc, navigationTree, undefined, results, collectors); const uri = document.uri; return results.map(([type, range]) => vscode_languageserver_1.CodeLens.create(range, { type, uri })); } anyCodeLensEnabled(lang) { const vscodeTsConfig = this.configManager.getClientTsUserConfig(lang); return (vscodeTsConfig.referencesCodeLens?.enabled || vscodeTsConfig.implementationsCodeLens?.enabled); } /** * https://github.com/microsoft/vscode/blob/062ba1ed6c2b9ff4819f4f7dad76de3fde0044ab/extensions/typescript-language-features/src/languageFeatures/codeLens/referencesCodeLens.ts#L61 */ extractReferenceLocation(tsDoc, item, parent, config) { if (parent && parent.kind === typescript_1.default.ScriptElementKind.enumElement) { return this.getSymbolRange(tsDoc, item); } switch (item.kind) { case typescript_1.default.ScriptElementKind.functionElement: { const showOnAllFunctions = config.referencesCodeLens?.showOnAllFunctions; if (showOnAllFunctions) { return this.getSymbolRange(tsDoc, item); } if (this.isExported(item, tsDoc)) { return this.getSymbolRange(tsDoc, item); } break; } case typescript_1.default.ScriptElementKind.constElement: case typescript_1.default.ScriptElementKind.letElement: case typescript_1.default.ScriptElementKind.variableElement: // Only show references for exported variables if (this.isExported(item, tsDoc)) { return this.getSymbolRange(tsDoc, item); } break; case typescript_1.default.ScriptElementKind.classElement: if (item.text === '<class>') { break; } return this.getSymbolRange(tsDoc, item); case typescript_1.default.ScriptElementKind.interfaceElement: case typescript_1.default.ScriptElementKind.typeElement: case typescript_1.default.ScriptElementKind.enumElement: return this.getSymbolRange(tsDoc, item); case typescript_1.default.ScriptElementKind.memberFunctionElement: case typescript_1.default.ScriptElementKind.memberGetAccessorElement: case typescript_1.default.ScriptElementKind.memberSetAccessorElement: case typescript_1.default.ScriptElementKind.constructorImplementationElement: case typescript_1.default.ScriptElementKind.memberVariableElement: if (parent?.spans[0].start === item.spans[0].start) { return undefined; } // Only show if parent is a class type object (not a literal) switch (parent?.kind) { case typescript_1.default.ScriptElementKind.classElement: case typescript_1.default.ScriptElementKind.interfaceElement: case typescript_1.default.ScriptElementKind.typeElement: return this.getSymbolRange(tsDoc, item); } break; } return undefined; } isExported(item, tsDoc) { return !tsDoc.parserError && item.kindModifiers.match(/\bexport\b/g) !== null; } /** * https://github.com/microsoft/vscode/blob/062ba1ed6c2b9ff4819f4f7dad76de3fde0044ab/extensions/typescript-language-features/src/languageFeatures/codeLens/implementationsCodeLens.ts#L66 */ extractImplementationLocation(tsDoc, item, config, parent) { if (item.kind === typescript_1.default.ScriptElementKind.memberFunctionElement && parent && parent.kind === typescript_1.default.ScriptElementKind.interfaceElement && config.implementationsCodeLens?.showOnInterfaceMethods === true) { return this.getSymbolRange(tsDoc, item); } switch (item.kind) { case typescript_1.default.ScriptElementKind.interfaceElement: return this.getSymbolRange(tsDoc, item); case typescript_1.default.ScriptElementKind.classElement: case typescript_1.default.ScriptElementKind.memberFunctionElement: case typescript_1.default.ScriptElementKind.memberVariableElement: case typescript_1.default.ScriptElementKind.memberGetAccessorElement: case typescript_1.default.ScriptElementKind.memberSetAccessorElement: if (item.kindModifiers.match(/\babstract\b/g)) { return this.getSymbolRange(tsDoc, item); } break; } return undefined; } getSymbolRange(tsDoc, item) { if (!item.nameSpan || (0, utils_3.isTextSpanInGeneratedCode)(tsDoc.getFullText(), item.nameSpan)) { return; } const range = (0, documents_1.mapRangeToOriginal)(tsDoc, (0, utils_2.convertRange)(tsDoc, item.nameSpan)); if (range.start.line >= 0 && range.end.line >= 0) { return (0, utils_1.isZeroLengthRange)(range) ? undefined : range; } } walkTree(tsDoc, item, parent, results, collectors) { for (const collector of collectors) { const range = collector.collect(tsDoc, item, parent); if (range) { results.push([collector.type, range]); } } item.childItems?.forEach((child) => this.walkTree(tsDoc, child, item, results, collectors)); } async resolveCodeLens(textDocument, codeLensToResolve, cancellationToken) { if (codeLensToResolve.data.type === 'reference') { return await this.resolveReferenceCodeLens(textDocument, codeLensToResolve, cancellationToken); } if (codeLensToResolve.data.type === 'implementation') { return await this.resolveImplementationCodeLens(textDocument, codeLensToResolve, cancellationToken); } return codeLensToResolve; } async resolveReferenceCodeLens(textDocument, codeLensToResolve, cancellationToken) { const references = (await this.referenceProvider.findReferences(textDocument, codeLensToResolve.range.start, { includeDeclaration: false }, cancellationToken)) ?? []; codeLensToResolve.command = { title: references.length === 1 ? `1 reference` : `${references.length} references`, // language clients need to map this to the corresponding command in each editor // see example in svelte-vscode/src/middlewares.ts command: '', arguments: [textDocument.uri, codeLensToResolve.range.start, references] }; return codeLensToResolve; } async resolveImplementationCodeLens(textDocument, codeLensToResolve, cancellationToken) { const implementations = (await this.implementationProvider.getImplementation(textDocument, codeLensToResolve.range.start, cancellationToken)) ?? []; codeLensToResolve.command = { title: implementations.length === 1 ? `1 implementation` : `${implementations.length} implementations`, command: '', arguments: [textDocument.uri, codeLensToResolve.range.start, implementations] }; return codeLensToResolve; } } exports.CodeLensProviderImpl = CodeLensProviderImpl; //# sourceMappingURL=CodeLensProvider.js.map