"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
    return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.TypeScriptPlugin = 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 SnapshotManager_1 = require("./SnapshotManager");
const CodeActionsProvider_1 = require("./features/CodeActionsProvider");
const CompletionProvider_1 = require("./features/CompletionProvider");
const DiagnosticsProvider_1 = require("./features/DiagnosticsProvider");
const FindComponentReferencesProvider_1 = require("./features/FindComponentReferencesProvider");
const FindFileReferencesProvider_1 = require("./features/FindFileReferencesProvider");
const FindReferencesProvider_1 = require("./features/FindReferencesProvider");
const FoldingRangeProvider_1 = require("./features/FoldingRangeProvider");
const HoverProvider_1 = require("./features/HoverProvider");
const ImplementationProvider_1 = require("./features/ImplementationProvider");
const InlayHintProvider_1 = require("./features/InlayHintProvider");
const RenameProvider_1 = require("./features/RenameProvider");
const SelectionRangeProvider_1 = require("./features/SelectionRangeProvider");
const SemanticTokensProvider_1 = require("./features/SemanticTokensProvider");
const SignatureHelpProvider_1 = require("./features/SignatureHelpProvider");
const TypeDefinitionProvider_1 = require("./features/TypeDefinitionProvider");
const UpdateImportsProvider_1 = require("./features/UpdateImportsProvider");
const getDirectiveCommentCompletions_1 = require("./features/getDirectiveCommentCompletions");
const utils_2 = require("./features/utils");
const DocumentHighlightProvider_1 = require("./features/DocumentHighlightProvider");
const svelte_ast_utils_1 = require("./svelte-ast-utils");
const utils_3 = require("./utils");
const CallHierarchyProvider_1 = require("./features/CallHierarchyProvider");
const CodeLensProvider_1 = require("./features/CodeLensProvider");
const WorkspaceSymbolProvider_1 = require("./features/WorkspaceSymbolProvider");
class TypeScriptPlugin {
    constructor(configManager, lsAndTsDocResolver, workspaceUris, documentManager) {
        this.__name = 'ts';
        this.configManager = configManager;
        this.documentManager = documentManager;
        this.lsAndTsDocResolver = lsAndTsDocResolver;
        this.completionProvider = new CompletionProvider_1.CompletionsProviderImpl(this.lsAndTsDocResolver, this.configManager);
        this.codeActionsProvider = new CodeActionsProvider_1.CodeActionsProviderImpl(this.lsAndTsDocResolver, this.completionProvider, configManager);
        this.updateImportsProvider = new UpdateImportsProvider_1.UpdateImportsProviderImpl(this.lsAndTsDocResolver, typescript_1.default.sys.useCaseSensitiveFileNames);
        this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.lsAndTsDocResolver, configManager);
        this.renameProvider = new RenameProvider_1.RenameProviderImpl(this.lsAndTsDocResolver, configManager);
        this.hoverProvider = new HoverProvider_1.HoverProviderImpl(this.lsAndTsDocResolver);
        this.findFileReferencesProvider = new FindFileReferencesProvider_1.FindFileReferencesProviderImpl(this.lsAndTsDocResolver);
        this.findComponentReferencesProvider = new FindComponentReferencesProvider_1.FindComponentReferencesProviderImpl(this.lsAndTsDocResolver);
        this.findReferencesProvider = new FindReferencesProvider_1.FindReferencesProviderImpl(this.lsAndTsDocResolver, this.findComponentReferencesProvider);
        this.selectionRangeProvider = new SelectionRangeProvider_1.SelectionRangeProviderImpl(this.lsAndTsDocResolver);
        this.signatureHelpProvider = new SignatureHelpProvider_1.SignatureHelpProviderImpl(this.lsAndTsDocResolver);
        this.semanticTokensProvider = new SemanticTokensProvider_1.SemanticTokensProviderImpl(this.lsAndTsDocResolver);
        this.implementationProvider = new ImplementationProvider_1.ImplementationProviderImpl(this.lsAndTsDocResolver);
        this.typeDefinitionProvider = new TypeDefinitionProvider_1.TypeDefinitionProviderImpl(this.lsAndTsDocResolver);
        this.inlayHintProvider = new InlayHintProvider_1.InlayHintProviderImpl(this.lsAndTsDocResolver);
        this.callHierarchyProvider = new CallHierarchyProvider_1.CallHierarchyProviderImpl(this.lsAndTsDocResolver, workspaceUris);
        this.foldingRangeProvider = new FoldingRangeProvider_1.FoldingRangeProviderImpl(this.lsAndTsDocResolver, configManager);
        this.codLensProvider = new CodeLensProvider_1.CodeLensProviderImpl(this.lsAndTsDocResolver, this.findReferencesProvider, this.implementationProvider, this.configManager);
        this.documentHeightProvider = new DocumentHighlightProvider_1.DocumentHighlightProviderImpl(this.lsAndTsDocResolver);
        this.workspaceSymbolsProvider = new WorkspaceSymbolProvider_1.WorkspaceSymbolsProviderImpl(this.lsAndTsDocResolver, configManager);
    }
    async getDiagnostics(document, cancellationToken) {
        if (!this.featureEnabled('diagnostics')) {
            return [];
        }
        return this.diagnosticsProvider.getDiagnostics(document, cancellationToken);
    }
    async getDiagnosticsForPullMode(document, previousResultId, cancellationToken) {
        if (!this.featureEnabled('diagnostics')) {
            return {
                kind: 'full',
                items: []
            };
        }
        return this.diagnosticsProvider.getDiagnosticsForPullMode(document, previousResultId, cancellationToken);
    }
    async doHover(document, position) {
        if (!this.featureEnabled('hover')) {
            return null;
        }
        return this.hoverProvider.doHover(document, position);
    }
    async getDocumentSymbols(document, cancellationToken) {
        if (!this.featureEnabled('documentSymbols')) {
            return [];
        }
        const { lang, tsDoc } = await this.lsAndTsDocResolver.getLsForSyntheticOperations(document);
        if (cancellationToken?.isCancellationRequested) {
            return [];
        }
        const navTree = lang.getNavigationTree(tsDoc.filePath);
        const symbols = [];
        collectSymbols(navTree, undefined, (symbol) => symbols.push(symbol));
        const topContainerName = symbols[0].name;
        const result = [];
        for (let symbol of symbols.slice(1)) {
            if (symbol.containerName === topContainerName) {
                symbol.containerName = 'script';
            }
            symbol = (0, documents_1.mapSymbolInformationToOriginal)(tsDoc, symbol);
            if (symbol.location.range.start.line < 0 ||
                symbol.location.range.end.line < 0 ||
                (0, utils_1.isZeroLengthRange)(symbol.location.range) ||
                symbol.name.startsWith('__sveltets_')) {
                continue;
            }
            if ((symbol.kind === vscode_languageserver_1.SymbolKind.Property || symbol.kind === vscode_languageserver_1.SymbolKind.Method) &&
                !(0, utils_3.isInScript)(symbol.location.range.start, document)) {
                if (symbol.name === 'props' &&
                    document.getText().charAt(document.offsetAt(symbol.location.range.start)) !==
                        'p') {
                    // This is the "props" of a generated component constructor
                    continue;
                }
                const node = tsDoc.svelteNodeAt(symbol.location.range.start);
                if ((node && ((0, svelte_ast_utils_1.isAttributeName)(node) || (0, svelte_ast_utils_1.isAttributeShorthand)(node))) ||
                    (0, svelte_ast_utils_1.isEventHandler)(node)) {
                    // This is a html or component property, they are not treated as a new symbol
                    // in JSX and so we do the same for the new transformation.
                    continue;
                }
            }
            if (symbol.name === '<function>') {
                let name = (0, documents_1.getTextInRange)(symbol.location.range, document.getText()).trimLeft();
                if (name.length > 50) {
                    name = name.substring(0, 50) + '...';
                }
                symbol.name = name;
            }
            if (symbol.name.startsWith('$$_')) {
                if (!symbol.name.includes('$on')) {
                    continue;
                }
                // on:foo={() => ''}   ->   $on("foo") callback
                symbol.name = symbol.name.substring(symbol.name.indexOf('$on'));
            }
            result.push(symbol);
        }
        return result;
        function collectSymbols(tree, container, cb) {
            const start = tree.spans[0];
            const end = tree.spans[tree.spans.length - 1];
            if (start && end) {
                cb(vscode_languageserver_1.SymbolInformation.create(tree.text, (0, utils_3.symbolKindFromString)(tree.kind), vscode_languageserver_1.Range.create(tsDoc.positionAt(start.start), tsDoc.positionAt(end.start + end.length)), tsDoc.getURL(), container));
            }
            if (tree.childItems) {
                for (const child of tree.childItems) {
                    collectSymbols(child, tree.text, cb);
                }
            }
        }
    }
    async getCompletions(document, position, completionContext, cancellationToken) {
        if (!this.featureEnabled('completions')) {
            return null;
        }
        const tsDirectiveCommentCompletions = (0, getDirectiveCommentCompletions_1.getDirectiveCommentCompletions)(position, document, completionContext);
        const completions = await this.completionProvider.getCompletions(document, position, completionContext, cancellationToken);
        if (completions && tsDirectiveCommentCompletions) {
            return vscode_languageserver_1.CompletionList.create(completions.items.concat(tsDirectiveCommentCompletions.items), completions.isIncomplete);
        }
        return completions ?? tsDirectiveCommentCompletions;
    }
    async resolveCompletion(document, completionItem, cancellationToken) {
        return this.completionProvider.resolveCompletion(document, completionItem, cancellationToken);
    }
    async getDefinitions(document, position) {
        const { lang, tsDoc, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document);
        const defs = lang.getDefinitionAndBoundSpan(tsDoc.filePath, tsDoc.offsetAt(tsDoc.getGeneratedPosition(position)));
        if (!defs || !defs.definitions) {
            return [];
        }
        const snapshots = new utils_2.SnapshotMap(this.lsAndTsDocResolver, lsContainer);
        snapshots.set(tsDoc.filePath, tsDoc);
        const result = await Promise.all(defs.definitions.map(async (def) => {
            if ((0, utils_3.isSvelte2tsxShimFile)(def.fileName)) {
                return;
            }
            let snapshot = await snapshots.retrieve(def.fileName);
            // Go from generated $store to store if user wants to find definition for $store
            if ((0, utils_2.isTextSpanInGeneratedCode)(snapshot.getFullText(), def.textSpan)) {
                if (!(0, utils_2.is$storeVariableIn$storeDeclaration)(snapshot.getFullText(), def.textSpan.start)) {
                    return;
                }
                // there will be exactly one definition, the store
                def = lang.getDefinitionAndBoundSpan(tsDoc.filePath, tsDoc.getFullText().indexOf(');', def.textSpan.start) - 1).definitions[0];
                snapshot = await snapshots.retrieve(def.fileName);
            }
            const defLocation = (0, utils_3.convertToLocationForReferenceOrDefinition)(snapshot, def.textSpan);
            return vscode_languageserver_1.LocationLink.create(defLocation.uri, defLocation.range, defLocation.range, (0, utils_3.convertToLocationRange)(tsDoc, defs.textSpan));
        }));
        return result.filter(utils_1.isNotNullOrUndefined);
    }
    async prepareRename(document, position) {
        return this.renameProvider.prepareRename(document, position);
    }
    async rename(document, position, newName) {
        return this.renameProvider.rename(document, position, newName);
    }
    async getCodeActions(document, range, context, cancellationToken) {
        if (!this.featureEnabled('codeActions')) {
            return [];
        }
        return this.codeActionsProvider.getCodeActions(document, range, context, cancellationToken);
    }
    async resolveCodeAction(document, codeAction, cancellationToken) {
        return this.codeActionsProvider.resolveCodeAction(document, codeAction, cancellationToken);
    }
    async executeCommand(document, command, args) {
        if (!this.featureEnabled('codeActions')) {
            return null;
        }
        return this.codeActionsProvider.executeCommand(document, command, args);
    }
    async updateImports(fileRename) {
        if (!(this.configManager.enabled('svelte.enable') &&
            this.configManager.enabled('svelte.rename.enable'))) {
            return null;
        }
        return this.updateImportsProvider.updateImports(fileRename);
    }
    async findReferences(document, position, context) {
        return this.findReferencesProvider.findReferences(document, position, context);
    }
    async fileReferences(uri) {
        return this.findFileReferencesProvider.fileReferences(uri);
    }
    async findComponentReferences(uri) {
        return this.findComponentReferencesProvider.findComponentReferences(uri);
    }
    async onWatchFileChanges(onWatchFileChangesParas) {
        const newFiles = [];
        for (const { fileName, changeType } of onWatchFileChangesParas) {
            const pathParts = fileName.split(/\/|\\/);
            const dirPathParts = pathParts.slice(0, pathParts.length - 1);
            const declarationExtensions = [typescript_1.default.Extension.Dcts, typescript_1.default.Extension.Dts, typescript_1.default.Extension.Dmts];
            const canSafelyIgnore = declarationExtensions.every((ext) => !fileName.endsWith(ext)) &&
                SnapshotManager_1.ignoredBuildDirectories.some((dir) => {
                    const index = dirPathParts.indexOf(dir);
                    return (
                    // Files in .svelte-kit/types should always come through
                    index > 0 && (dir !== '.svelte-kit' || dirPathParts[index + 1] !== 'types'));
                });
            if (canSafelyIgnore) {
                continue;
            }
            const isSvelteFile = (0, utils_3.isSvelteFilePath)(fileName);
            const isClientSvelteFile = isSvelteFile && this.documentManager.get((0, utils_1.pathToUrl)(fileName))?.openedByClient;
            if (changeType === vscode_languageserver_1.FileChangeType.Deleted) {
                if (!isClientSvelteFile) {
                    await this.lsAndTsDocResolver.deleteSnapshot(fileName);
                }
                continue;
            }
            if (changeType === vscode_languageserver_1.FileChangeType.Created) {
                newFiles.push(fileName);
                continue;
            }
            if (isSvelteFile) {
                if (!isClientSvelteFile) {
                    await this.lsAndTsDocResolver.updateExistingSvelteFile(fileName);
                }
                continue;
            }
            await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName);
        }
        if (newFiles.length) {
            await this.lsAndTsDocResolver.updateProjectFiles(newFiles);
            await this.lsAndTsDocResolver.invalidateModuleCache(newFiles);
        }
    }
    async updateTsOrJsFile(fileName, changes) {
        await this.lsAndTsDocResolver.updateExistingTsOrJsFile(fileName, changes);
    }
    async getSelectionRange(document, position) {
        if (!this.featureEnabled('selectionRange')) {
            return null;
        }
        return this.selectionRangeProvider.getSelectionRange(document, position);
    }
    async getSignatureHelp(document, position, context, cancellationToken) {
        if (!this.featureEnabled('signatureHelp')) {
            return null;
        }
        return this.signatureHelpProvider.getSignatureHelp(document, position, context, cancellationToken);
    }
    async getSemanticTokens(textDocument, range, cancellationToken) {
        if (!this.featureEnabled('semanticTokens')) {
            return {
                data: []
            };
        }
        return this.semanticTokensProvider.getSemanticTokens(textDocument, range, cancellationToken);
    }
    async getImplementation(document, position, cancellationToken) {
        return this.implementationProvider.getImplementation(document, position, cancellationToken);
    }
    async getTypeDefinition(document, position) {
        return this.typeDefinitionProvider.getTypeDefinition(document, position);
    }
    async getInlayHints(document, range, cancellationToken) {
        if (!this.configManager.enabled('typescript.enable')) {
            return null;
        }
        return this.inlayHintProvider.getInlayHints(document, range, cancellationToken);
    }
    prepareCallHierarchy(document, position, cancellationToken) {
        return this.callHierarchyProvider.prepareCallHierarchy(document, position, cancellationToken);
    }
    getIncomingCalls(item, cancellationToken) {
        return this.callHierarchyProvider.getIncomingCalls(item, cancellationToken);
    }
    async getOutgoingCalls(item, cancellationToken) {
        return this.callHierarchyProvider.getOutgoingCalls(item, cancellationToken);
    }
    async getFoldingRanges(document) {
        return this.foldingRangeProvider.getFoldingRanges(document);
    }
    getCodeLens(document) {
        return this.codLensProvider.getCodeLens(document);
    }
    resolveCodeLens(document, codeLensToResolve, cancellationToken) {
        return this.codLensProvider.resolveCodeLens(document, codeLensToResolve, cancellationToken);
    }
    async findDocumentHighlight(document, position) {
        return this.documentHeightProvider.findDocumentHighlight(document, position);
    }
    async getWorkspaceSymbols(query, cancellationToken) {
        if (!this.featureEnabled('workspaceSymbols')) {
            return null;
        }
        return this.workspaceSymbolsProvider.getWorkspaceSymbols(query, cancellationToken);
    }
    featureEnabled(feature) {
        return (this.configManager.enabled('typescript.enable') &&
            this.configManager.enabled(`typescript.${feature}.enable`));
    }
}
exports.TypeScriptPlugin = TypeScriptPlugin;
//# sourceMappingURL=TypeScriptPlugin.js.map