@macroforge/svelte-language-server 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +331 -0
- package/bin/server.js +5 -0
- package/dist/src/importPackage.d.ts +16 -0
- package/dist/src/importPackage.js +76 -0
- package/dist/src/importPackage.js.map +1 -0
- package/dist/src/index.d.ts +3 -0
- package/dist/src/index.js +23 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/lib/DiagnosticsManager.d.ts +20 -0
- package/dist/src/lib/DiagnosticsManager.js +71 -0
- package/dist/src/lib/DiagnosticsManager.js.map +1 -0
- package/dist/src/lib/FallbackWatcher.d.ts +15 -0
- package/dist/src/lib/FallbackWatcher.js +66 -0
- package/dist/src/lib/FallbackWatcher.js.map +1 -0
- package/dist/src/lib/documentHighlight/wordHighlight.d.ts +3 -0
- package/dist/src/lib/documentHighlight/wordHighlight.js +62 -0
- package/dist/src/lib/documentHighlight/wordHighlight.js.map +1 -0
- package/dist/src/lib/documents/Document.d.ts +63 -0
- package/dist/src/lib/documents/Document.js +138 -0
- package/dist/src/lib/documents/Document.js.map +1 -0
- package/dist/src/lib/documents/DocumentBase.d.ts +65 -0
- package/dist/src/lib/documents/DocumentBase.js +69 -0
- package/dist/src/lib/documents/DocumentBase.js.map +1 -0
- package/dist/src/lib/documents/DocumentManager.d.ts +28 -0
- package/dist/src/lib/documents/DocumentManager.js +122 -0
- package/dist/src/lib/documents/DocumentManager.js.map +1 -0
- package/dist/src/lib/documents/DocumentMapper.d.ts +88 -0
- package/dist/src/lib/documents/DocumentMapper.js +258 -0
- package/dist/src/lib/documents/DocumentMapper.js.map +1 -0
- package/dist/src/lib/documents/configLoader.d.ts +80 -0
- package/dist/src/lib/documents/configLoader.js +265 -0
- package/dist/src/lib/documents/configLoader.js.map +1 -0
- package/dist/src/lib/documents/fileCollection.d.ts +41 -0
- package/dist/src/lib/documents/fileCollection.js +87 -0
- package/dist/src/lib/documents/fileCollection.js.map +1 -0
- package/dist/src/lib/documents/index.d.ts +5 -0
- package/dist/src/lib/documents/index.js +22 -0
- package/dist/src/lib/documents/index.js.map +1 -0
- package/dist/src/lib/documents/parseHtml.d.ts +13 -0
- package/dist/src/lib/documents/parseHtml.js +160 -0
- package/dist/src/lib/documents/parseHtml.js.map +1 -0
- package/dist/src/lib/documents/utils.d.ts +105 -0
- package/dist/src/lib/documents/utils.js +410 -0
- package/dist/src/lib/documents/utils.js.map +1 -0
- package/dist/src/lib/foldingRange/indentFolding.d.ts +26 -0
- package/dist/src/lib/foldingRange/indentFolding.js +142 -0
- package/dist/src/lib/foldingRange/indentFolding.js.map +1 -0
- package/dist/src/lib/semanticToken/semanticTokenLegend.d.ts +33 -0
- package/dist/src/lib/semanticToken/semanticTokenLegend.js +37 -0
- package/dist/src/lib/semanticToken/semanticTokenLegend.js.map +1 -0
- package/dist/src/logger.d.ts +9 -0
- package/dist/src/logger.js +28 -0
- package/dist/src/logger.js.map +1 -0
- package/dist/src/ls-config.d.ts +326 -0
- package/dist/src/ls-config.js +386 -0
- package/dist/src/ls-config.js.map +1 -0
- package/dist/src/plugins/PluginHost.d.ts +68 -0
- package/dist/src/plugins/PluginHost.js +447 -0
- package/dist/src/plugins/PluginHost.js.map +1 -0
- package/dist/src/plugins/css/CSSDocument.d.ts +46 -0
- package/dist/src/plugins/css/CSSDocument.js +78 -0
- package/dist/src/plugins/css/CSSDocument.js.map +1 -0
- package/dist/src/plugins/css/CSSPlugin.d.ts +35 -0
- package/dist/src/plugins/css/CSSPlugin.js +407 -0
- package/dist/src/plugins/css/CSSPlugin.js.map +1 -0
- package/dist/src/plugins/css/FileSystemProvider.d.ts +10 -0
- package/dist/src/plugins/css/FileSystemProvider.js +75 -0
- package/dist/src/plugins/css/FileSystemProvider.js.map +1 -0
- package/dist/src/plugins/css/StyleAttributeDocument.d.ts +41 -0
- package/dist/src/plugins/css/StyleAttributeDocument.js +65 -0
- package/dist/src/plugins/css/StyleAttributeDocument.js.map +1 -0
- package/dist/src/plugins/css/features/getIdClassCompletion.d.ts +19 -0
- package/dist/src/plugins/css/features/getIdClassCompletion.js +56 -0
- package/dist/src/plugins/css/features/getIdClassCompletion.js.map +1 -0
- package/dist/src/plugins/css/features/svelte-selectors.d.ts +2 -0
- package/dist/src/plugins/css/features/svelte-selectors.js +18 -0
- package/dist/src/plugins/css/features/svelte-selectors.js.map +1 -0
- package/dist/src/plugins/css/global-vars.d.ts +16 -0
- package/dist/src/plugins/css/global-vars.js +82 -0
- package/dist/src/plugins/css/global-vars.js.map +1 -0
- package/dist/src/plugins/css/service.d.ts +5 -0
- package/dist/src/plugins/css/service.js +66 -0
- package/dist/src/plugins/css/service.js.map +1 -0
- package/dist/src/plugins/documentContext.d.ts +3 -0
- package/dist/src/plugins/documentContext.js +36 -0
- package/dist/src/plugins/documentContext.js.map +1 -0
- package/dist/src/plugins/html/HTMLPlugin.d.ts +36 -0
- package/dist/src/plugins/html/HTMLPlugin.js +363 -0
- package/dist/src/plugins/html/HTMLPlugin.js.map +1 -0
- package/dist/src/plugins/html/dataProvider.d.ts +1 -0
- package/dist/src/plugins/html/dataProvider.js +481 -0
- package/dist/src/plugins/html/dataProvider.js.map +1 -0
- package/dist/src/plugins/index.d.ts +7 -0
- package/dist/src/plugins/index.js +24 -0
- package/dist/src/plugins/index.js.map +1 -0
- package/dist/src/plugins/interfaces.d.ts +132 -0
- package/dist/src/plugins/interfaces.js +3 -0
- package/dist/src/plugins/interfaces.js.map +1 -0
- package/dist/src/plugins/svelte/SvelteDocument.d.ts +98 -0
- package/dist/src/plugins/svelte/SvelteDocument.js +318 -0
- package/dist/src/plugins/svelte/SvelteDocument.js.map +1 -0
- package/dist/src/plugins/svelte/SveltePlugin.d.ts +24 -0
- package/dist/src/plugins/svelte/SveltePlugin.js +306 -0
- package/dist/src/plugins/svelte/SveltePlugin.js.map +1 -0
- package/dist/src/plugins/svelte/features/SvelteTags.d.ts +28 -0
- package/dist/src/plugins/svelte/features/SvelteTags.js +136 -0
- package/dist/src/plugins/svelte/features/SvelteTags.js.map +1 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.d.ts +11 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.js +140 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.js.map +1 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.d.ts +9 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.js +140 -0
- package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.js.map +1 -0
- package/dist/src/plugins/svelte/features/getCodeActions/index.d.ts +4 -0
- package/dist/src/plugins/svelte/features/getCodeActions/index.js +19 -0
- package/dist/src/plugins/svelte/features/getCodeActions/index.js.map +1 -0
- package/dist/src/plugins/svelte/features/getCompletions.d.ts +4 -0
- package/dist/src/plugins/svelte/features/getCompletions.js +184 -0
- package/dist/src/plugins/svelte/features/getCompletions.js.map +1 -0
- package/dist/src/plugins/svelte/features/getDiagnostics.d.ts +9 -0
- package/dist/src/plugins/svelte/features/getDiagnostics.js +284 -0
- package/dist/src/plugins/svelte/features/getDiagnostics.js.map +1 -0
- package/dist/src/plugins/svelte/features/getHoverInfo.d.ts +7 -0
- package/dist/src/plugins/svelte/features/getHoverInfo.js +93 -0
- package/dist/src/plugins/svelte/features/getHoverInfo.js.map +1 -0
- package/dist/src/plugins/svelte/features/getModifierData.d.ts +7 -0
- package/dist/src/plugins/svelte/features/getModifierData.js +56 -0
- package/dist/src/plugins/svelte/features/getModifierData.js.map +1 -0
- package/dist/src/plugins/svelte/features/getSelectionRanges.d.ts +3 -0
- package/dist/src/plugins/svelte/features/getSelectionRanges.js +46 -0
- package/dist/src/plugins/svelte/features/getSelectionRanges.js.map +1 -0
- package/dist/src/plugins/svelte/features/utils.d.ts +5 -0
- package/dist/src/plugins/svelte/features/utils.js +18 -0
- package/dist/src/plugins/svelte/features/utils.js.map +1 -0
- package/dist/src/plugins/typescript/ComponentInfoProvider.d.ts +27 -0
- package/dist/src/plugins/typescript/ComponentInfoProvider.js +116 -0
- package/dist/src/plugins/typescript/ComponentInfoProvider.js.map +1 -0
- package/dist/src/plugins/typescript/DocumentMapper.d.ts +10 -0
- package/dist/src/plugins/typescript/DocumentMapper.js +25 -0
- package/dist/src/plugins/typescript/DocumentMapper.js.map +1 -0
- package/dist/src/plugins/typescript/DocumentSnapshot.d.ts +173 -0
- package/dist/src/plugins/typescript/DocumentSnapshot.js +623 -0
- package/dist/src/plugins/typescript/DocumentSnapshot.js.map +1 -0
- package/dist/src/plugins/typescript/LSAndTSDocResolver.d.ts +100 -0
- package/dist/src/plugins/typescript/LSAndTSDocResolver.js +301 -0
- package/dist/src/plugins/typescript/LSAndTSDocResolver.js.map +1 -0
- package/dist/src/plugins/typescript/SnapshotManager.d.ts +59 -0
- package/dist/src/plugins/typescript/SnapshotManager.js +238 -0
- package/dist/src/plugins/typescript/SnapshotManager.js.map +1 -0
- package/dist/src/plugins/typescript/TypeScriptPlugin.d.ts +65 -0
- package/dist/src/plugins/typescript/TypeScriptPlugin.js +332 -0
- package/dist/src/plugins/typescript/TypeScriptPlugin.js.map +1 -0
- package/dist/src/plugins/typescript/features/CallHierarchyProvider.d.ts +24 -0
- package/dist/src/plugins/typescript/features/CallHierarchyProvider.js +325 -0
- package/dist/src/plugins/typescript/features/CallHierarchyProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/CodeActionsProvider.d.ts +72 -0
- package/dist/src/plugins/typescript/features/CodeActionsProvider.js +1030 -0
- package/dist/src/plugins/typescript/features/CodeActionsProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/CodeLensProvider.d.ts +28 -0
- package/dist/src/plugins/typescript/features/CodeLensProvider.js +205 -0
- package/dist/src/plugins/typescript/features/CodeLensProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/CompletionProvider.d.ts +57 -0
- package/dist/src/plugins/typescript/features/CompletionProvider.js +791 -0
- package/dist/src/plugins/typescript/features/CompletionProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/DiagnosticsProvider.d.ts +36 -0
- package/dist/src/plugins/typescript/features/DiagnosticsProvider.js +497 -0
- package/dist/src/plugins/typescript/features/DiagnosticsProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/DocumentHighlightProvider.d.ts +17 -0
- package/dist/src/plugins/typescript/features/DocumentHighlightProvider.js +211 -0
- package/dist/src/plugins/typescript/features/DocumentHighlightProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.d.ts +9 -0
- package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.js +66 -0
- package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/FindFileReferencesProvider.d.ts +9 -0
- package/dist/src/plugins/typescript/features/FindFileReferencesProvider.js +38 -0
- package/dist/src/plugins/typescript/features/FindFileReferencesProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/FindReferencesProvider.d.ts +20 -0
- package/dist/src/plugins/typescript/features/FindReferencesProvider.js +149 -0
- package/dist/src/plugins/typescript/features/FindReferencesProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/FoldingRangeProvider.d.ts +28 -0
- package/dist/src/plugins/typescript/features/FoldingRangeProvider.js +247 -0
- package/dist/src/plugins/typescript/features/FoldingRangeProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/HoverProvider.d.ts +11 -0
- package/dist/src/plugins/typescript/features/HoverProvider.js +75 -0
- package/dist/src/plugins/typescript/features/HoverProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/ImplementationProvider.d.ts +9 -0
- package/dist/src/plugins/typescript/features/ImplementationProvider.js +47 -0
- package/dist/src/plugins/typescript/features/ImplementationProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/InlayHintProvider.d.ts +22 -0
- package/dist/src/plugins/typescript/features/InlayHintProvider.js +225 -0
- package/dist/src/plugins/typescript/features/InlayHintProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/RenameProvider.d.ts +53 -0
- package/dist/src/plugins/typescript/features/RenameProvider.js +423 -0
- package/dist/src/plugins/typescript/features/RenameProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/SelectionRangeProvider.d.ts +18 -0
- package/dist/src/plugins/typescript/features/SelectionRangeProvider.js +62 -0
- package/dist/src/plugins/typescript/features/SelectionRangeProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/SemanticTokensProvider.d.ts +15 -0
- package/dist/src/plugins/typescript/features/SemanticTokensProvider.js +116 -0
- package/dist/src/plugins/typescript/features/SemanticTokensProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/SignatureHelpProvider.d.ts +22 -0
- package/dist/src/plugins/typescript/features/SignatureHelpProvider.js +110 -0
- package/dist/src/plugins/typescript/features/SignatureHelpProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/TypeDefinitionProvider.d.ts +9 -0
- package/dist/src/plugins/typescript/features/TypeDefinitionProvider.js +35 -0
- package/dist/src/plugins/typescript/features/TypeDefinitionProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/UpdateImportsProvider.d.ts +11 -0
- package/dist/src/plugins/typescript/features/UpdateImportsProvider.js +109 -0
- package/dist/src/plugins/typescript/features/UpdateImportsProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.d.ts +25 -0
- package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.js +176 -0
- package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.js.map +1 -0
- package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.d.ts +13 -0
- package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.js +58 -0
- package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.js.map +1 -0
- package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.d.ts +4 -0
- package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.js +57 -0
- package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.js.map +1 -0
- package/dist/src/plugins/typescript/features/utils.d.ts +81 -0
- package/dist/src/plugins/typescript/features/utils.js +331 -0
- package/dist/src/plugins/typescript/features/utils.js.map +1 -0
- package/dist/src/plugins/typescript/macroforgeAugmenter.d.ts +23 -0
- package/dist/src/plugins/typescript/macroforgeAugmenter.js +41 -0
- package/dist/src/plugins/typescript/macroforgeAugmenter.js.map +1 -0
- package/dist/src/plugins/typescript/module-loader.d.ts +28 -0
- package/dist/src/plugins/typescript/module-loader.js +254 -0
- package/dist/src/plugins/typescript/module-loader.js.map +1 -0
- package/dist/src/plugins/typescript/previewer.d.ts +7 -0
- package/dist/src/plugins/typescript/previewer.js +120 -0
- package/dist/src/plugins/typescript/previewer.js.map +1 -0
- package/dist/src/plugins/typescript/service.d.ts +105 -0
- package/dist/src/plugins/typescript/service.js +1073 -0
- package/dist/src/plugins/typescript/service.js.map +1 -0
- package/dist/src/plugins/typescript/serviceCache.d.ts +90 -0
- package/dist/src/plugins/typescript/serviceCache.js +50 -0
- package/dist/src/plugins/typescript/serviceCache.js.map +1 -0
- package/dist/src/plugins/typescript/svelte-ast-utils.d.ts +77 -0
- package/dist/src/plugins/typescript/svelte-ast-utils.js +100 -0
- package/dist/src/plugins/typescript/svelte-ast-utils.js.map +1 -0
- package/dist/src/plugins/typescript/svelte-sys.d.ts +9 -0
- package/dist/src/plugins/typescript/svelte-sys.js +79 -0
- package/dist/src/plugins/typescript/svelte-sys.js.map +1 -0
- package/dist/src/plugins/typescript/utils.d.ts +48 -0
- package/dist/src/plugins/typescript/utils.js +334 -0
- package/dist/src/plugins/typescript/utils.js.map +1 -0
- package/dist/src/server.d.ts +19 -0
- package/dist/src/server.js +434 -0
- package/dist/src/server.js.map +1 -0
- package/dist/src/svelte-check.d.ts +65 -0
- package/dist/src/svelte-check.js +288 -0
- package/dist/src/svelte-check.js.map +1 -0
- package/dist/src/utils.d.ts +111 -0
- package/dist/src/utils.js +337 -0
- package/dist/src/utils.js.map +1 -0
- package/dist/tsconfig.tsbuildinfo +1 -0
- package/package.json +79 -0
|
@@ -0,0 +1,1030 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.CodeActionsProviderImpl = exports.REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND = exports.ADD_MISSING_IMPORTS_CODE_ACTION_KIND = exports.SORT_IMPORT_CODE_ACTION_KIND = void 0;
|
|
37
|
+
const svelte2tsx_1 = require("svelte2tsx");
|
|
38
|
+
const typescript_1 = __importStar(require("typescript"));
|
|
39
|
+
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
40
|
+
const documents_1 = require("../../../lib/documents");
|
|
41
|
+
const utils_1 = require("../../../utils");
|
|
42
|
+
const DocumentSnapshot_1 = require("../DocumentSnapshot");
|
|
43
|
+
const utils_2 = require("../utils");
|
|
44
|
+
const DiagnosticsProvider_1 = require("./DiagnosticsProvider");
|
|
45
|
+
const utils_3 = require("./utils");
|
|
46
|
+
/**
|
|
47
|
+
* TODO change this to protocol constant if it's part of the protocol
|
|
48
|
+
*/
|
|
49
|
+
exports.SORT_IMPORT_CODE_ACTION_KIND = 'source.sortImports';
|
|
50
|
+
exports.ADD_MISSING_IMPORTS_CODE_ACTION_KIND = 'source.addMissingImports';
|
|
51
|
+
exports.REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND = 'source.removeUnusedImports';
|
|
52
|
+
const FIX_IMPORT_FIX_NAME = 'import';
|
|
53
|
+
const FIX_IMPORT_FIX_ID = 'fixMissingImport';
|
|
54
|
+
const FIX_IMPORT_FIX_DESCRIPTION = 'Add all missing imports';
|
|
55
|
+
const nonIdentifierRegex = /[\`\~\!\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>/\?\s]/;
|
|
56
|
+
class CodeActionsProviderImpl {
|
|
57
|
+
constructor(lsAndTsDocResolver, completionProvider, configManager) {
|
|
58
|
+
this.lsAndTsDocResolver = lsAndTsDocResolver;
|
|
59
|
+
this.completionProvider = completionProvider;
|
|
60
|
+
this.configManager = configManager;
|
|
61
|
+
}
|
|
62
|
+
async getCodeActions(document, range, context, cancellationToken) {
|
|
63
|
+
if (context.only?.[0] === vscode_languageserver_1.CodeActionKind.SourceOrganizeImports) {
|
|
64
|
+
return await this.organizeImports(document, cancellationToken);
|
|
65
|
+
}
|
|
66
|
+
if (context.only?.[0] === exports.SORT_IMPORT_CODE_ACTION_KIND) {
|
|
67
|
+
return await this.organizeImports(document, cancellationToken, typescript_1.OrganizeImportsMode.SortAndCombine);
|
|
68
|
+
}
|
|
69
|
+
if (context.only?.[0] === exports.REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND) {
|
|
70
|
+
return await this.organizeImports(document, cancellationToken, typescript_1.OrganizeImportsMode.RemoveUnused);
|
|
71
|
+
}
|
|
72
|
+
if (context.only?.[0] === exports.ADD_MISSING_IMPORTS_CODE_ACTION_KIND) {
|
|
73
|
+
return await this.addMissingImports(document, cancellationToken);
|
|
74
|
+
}
|
|
75
|
+
// for source action command (all source.xxx)
|
|
76
|
+
// vscode would show different source code action kinds to choose from
|
|
77
|
+
if (context.only?.[0] === vscode_languageserver_1.CodeActionKind.Source) {
|
|
78
|
+
return [
|
|
79
|
+
...(await this.organizeImports(document, cancellationToken)),
|
|
80
|
+
...(await this.organizeImports(document, cancellationToken, typescript_1.OrganizeImportsMode.SortAndCombine)),
|
|
81
|
+
...(await this.organizeImports(document, cancellationToken, typescript_1.OrganizeImportsMode.RemoveUnused)),
|
|
82
|
+
...(await this.addMissingImports(document, cancellationToken))
|
|
83
|
+
];
|
|
84
|
+
}
|
|
85
|
+
if (context.diagnostics.length &&
|
|
86
|
+
(!context.only || context.only.includes(vscode_languageserver_1.CodeActionKind.QuickFix))) {
|
|
87
|
+
return await this.applyQuickfix(document, range, context, cancellationToken);
|
|
88
|
+
}
|
|
89
|
+
if (!context.only || context.only.includes(vscode_languageserver_1.CodeActionKind.Refactor)) {
|
|
90
|
+
return await this.getApplicableRefactors(document, range, cancellationToken);
|
|
91
|
+
}
|
|
92
|
+
return [];
|
|
93
|
+
}
|
|
94
|
+
async resolveCodeAction(document, codeAction, cancellationToken) {
|
|
95
|
+
if (!this.isQuickFixAllResolveInfo(codeAction.data)) {
|
|
96
|
+
return codeAction;
|
|
97
|
+
}
|
|
98
|
+
const { lang, tsDoc, userPreferences, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document);
|
|
99
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
100
|
+
return codeAction;
|
|
101
|
+
}
|
|
102
|
+
const formatCodeSettings = await this.configManager.getFormatCodeSettingsForFile(document, tsDoc.scriptKind);
|
|
103
|
+
const formatCodeBasis = (0, utils_3.getFormatCodeBasis)(formatCodeSettings);
|
|
104
|
+
const getDiagnostics = (0, utils_1.memoize)(() => lang.getSemanticDiagnostics(tsDoc.filePath).map((dia) => ({
|
|
105
|
+
range: (0, documents_1.mapRangeToOriginal)(tsDoc, (0, utils_2.convertRange)(tsDoc, dia)),
|
|
106
|
+
message: '',
|
|
107
|
+
code: dia.code
|
|
108
|
+
})));
|
|
109
|
+
const isImportFix = codeAction.data.fixName === FIX_IMPORT_FIX_NAME;
|
|
110
|
+
const virtualDocInfo = isImportFix
|
|
111
|
+
? this.createVirtualDocumentForCombinedImportCodeFix(document, getDiagnostics(), tsDoc, lsContainer, lang)
|
|
112
|
+
: undefined;
|
|
113
|
+
const fix = lang.getCombinedCodeFix({
|
|
114
|
+
type: 'file',
|
|
115
|
+
fileName: (virtualDocInfo?.virtualDoc ?? document).getFilePath()
|
|
116
|
+
}, codeAction.data.fixId, formatCodeSettings, userPreferences);
|
|
117
|
+
if (virtualDocInfo) {
|
|
118
|
+
const getCanonicalFileName = (0, utils_1.createGetCanonicalFileName)(typescript_1.default.sys.useCaseSensitiveFileNames);
|
|
119
|
+
const virtualDocPath = getCanonicalFileName((0, utils_1.normalizePath)(virtualDocInfo.virtualDoc.getFilePath()));
|
|
120
|
+
for (const change of fix.changes) {
|
|
121
|
+
if (getCanonicalFileName((0, utils_1.normalizePath)(change.fileName)) === virtualDocPath) {
|
|
122
|
+
change.fileName = tsDoc.filePath;
|
|
123
|
+
this.removeDuplicatedComponentImport(virtualDocInfo.insertedNames, change);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
await this.lsAndTsDocResolver.deleteSnapshot(virtualDocPath);
|
|
127
|
+
}
|
|
128
|
+
const snapshots = new utils_3.SnapshotMap(this.lsAndTsDocResolver, lsContainer);
|
|
129
|
+
const fixActions = [
|
|
130
|
+
{
|
|
131
|
+
fixName: codeAction.data.fixName,
|
|
132
|
+
changes: Array.from(fix.changes),
|
|
133
|
+
description: ''
|
|
134
|
+
}
|
|
135
|
+
];
|
|
136
|
+
const documentChangesPromises = fixActions.map((fix) => this.convertAndFixCodeFixAction({
|
|
137
|
+
document,
|
|
138
|
+
fix,
|
|
139
|
+
formatCodeBasis,
|
|
140
|
+
formatCodeSettings,
|
|
141
|
+
getDiagnostics,
|
|
142
|
+
snapshots,
|
|
143
|
+
skipAddScriptTag: true
|
|
144
|
+
}));
|
|
145
|
+
const documentChanges = (await Promise.all(documentChangesPromises)).flat();
|
|
146
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
147
|
+
return codeAction;
|
|
148
|
+
}
|
|
149
|
+
if (isImportFix) {
|
|
150
|
+
this.fixCombinedImportQuickFix(documentChanges, document, formatCodeBasis);
|
|
151
|
+
}
|
|
152
|
+
codeAction.edit = {
|
|
153
|
+
documentChanges
|
|
154
|
+
};
|
|
155
|
+
return codeAction;
|
|
156
|
+
}
|
|
157
|
+
/**
|
|
158
|
+
* Do not use this in regular code action
|
|
159
|
+
* This'll cause TypeScript to rebuild and invalidate caches every time. It'll be slow
|
|
160
|
+
*/
|
|
161
|
+
createVirtualDocumentForCombinedImportCodeFix(document, diagnostics, tsDoc, lsContainer, lang) {
|
|
162
|
+
const virtualUri = document.uri + '.__virtual__.svelte';
|
|
163
|
+
const names = new Set();
|
|
164
|
+
const sourceFile = lang.getProgram()?.getSourceFile(tsDoc.filePath);
|
|
165
|
+
if (!sourceFile) {
|
|
166
|
+
return undefined;
|
|
167
|
+
}
|
|
168
|
+
for (const diagnostic of diagnostics) {
|
|
169
|
+
if (diagnostic.range.start.line < 0 ||
|
|
170
|
+
diagnostic.range.end.line < 0 ||
|
|
171
|
+
(diagnostic.code !== DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME &&
|
|
172
|
+
diagnostic.code !== DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y)) {
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
const identifier = this.findIdentifierForDiagnostic(tsDoc, diagnostic, sourceFile);
|
|
176
|
+
const name = identifier?.text;
|
|
177
|
+
if (!name || names.has(name)) {
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
if (name.startsWith('$')) {
|
|
181
|
+
names.add(name.slice(1));
|
|
182
|
+
}
|
|
183
|
+
else if (!(0, utils_2.isInScript)(diagnostic.range.start, document)) {
|
|
184
|
+
if (this.isComponentStartTag(identifier)) {
|
|
185
|
+
names.add((0, utils_2.toGeneratedSvelteComponentName)(name));
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
if (!names.size) {
|
|
190
|
+
return undefined;
|
|
191
|
+
}
|
|
192
|
+
const inserts = Array.from(names.values())
|
|
193
|
+
.map((name) => name + ';')
|
|
194
|
+
.join('');
|
|
195
|
+
// assumption: imports are always at the top of the script tag
|
|
196
|
+
// so these appends won't change the position of the edits
|
|
197
|
+
const text = document.getText();
|
|
198
|
+
const newText = document.scriptInfo
|
|
199
|
+
? text.slice(0, document.scriptInfo.end) + inserts + text.slice(document.scriptInfo.end)
|
|
200
|
+
: `${document.getText()}<script>${inserts}</script>`;
|
|
201
|
+
const virtualDoc = new documents_1.Document(virtualUri, newText);
|
|
202
|
+
virtualDoc.openedByClient = true;
|
|
203
|
+
// let typescript know about the virtual document
|
|
204
|
+
lsContainer.openVirtualDocument(virtualDoc);
|
|
205
|
+
lsContainer.getService();
|
|
206
|
+
return {
|
|
207
|
+
virtualDoc,
|
|
208
|
+
insertedNames: names
|
|
209
|
+
};
|
|
210
|
+
}
|
|
211
|
+
/**
|
|
212
|
+
* Remove component default import if there is a named import with the same name
|
|
213
|
+
* Usually happens with reexport or inheritance of component library
|
|
214
|
+
*/
|
|
215
|
+
removeDuplicatedComponentImport(insertedNames, change) {
|
|
216
|
+
for (const name of insertedNames) {
|
|
217
|
+
const unSuffixedNames = (0, utils_2.changeSvelteComponentName)(name);
|
|
218
|
+
const matchRegex = unSuffixedNames != name && this.toImportMemberRegex(unSuffixedNames);
|
|
219
|
+
if (!matchRegex ||
|
|
220
|
+
!change.textChanges.some((textChange) => textChange.newText.match(matchRegex))) {
|
|
221
|
+
continue;
|
|
222
|
+
}
|
|
223
|
+
const importRegex = new RegExp(`\\s+import ${name} from ('|")(.*)('|");?\r?\n?`);
|
|
224
|
+
change.textChanges = change.textChanges
|
|
225
|
+
.map((textChange) => ({
|
|
226
|
+
...textChange,
|
|
227
|
+
newText: textChange.newText.replace(importRegex, (match) => {
|
|
228
|
+
if (match.split('\n').length > 2) {
|
|
229
|
+
return '\n';
|
|
230
|
+
}
|
|
231
|
+
else {
|
|
232
|
+
return '';
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
}))
|
|
236
|
+
// in case there are replacements
|
|
237
|
+
.filter((change) => change.span.length || change.newText);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
fixCombinedImportQuickFix(documentChanges, document, formatCodeBasis) {
|
|
241
|
+
if (!documentChanges.length || document.scriptInfo || document.moduleScriptInfo) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
const editForThisFile = documentChanges.find((change) => change.textDocument.uri === document.uri);
|
|
245
|
+
if (editForThisFile?.edits.length) {
|
|
246
|
+
const [first] = editForThisFile.edits;
|
|
247
|
+
first.newText =
|
|
248
|
+
(0, utils_3.getNewScriptStartTag)(this.configManager.getConfig(), formatCodeBasis.newLine) +
|
|
249
|
+
formatCodeBasis.baseIndent +
|
|
250
|
+
first.newText.trimStart();
|
|
251
|
+
const last = editForThisFile.edits[editForThisFile.edits.length - 1];
|
|
252
|
+
last.newText = last.newText + '</script>' + formatCodeBasis.newLine;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
toImportMemberRegex(name) {
|
|
256
|
+
return new RegExp(`${name}($| |,)`);
|
|
257
|
+
}
|
|
258
|
+
isQuickFixAllResolveInfo(data) {
|
|
259
|
+
const asserted = data;
|
|
260
|
+
return asserted?.fixId != undefined && typeof asserted.fixName === 'string';
|
|
261
|
+
}
|
|
262
|
+
async organizeImports(document, cancellationToken, mode = typescript_1.OrganizeImportsMode.All) {
|
|
263
|
+
if (!document.scriptInfo && !document.moduleScriptInfo) {
|
|
264
|
+
return [];
|
|
265
|
+
}
|
|
266
|
+
const { lang, tsDoc, userPreferences } = await this.getLSAndTSDoc(document);
|
|
267
|
+
if (cancellationToken?.isCancellationRequested || tsDoc.parserError) {
|
|
268
|
+
// If there's a parser error, we fall back to only the script contents,
|
|
269
|
+
// so organize imports likely throws out a lot of seemingly unused imports
|
|
270
|
+
// because they are only used in the template. Therefore do nothing in this case.
|
|
271
|
+
return [];
|
|
272
|
+
}
|
|
273
|
+
const changes = lang.organizeImports({
|
|
274
|
+
fileName: tsDoc.filePath,
|
|
275
|
+
type: 'file',
|
|
276
|
+
mode
|
|
277
|
+
}, {
|
|
278
|
+
...(await this.configManager.getFormatCodeSettingsForFile(document, tsDoc.scriptKind)),
|
|
279
|
+
// handle it on our own
|
|
280
|
+
baseIndentSize: undefined
|
|
281
|
+
}, userPreferences);
|
|
282
|
+
const documentChanges = await Promise.all(changes.map(async (change) => {
|
|
283
|
+
// Organize Imports will only affect the current file, so no need to check the file path
|
|
284
|
+
return vscode_languageserver_1.TextDocumentEdit.create(vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create(document.url, null), change.textChanges
|
|
285
|
+
.map((edit) => {
|
|
286
|
+
const range = this.checkRemoveImportCodeActionRange(edit, tsDoc, (0, documents_1.mapRangeToOriginal)(tsDoc, (0, utils_2.convertRange)(tsDoc, edit.span)));
|
|
287
|
+
edit.newText = (0, utils_1.removeLineWithString)(edit.newText, 'SvelteComponentTyped as __SvelteComponentTyped__');
|
|
288
|
+
return this.fixIndentationOfImports(vscode_languageserver_1.TextEdit.replace(range, edit.newText), document);
|
|
289
|
+
})
|
|
290
|
+
.filter((edit) =>
|
|
291
|
+
// The __SvelteComponentTyped__ import is added by us and will have a negative mapped line
|
|
292
|
+
edit.range.start.line !== -1));
|
|
293
|
+
}));
|
|
294
|
+
for (const change of documentChanges) {
|
|
295
|
+
this.checkIndentLeftover(change, document);
|
|
296
|
+
}
|
|
297
|
+
let kind;
|
|
298
|
+
let title;
|
|
299
|
+
switch (mode) {
|
|
300
|
+
case typescript_1.OrganizeImportsMode.SortAndCombine:
|
|
301
|
+
kind = exports.SORT_IMPORT_CODE_ACTION_KIND;
|
|
302
|
+
title = 'Sort Imports';
|
|
303
|
+
break;
|
|
304
|
+
case typescript_1.OrganizeImportsMode.RemoveUnused:
|
|
305
|
+
kind = exports.REMOVE_UNUSED_IMPORTS_CODE_ACTION_KIND;
|
|
306
|
+
title = 'Remove Unused Imports';
|
|
307
|
+
break;
|
|
308
|
+
default:
|
|
309
|
+
kind = vscode_languageserver_1.CodeActionKind.SourceOrganizeImports;
|
|
310
|
+
title = 'Organize Imports';
|
|
311
|
+
}
|
|
312
|
+
return [vscode_languageserver_1.CodeAction.create(title, { documentChanges }, kind)];
|
|
313
|
+
}
|
|
314
|
+
fixIndentationOfImports(edit, document) {
|
|
315
|
+
// "Organize Imports" will have edits that delete a group of imports by return empty edits
|
|
316
|
+
// and one edit which contains all the organized imports of the group. Fix indentation
|
|
317
|
+
// of that one by prepending all lines with the indentation of the first line.
|
|
318
|
+
const { newText, range } = edit;
|
|
319
|
+
if (!newText || range.start.character === 0) {
|
|
320
|
+
return edit;
|
|
321
|
+
}
|
|
322
|
+
const line = (0, documents_1.getLineAtPosition)(range.start, document.getText());
|
|
323
|
+
const leadingChars = line.substring(0, range.start.character);
|
|
324
|
+
if (leadingChars.trim() !== '') {
|
|
325
|
+
return edit;
|
|
326
|
+
}
|
|
327
|
+
const fixedNewText = (0, utils_1.modifyLines)(edit.newText, (line, idx) => idx === 0 || !line ? line : leadingChars + line);
|
|
328
|
+
if (range.end.character > 0) {
|
|
329
|
+
const endLine = (0, documents_1.getLineAtPosition)(range.end, document.getText());
|
|
330
|
+
const isIndent = !endLine.substring(0, range.end.character).trim();
|
|
331
|
+
if (isIndent) {
|
|
332
|
+
const trimmedEndLine = endLine.trim();
|
|
333
|
+
// imports that would be removed by the next delete edit
|
|
334
|
+
if (trimmedEndLine && !trimmedEndLine.startsWith('import')) {
|
|
335
|
+
range.end.character = 0;
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
return vscode_languageserver_1.TextEdit.replace(range, fixedNewText);
|
|
340
|
+
}
|
|
341
|
+
checkRemoveImportCodeActionRange(edit, snapshot, range) {
|
|
342
|
+
if (!(snapshot instanceof DocumentSnapshot_1.SvelteDocumentSnapshot)) {
|
|
343
|
+
return range;
|
|
344
|
+
}
|
|
345
|
+
// Handle svelte2tsx wrong import mapping:
|
|
346
|
+
// The character after the last import maps to the start of the script
|
|
347
|
+
// TODO find a way to fix this in svelte2tsx and then remove this
|
|
348
|
+
if ((range.end.line === 0 && range.end.character === 1) ||
|
|
349
|
+
range.end.line < range.start.line ||
|
|
350
|
+
((0, utils_2.isInScript)(range.start, snapshot) && !(0, utils_2.isInScript)(range.end, snapshot))) {
|
|
351
|
+
edit.span.length -= 1;
|
|
352
|
+
range = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, edit.span));
|
|
353
|
+
const line = (0, documents_1.getLineAtPosition)(range.end, snapshot.getOriginalText());
|
|
354
|
+
// remove-import code action will removes the
|
|
355
|
+
// line break generated by svelte2tsx,
|
|
356
|
+
// but when there's no line break in the source
|
|
357
|
+
// move back to next character would remove the next character
|
|
358
|
+
if ([';', '"', "'"].includes(line[range.end.character])) {
|
|
359
|
+
range.end.character += 1;
|
|
360
|
+
}
|
|
361
|
+
if ((0, documents_1.isAtEndOfLine)(line, range.end.character)) {
|
|
362
|
+
range.end.line += 1;
|
|
363
|
+
range.end.character = 0;
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
return range;
|
|
367
|
+
}
|
|
368
|
+
checkIndentLeftover(change, document) {
|
|
369
|
+
if (!change.edits.length) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const orderedByStart = change.edits.sort((a, b) => {
|
|
373
|
+
if (a.range.start.line !== b.range.start.line) {
|
|
374
|
+
return a.range.start.line - b.range.start.line;
|
|
375
|
+
}
|
|
376
|
+
return a.range.start.character - b.range.start.character;
|
|
377
|
+
});
|
|
378
|
+
let current;
|
|
379
|
+
let groups = [];
|
|
380
|
+
for (let i = 0; i < orderedByStart.length; i++) {
|
|
381
|
+
const edit = orderedByStart[i];
|
|
382
|
+
if (!current) {
|
|
383
|
+
current = { range: (0, utils_2.cloneRange)(edit.range), newText: edit.newText };
|
|
384
|
+
continue;
|
|
385
|
+
}
|
|
386
|
+
if ((0, utils_1.isPositionEqual)(current.range.end, edit.range.start)) {
|
|
387
|
+
current.range.end = edit.range.end;
|
|
388
|
+
current.newText += edit.newText;
|
|
389
|
+
}
|
|
390
|
+
else {
|
|
391
|
+
groups.push(current);
|
|
392
|
+
current = { range: (0, utils_2.cloneRange)(edit.range), newText: edit.newText };
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
if (current) {
|
|
396
|
+
groups.push(current);
|
|
397
|
+
}
|
|
398
|
+
for (const edit of groups) {
|
|
399
|
+
if (edit.newText) {
|
|
400
|
+
continue;
|
|
401
|
+
}
|
|
402
|
+
const range = edit.range;
|
|
403
|
+
const lineContentBeforeRemove = document.getText({
|
|
404
|
+
start: { line: range.start.line, character: 0 },
|
|
405
|
+
end: range.start
|
|
406
|
+
});
|
|
407
|
+
const onlyIndentLeft = !lineContentBeforeRemove.trim();
|
|
408
|
+
if (!onlyIndentLeft) {
|
|
409
|
+
continue;
|
|
410
|
+
}
|
|
411
|
+
const lineContentAfterRemove = document.getText({
|
|
412
|
+
start: range.end,
|
|
413
|
+
end: { line: range.end.line, character: Number.MAX_VALUE }
|
|
414
|
+
});
|
|
415
|
+
const emptyAfterRemove = !lineContentAfterRemove.trim() || lineContentAfterRemove.startsWith('</script>');
|
|
416
|
+
if (emptyAfterRemove) {
|
|
417
|
+
change.edits.push({
|
|
418
|
+
range: { start: { line: range.start.line, character: 0 }, end: range.start },
|
|
419
|
+
newText: ''
|
|
420
|
+
});
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
async applyQuickfix(document, range, context, cancellationToken) {
|
|
425
|
+
const { lang, tsDoc, userPreferences, lsContainer } = await this.getLSAndTSDoc(document);
|
|
426
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
427
|
+
return [];
|
|
428
|
+
}
|
|
429
|
+
const start = tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.start));
|
|
430
|
+
const end = tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.end));
|
|
431
|
+
const errorCodes = context.diagnostics.map((diag) => Number(diag.code));
|
|
432
|
+
const cannotFindNameDiagnostic = context.diagnostics.filter((diagnostic) => diagnostic.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME ||
|
|
433
|
+
diagnostic.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y);
|
|
434
|
+
const formatCodeSettings = await this.configManager.getFormatCodeSettingsForFile(document, tsDoc.scriptKind);
|
|
435
|
+
const formatCodeBasis = (0, utils_3.getFormatCodeBasis)(formatCodeSettings);
|
|
436
|
+
let codeFixes = cannotFindNameDiagnostic.length
|
|
437
|
+
? this.getComponentImportQuickFix(document, lang, tsDoc, userPreferences, cannotFindNameDiagnostic, formatCodeSettings)
|
|
438
|
+
: undefined;
|
|
439
|
+
// either-or situation when it's not a "did you mean" fix
|
|
440
|
+
if (codeFixes === undefined ||
|
|
441
|
+
errorCodes.includes(DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y)) {
|
|
442
|
+
codeFixes ??= [];
|
|
443
|
+
codeFixes = codeFixes.concat(...lang.getCodeFixesAtPosition(tsDoc.filePath, start, end, errorCodes, formatCodeSettings, userPreferences), ...this.getSvelteQuickFixes(lang, cannotFindNameDiagnostic, tsDoc, userPreferences, formatCodeSettings));
|
|
444
|
+
}
|
|
445
|
+
const snapshots = new utils_3.SnapshotMap(this.lsAndTsDocResolver, lsContainer);
|
|
446
|
+
snapshots.set(tsDoc.filePath, tsDoc);
|
|
447
|
+
const codeActionsPromises = codeFixes.map(async (fix) => {
|
|
448
|
+
const documentChanges = await this.convertAndFixCodeFixAction({
|
|
449
|
+
fix,
|
|
450
|
+
snapshots,
|
|
451
|
+
document,
|
|
452
|
+
formatCodeSettings,
|
|
453
|
+
formatCodeBasis,
|
|
454
|
+
getDiagnostics: () => context.diagnostics
|
|
455
|
+
});
|
|
456
|
+
const codeAction = vscode_languageserver_1.CodeAction.create(fix.description, {
|
|
457
|
+
documentChanges
|
|
458
|
+
}, vscode_languageserver_1.CodeActionKind.QuickFix);
|
|
459
|
+
return {
|
|
460
|
+
fix,
|
|
461
|
+
codeAction
|
|
462
|
+
};
|
|
463
|
+
});
|
|
464
|
+
const identifier = {
|
|
465
|
+
uri: document.uri
|
|
466
|
+
};
|
|
467
|
+
const codeActions = await Promise.all(codeActionsPromises);
|
|
468
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
469
|
+
return [];
|
|
470
|
+
}
|
|
471
|
+
const codeActionsNotFilteredOut = codeActions.filter(({ codeAction }) => codeAction.edit?.documentChanges?.every((change) => change.edits.length > 0));
|
|
472
|
+
const fixAllActions = this.getFixAllActions(codeActionsNotFilteredOut.map(({ fix }) => fix), identifier, tsDoc.filePath, lang);
|
|
473
|
+
const addLangCodeAction = this.getAddLangTSCodeAction(document, context, tsDoc, formatCodeBasis);
|
|
474
|
+
// filter out empty code action
|
|
475
|
+
const result = codeActionsNotFilteredOut
|
|
476
|
+
.map(({ codeAction }) => codeAction)
|
|
477
|
+
.concat(fixAllActions);
|
|
478
|
+
return addLangCodeAction ? [addLangCodeAction].concat(result) : result;
|
|
479
|
+
}
|
|
480
|
+
async convertAndFixCodeFixAction({ fix, snapshots, document, formatCodeSettings, formatCodeBasis, getDiagnostics, skipAddScriptTag }) {
|
|
481
|
+
const documentChangesPromises = fix.changes.map(async (change) => {
|
|
482
|
+
const snapshot = await snapshots.retrieve(change.fileName);
|
|
483
|
+
return vscode_languageserver_1.TextDocumentEdit.create(vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create((0, utils_1.pathToUrl)(change.fileName), null), change.textChanges
|
|
484
|
+
.map((edit) => {
|
|
485
|
+
if (fix.fixName === FIX_IMPORT_FIX_NAME &&
|
|
486
|
+
snapshot instanceof DocumentSnapshot_1.SvelteDocumentSnapshot) {
|
|
487
|
+
const namePosition = 'position' in fix ? fix.position : undefined;
|
|
488
|
+
const startPos = namePosition ??
|
|
489
|
+
this.findDiagnosticForImportFix(document, edit, getDiagnostics())
|
|
490
|
+
?.range?.start ??
|
|
491
|
+
vscode_languageserver_1.Position.create(0, 0);
|
|
492
|
+
return this.completionProvider.codeActionChangeToTextEdit(document, snapshot, edit, true, startPos, formatCodeBasis.newLine, undefined, skipAddScriptTag);
|
|
493
|
+
}
|
|
494
|
+
if ((0, utils_3.isTextSpanInGeneratedCode)(snapshot.getFullText(), edit.span)) {
|
|
495
|
+
return undefined;
|
|
496
|
+
}
|
|
497
|
+
let originalRange = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, edit.span));
|
|
498
|
+
if (fix.fixName === 'unusedIdentifier') {
|
|
499
|
+
originalRange = this.checkRemoveImportCodeActionRange(edit, snapshot, originalRange);
|
|
500
|
+
}
|
|
501
|
+
if (fix.fixName === 'fixAwaitInSyncFunction' && document.scriptInfo) {
|
|
502
|
+
const scriptStartTagStart = document.scriptInfo.container.start;
|
|
503
|
+
const scriptStartTagEnd = document.scriptInfo.start;
|
|
504
|
+
const withinStartTag = document.offsetAt(originalRange.start) < scriptStartTagEnd &&
|
|
505
|
+
document.offsetAt(originalRange.end) > scriptStartTagStart;
|
|
506
|
+
if (withinStartTag) {
|
|
507
|
+
return undefined;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
if (fix.fixName === 'fixMissingFunctionDeclaration') {
|
|
511
|
+
const position = 'position' in fix ? fix.position : undefined;
|
|
512
|
+
const checkRange = position
|
|
513
|
+
? vscode_languageserver_1.Range.create(position, position)
|
|
514
|
+
: this.findDiagnosticForQuickFix(document, DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME, getDiagnostics(), (possiblyIdentifier) => {
|
|
515
|
+
return edit.newText.includes('function ' + possiblyIdentifier + '(');
|
|
516
|
+
})?.range;
|
|
517
|
+
originalRange = this.checkEndOfFileCodeInsert(originalRange, checkRange, document);
|
|
518
|
+
// ts doesn't add base indent to the first line
|
|
519
|
+
if (formatCodeSettings.baseIndentSize) {
|
|
520
|
+
const emptyLine = formatCodeBasis.newLine.repeat(2);
|
|
521
|
+
edit.newText =
|
|
522
|
+
emptyLine +
|
|
523
|
+
formatCodeBasis.baseIndent +
|
|
524
|
+
edit.newText.trimLeft();
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
if (fix.fixName === 'disableJsDiagnostics') {
|
|
528
|
+
if (edit.newText.includes('ts-nocheck')) {
|
|
529
|
+
return this.checkTsNoCheckCodeInsert(document, edit);
|
|
530
|
+
}
|
|
531
|
+
return this.checkDisableJsDiagnosticsCodeInsert(originalRange, document, edit);
|
|
532
|
+
}
|
|
533
|
+
if (fix.fixName === 'inferFromUsage') {
|
|
534
|
+
originalRange = this.checkAddJsDocCodeActionRange(snapshot, originalRange, document);
|
|
535
|
+
}
|
|
536
|
+
if (fix.fixName === 'fixConvertConstToLet') {
|
|
537
|
+
const offset = document.offsetAt(originalRange.start);
|
|
538
|
+
const constOffset = document.getText().indexOf('const', offset);
|
|
539
|
+
if (constOffset < 0) {
|
|
540
|
+
return undefined;
|
|
541
|
+
}
|
|
542
|
+
const beforeConst = document.getText().slice(0, constOffset);
|
|
543
|
+
if (beforeConst[beforeConst.length - 1] === '@' &&
|
|
544
|
+
beforeConst
|
|
545
|
+
.slice(0, beforeConst.length - 1)
|
|
546
|
+
.trimEnd()
|
|
547
|
+
.endsWith('{')) {
|
|
548
|
+
return undefined;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
if (originalRange.start.line < 0 || originalRange.end.line < 0) {
|
|
552
|
+
return undefined;
|
|
553
|
+
}
|
|
554
|
+
return vscode_languageserver_1.TextEdit.replace(originalRange, edit.newText);
|
|
555
|
+
})
|
|
556
|
+
.filter(utils_1.isNotNullOrUndefined));
|
|
557
|
+
});
|
|
558
|
+
const documentChanges = await Promise.all(documentChangesPromises);
|
|
559
|
+
return documentChanges;
|
|
560
|
+
}
|
|
561
|
+
findDiagnosticForImportFix(document, edit, diagnostics) {
|
|
562
|
+
return this.findDiagnosticForQuickFix(document, DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME, diagnostics, (possibleIdentifier) => !nonIdentifierRegex.test(possibleIdentifier) &&
|
|
563
|
+
this.toImportMemberRegex(possibleIdentifier).test(edit.newText));
|
|
564
|
+
}
|
|
565
|
+
findDiagnosticForQuickFix(document, targetCode, diagnostics, match) {
|
|
566
|
+
const diagnostic = diagnostics.find((diagnostic) => {
|
|
567
|
+
if (diagnostic.code !== targetCode) {
|
|
568
|
+
return false;
|
|
569
|
+
}
|
|
570
|
+
const possibleIdentifier = document.getText(diagnostic.range);
|
|
571
|
+
if (possibleIdentifier) {
|
|
572
|
+
return match(possibleIdentifier);
|
|
573
|
+
}
|
|
574
|
+
return false;
|
|
575
|
+
});
|
|
576
|
+
return diagnostic;
|
|
577
|
+
}
|
|
578
|
+
getFixAllActions(codeFixes, identifier, fileName, lang) {
|
|
579
|
+
const checkedFixIds = new Set();
|
|
580
|
+
const fixAll = [];
|
|
581
|
+
for (const codeFix of codeFixes) {
|
|
582
|
+
if (!codeFix.fixId || !codeFix.fixAllDescription || checkedFixIds.has(codeFix.fixId)) {
|
|
583
|
+
continue;
|
|
584
|
+
}
|
|
585
|
+
// we have custom fix for import
|
|
586
|
+
// check it again if fix-all might be necessary
|
|
587
|
+
if (codeFix.fixName === FIX_IMPORT_FIX_NAME) {
|
|
588
|
+
const allCannotFindNameDiagnostics = lang
|
|
589
|
+
.getSemanticDiagnostics(fileName)
|
|
590
|
+
.filter((diagnostic) => diagnostic.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME ||
|
|
591
|
+
diagnostic.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y);
|
|
592
|
+
if (allCannotFindNameDiagnostics.length < 2) {
|
|
593
|
+
checkedFixIds.add(codeFix.fixId);
|
|
594
|
+
continue;
|
|
595
|
+
}
|
|
596
|
+
}
|
|
597
|
+
const codeAction = vscode_languageserver_1.CodeAction.create(codeFix.fixAllDescription, vscode_languageserver_1.CodeActionKind.QuickFix);
|
|
598
|
+
const data = {
|
|
599
|
+
...identifier,
|
|
600
|
+
fixName: codeFix.fixName,
|
|
601
|
+
fixId: codeFix.fixId
|
|
602
|
+
};
|
|
603
|
+
codeAction.data = data;
|
|
604
|
+
checkedFixIds.add(codeFix.fixId);
|
|
605
|
+
fixAll.push(codeAction);
|
|
606
|
+
}
|
|
607
|
+
return fixAll;
|
|
608
|
+
}
|
|
609
|
+
/**
|
|
610
|
+
* import quick fix requires the symbol name to be the same as where it's defined.
|
|
611
|
+
* But we have suffix on component default export to prevent conflict with
|
|
612
|
+
* a local variable. So we use auto-import completion as a workaround here.
|
|
613
|
+
*/
|
|
614
|
+
getComponentImportQuickFix(document, lang, tsDoc, userPreferences, diagnostics, formatCodeSetting) {
|
|
615
|
+
const sourceFile = lang.getProgram()?.getSourceFile(tsDoc.filePath);
|
|
616
|
+
if (!sourceFile) {
|
|
617
|
+
return;
|
|
618
|
+
}
|
|
619
|
+
const nameToPosition = new Map();
|
|
620
|
+
for (const diagnostic of diagnostics) {
|
|
621
|
+
if ((0, utils_2.isInScript)(diagnostic.range.start, document)) {
|
|
622
|
+
continue;
|
|
623
|
+
}
|
|
624
|
+
const possibleIdentifier = document.getText(diagnostic.range);
|
|
625
|
+
if (!possibleIdentifier ||
|
|
626
|
+
!(0, utils_1.possiblyComponent)(possibleIdentifier) ||
|
|
627
|
+
nameToPosition.has(possibleIdentifier)) {
|
|
628
|
+
continue;
|
|
629
|
+
}
|
|
630
|
+
const node = this.findIdentifierForDiagnostic(tsDoc, diagnostic, sourceFile);
|
|
631
|
+
if (!node || !this.isComponentStartTag(node)) {
|
|
632
|
+
return;
|
|
633
|
+
}
|
|
634
|
+
const tagNameEnd = node.getEnd();
|
|
635
|
+
const name = node.getText();
|
|
636
|
+
if ((0, utils_1.possiblyComponent)(name)) {
|
|
637
|
+
nameToPosition.set(name, tagNameEnd);
|
|
638
|
+
}
|
|
639
|
+
}
|
|
640
|
+
if (!nameToPosition.size) {
|
|
641
|
+
return;
|
|
642
|
+
}
|
|
643
|
+
const result = [];
|
|
644
|
+
for (const [name, position] of nameToPosition) {
|
|
645
|
+
const errorPreventingUserPreferences = this.completionProvider.fixUserPreferencesForSvelteComponentImport(userPreferences);
|
|
646
|
+
const resolvedCompletion = (c) => lang.getCompletionEntryDetails(tsDoc.filePath, position, c.name, formatCodeSetting, c.source, errorPreventingUserPreferences, c.data);
|
|
647
|
+
const toFix = (c) => c.codeActions?.map((a) => ({
|
|
648
|
+
...a,
|
|
649
|
+
description: (0, utils_2.changeSvelteComponentName)(a.description),
|
|
650
|
+
fixName: FIX_IMPORT_FIX_NAME,
|
|
651
|
+
fixId: FIX_IMPORT_FIX_ID,
|
|
652
|
+
fixAllDescription: FIX_IMPORT_FIX_DESCRIPTION,
|
|
653
|
+
position: originalPosition
|
|
654
|
+
})) ?? [];
|
|
655
|
+
const completion = lang.getCompletionsAtPosition(tsDoc.filePath, position, userPreferences, formatCodeSetting);
|
|
656
|
+
const entries = completion?.entries
|
|
657
|
+
.filter((c) => c.name === name || c.name === (0, utils_2.toGeneratedSvelteComponentName)(name))
|
|
658
|
+
.map(resolvedCompletion)
|
|
659
|
+
.sort((a, b) => this.numberOfDirectorySeparators(typescript_1.default.displayPartsToString(a?.sourceDisplay ?? [])) -
|
|
660
|
+
this.numberOfDirectorySeparators(typescript_1.default.displayPartsToString(b?.sourceDisplay ?? [])))
|
|
661
|
+
.filter(utils_1.isNotNullOrUndefined);
|
|
662
|
+
if (!entries?.length) {
|
|
663
|
+
continue;
|
|
664
|
+
}
|
|
665
|
+
const originalPosition = tsDoc.getOriginalPosition(tsDoc.positionAt(position));
|
|
666
|
+
const resultForName = entries.flatMap(toFix);
|
|
667
|
+
result.push(...resultForName);
|
|
668
|
+
}
|
|
669
|
+
return result;
|
|
670
|
+
}
|
|
671
|
+
isComponentStartTag(node) {
|
|
672
|
+
return (typescript_1.default.isCallExpression(node.parent) &&
|
|
673
|
+
typescript_1.default.isIdentifier(node.parent.expression) &&
|
|
674
|
+
node.parent.expression.text === '__sveltets_2_ensureComponent' &&
|
|
675
|
+
typescript_1.default.isIdentifier(node));
|
|
676
|
+
}
|
|
677
|
+
numberOfDirectorySeparators(path) {
|
|
678
|
+
return path.split('/').length - 1;
|
|
679
|
+
}
|
|
680
|
+
getSvelteQuickFixes(lang, cannotFindNameDiagnostics, tsDoc, userPreferences, formatCodeSettings) {
|
|
681
|
+
const program = lang.getProgram();
|
|
682
|
+
const sourceFile = program?.getSourceFile(tsDoc.filePath);
|
|
683
|
+
if (!program || !sourceFile) {
|
|
684
|
+
return [];
|
|
685
|
+
}
|
|
686
|
+
const results = [];
|
|
687
|
+
const getGlobalCompletion = (0, utils_1.memoize)(() => lang.getCompletionsAtPosition(tsDoc.filePath, 0, userPreferences, formatCodeSettings));
|
|
688
|
+
for (const diagnostic of cannotFindNameDiagnostics) {
|
|
689
|
+
const identifier = this.findIdentifierForDiagnostic(tsDoc, diagnostic, sourceFile);
|
|
690
|
+
if (!identifier) {
|
|
691
|
+
continue;
|
|
692
|
+
}
|
|
693
|
+
const isQuickFixTargetTargetStore = identifier?.escapedText.toString().startsWith('$');
|
|
694
|
+
const fixes = [];
|
|
695
|
+
if (isQuickFixTargetTargetStore) {
|
|
696
|
+
fixes.push(...this.getSvelteStoreQuickFixes(identifier, lang, tsDoc, userPreferences, formatCodeSettings, getGlobalCompletion));
|
|
697
|
+
}
|
|
698
|
+
if (!fixes.length) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const originalPosition = tsDoc.getOriginalPosition(tsDoc.positionAt(identifier.pos));
|
|
702
|
+
results.push(...fixes.map((fix) => ({
|
|
703
|
+
name: identifier.getText(),
|
|
704
|
+
position: originalPosition,
|
|
705
|
+
...fix
|
|
706
|
+
})));
|
|
707
|
+
}
|
|
708
|
+
return results;
|
|
709
|
+
}
|
|
710
|
+
findIdentifierForDiagnostic(tsDoc, diagnostic, sourceFile) {
|
|
711
|
+
const start = tsDoc.offsetAt(tsDoc.getGeneratedPosition(diagnostic.range.start));
|
|
712
|
+
const end = tsDoc.offsetAt(tsDoc.getGeneratedPosition(diagnostic.range.end));
|
|
713
|
+
const identifier = (0, utils_3.findClosestContainingNode)(sourceFile, { start, length: end - start }, typescript_1.default.isIdentifier);
|
|
714
|
+
return identifier;
|
|
715
|
+
}
|
|
716
|
+
getSvelteStoreQuickFixes(identifier, lang, tsDoc, userPreferences, formatCodeSettings, getCompletions) {
|
|
717
|
+
const storeIdentifier = identifier.escapedText.toString().substring(1);
|
|
718
|
+
const completion = getCompletions();
|
|
719
|
+
if (!completion) {
|
|
720
|
+
return [];
|
|
721
|
+
}
|
|
722
|
+
const toFix = (c) => lang
|
|
723
|
+
.getCompletionEntryDetails(tsDoc.filePath, 0, c.name, formatCodeSettings, c.source, userPreferences, c.data)
|
|
724
|
+
?.codeActions?.map((a) => ({
|
|
725
|
+
...a,
|
|
726
|
+
changes: a.changes.map((change) => {
|
|
727
|
+
return {
|
|
728
|
+
...change,
|
|
729
|
+
textChanges: change.textChanges.map((textChange) => {
|
|
730
|
+
// For some reason, TS sometimes adds the `type` modifier. Remove it.
|
|
731
|
+
return {
|
|
732
|
+
...textChange,
|
|
733
|
+
newText: textChange.newText.replace(' type ', ' ')
|
|
734
|
+
};
|
|
735
|
+
})
|
|
736
|
+
};
|
|
737
|
+
}),
|
|
738
|
+
fixName: FIX_IMPORT_FIX_NAME,
|
|
739
|
+
fixId: FIX_IMPORT_FIX_ID,
|
|
740
|
+
fixAllDescription: FIX_IMPORT_FIX_DESCRIPTION
|
|
741
|
+
})) ?? [];
|
|
742
|
+
return (0, utils_1.flatten)(completion.entries.filter((c) => c.name === storeIdentifier).map(toFix));
|
|
743
|
+
}
|
|
744
|
+
getAddLangTSCodeAction(document, context, tsDoc, formatCodeBasis) {
|
|
745
|
+
if (tsDoc.scriptKind !== typescript_1.default.ScriptKind.JS) {
|
|
746
|
+
return;
|
|
747
|
+
}
|
|
748
|
+
let hasTSOnlyDiagnostic = false;
|
|
749
|
+
for (const diagnostic of context.diagnostics) {
|
|
750
|
+
const num = Number(diagnostic.code);
|
|
751
|
+
const canOnlyBeUsedInTS = num >= 8004 && num <= 8017;
|
|
752
|
+
if (canOnlyBeUsedInTS) {
|
|
753
|
+
hasTSOnlyDiagnostic = true;
|
|
754
|
+
break;
|
|
755
|
+
}
|
|
756
|
+
}
|
|
757
|
+
if (!hasTSOnlyDiagnostic) {
|
|
758
|
+
return;
|
|
759
|
+
}
|
|
760
|
+
if (!document.scriptInfo && !document.moduleScriptInfo) {
|
|
761
|
+
const hasNonTopLevelLang = document.html.roots.some((node) => this.hasLangTsScriptTag(node));
|
|
762
|
+
// Might be because issue with parsing the script tag, so don't suggest adding a new one
|
|
763
|
+
if (hasNonTopLevelLang) {
|
|
764
|
+
return;
|
|
765
|
+
}
|
|
766
|
+
return vscode_languageserver_1.CodeAction.create('Add <script lang="ts"> tag', {
|
|
767
|
+
documentChanges: [
|
|
768
|
+
{
|
|
769
|
+
textDocument: vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create(document.uri, null),
|
|
770
|
+
edits: [
|
|
771
|
+
{
|
|
772
|
+
range: vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(0, 0), vscode_languageserver_1.Position.create(0, 0)),
|
|
773
|
+
newText: '<script lang="ts"></script>' + formatCodeBasis.newLine
|
|
774
|
+
}
|
|
775
|
+
]
|
|
776
|
+
}
|
|
777
|
+
]
|
|
778
|
+
}, vscode_languageserver_1.CodeActionKind.QuickFix);
|
|
779
|
+
}
|
|
780
|
+
const edits = [document.scriptInfo, document.moduleScriptInfo]
|
|
781
|
+
.map((info) => {
|
|
782
|
+
if (!info) {
|
|
783
|
+
return;
|
|
784
|
+
}
|
|
785
|
+
const startTagNameEnd = document.positionAt(info.container.start + 7); // <script
|
|
786
|
+
const existingLangOffset = document
|
|
787
|
+
.getText({
|
|
788
|
+
start: startTagNameEnd,
|
|
789
|
+
end: document.positionAt(info.start)
|
|
790
|
+
})
|
|
791
|
+
.indexOf('lang=');
|
|
792
|
+
if (existingLangOffset !== -1) {
|
|
793
|
+
return;
|
|
794
|
+
}
|
|
795
|
+
return {
|
|
796
|
+
range: vscode_languageserver_1.Range.create(startTagNameEnd, startTagNameEnd),
|
|
797
|
+
newText: ' lang="ts"'
|
|
798
|
+
};
|
|
799
|
+
})
|
|
800
|
+
.filter(utils_1.isNotNullOrUndefined);
|
|
801
|
+
if (edits.length) {
|
|
802
|
+
return vscode_languageserver_1.CodeAction.create('Add lang="ts" to <script> tag', {
|
|
803
|
+
documentChanges: [
|
|
804
|
+
{
|
|
805
|
+
textDocument: vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create(document.uri, null),
|
|
806
|
+
edits
|
|
807
|
+
}
|
|
808
|
+
]
|
|
809
|
+
}, vscode_languageserver_1.CodeActionKind.QuickFix);
|
|
810
|
+
}
|
|
811
|
+
}
|
|
812
|
+
hasLangTsScriptTag(node) {
|
|
813
|
+
if (node.tag === 'script' &&
|
|
814
|
+
(node.attributes?.lang === '"ts"' || node.attributes?.lang === "'ts'") &&
|
|
815
|
+
node.parent) {
|
|
816
|
+
return true;
|
|
817
|
+
}
|
|
818
|
+
for (const element of node.children) {
|
|
819
|
+
if (this.hasLangTsScriptTag(element)) {
|
|
820
|
+
return true;
|
|
821
|
+
}
|
|
822
|
+
}
|
|
823
|
+
return false;
|
|
824
|
+
}
|
|
825
|
+
async getApplicableRefactors(document, range, cancellationToken) {
|
|
826
|
+
if (!(0, documents_1.isRangeInTag)(range, document.scriptInfo) &&
|
|
827
|
+
!(0, documents_1.isRangeInTag)(range, document.moduleScriptInfo)) {
|
|
828
|
+
return [];
|
|
829
|
+
}
|
|
830
|
+
// Don't allow refactorings when there is likely a store subscription.
|
|
831
|
+
// Reason: Extracting that would lead to svelte2tsx' transformed store representation
|
|
832
|
+
// showing up, which will confuse the user. In the long run, we maybe have to
|
|
833
|
+
// setup a separate ts language service which only knows of the original script.
|
|
834
|
+
const textInRange = document
|
|
835
|
+
.getText()
|
|
836
|
+
.substring(document.offsetAt(range.start), document.offsetAt(range.end));
|
|
837
|
+
if (textInRange.includes('$')) {
|
|
838
|
+
return [];
|
|
839
|
+
}
|
|
840
|
+
const { lang, tsDoc, userPreferences } = await this.getLSAndTSDoc(document);
|
|
841
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
842
|
+
return [];
|
|
843
|
+
}
|
|
844
|
+
const textRange = {
|
|
845
|
+
pos: tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.start)),
|
|
846
|
+
end: tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.end))
|
|
847
|
+
};
|
|
848
|
+
const applicableRefactors = lang.getApplicableRefactors(document.getFilePath() || '', textRange, userPreferences);
|
|
849
|
+
return (this.applicableRefactorsToCodeActions(applicableRefactors, document, range, textRange)
|
|
850
|
+
// Only allow refactorings from which we know they work
|
|
851
|
+
.filter((refactor) => refactor.command?.command.includes('function_scope') ||
|
|
852
|
+
refactor.command?.command.includes('constant_scope') ||
|
|
853
|
+
refactor.command?.command === 'Infer function return type')
|
|
854
|
+
// The language server also proposes extraction into const/function in module scope,
|
|
855
|
+
// which is outside of the render function, which is svelte2tsx-specific and unmapped,
|
|
856
|
+
// so it would both not work and confuse the user ("What is this render? Never declared that").
|
|
857
|
+
// So filter out the module scope proposal and rename the render-title
|
|
858
|
+
.filter((refactor) => !refactor.title.includes('module scope'))
|
|
859
|
+
.map((refactor) => ({
|
|
860
|
+
...refactor,
|
|
861
|
+
title: refactor.title
|
|
862
|
+
.replace(`Extract to inner function in function '${svelte2tsx_1.internalHelpers.renderName}'`, 'Extract to function')
|
|
863
|
+
.replace(`Extract to constant in function '${svelte2tsx_1.internalHelpers.renderName}'`, 'Extract to constant')
|
|
864
|
+
})));
|
|
865
|
+
}
|
|
866
|
+
applicableRefactorsToCodeActions(applicableRefactors, document, originalRange, textRange) {
|
|
867
|
+
return (0, utils_1.flatten)(applicableRefactors.map((applicableRefactor) => {
|
|
868
|
+
if (applicableRefactor.inlineable === false) {
|
|
869
|
+
return [
|
|
870
|
+
vscode_languageserver_1.CodeAction.create(applicableRefactor.description, {
|
|
871
|
+
title: applicableRefactor.description,
|
|
872
|
+
command: applicableRefactor.name,
|
|
873
|
+
arguments: [
|
|
874
|
+
document.uri,
|
|
875
|
+
{
|
|
876
|
+
type: 'refactor',
|
|
877
|
+
textRange,
|
|
878
|
+
originalRange,
|
|
879
|
+
refactorName: 'Extract Symbol'
|
|
880
|
+
}
|
|
881
|
+
]
|
|
882
|
+
})
|
|
883
|
+
];
|
|
884
|
+
}
|
|
885
|
+
return applicableRefactor.actions.map((action) => {
|
|
886
|
+
return vscode_languageserver_1.CodeAction.create(action.description, {
|
|
887
|
+
title: action.description,
|
|
888
|
+
command: action.name,
|
|
889
|
+
arguments: [
|
|
890
|
+
document.uri,
|
|
891
|
+
{
|
|
892
|
+
type: 'refactor',
|
|
893
|
+
textRange,
|
|
894
|
+
originalRange,
|
|
895
|
+
refactorName: applicableRefactor.name
|
|
896
|
+
}
|
|
897
|
+
]
|
|
898
|
+
});
|
|
899
|
+
});
|
|
900
|
+
}));
|
|
901
|
+
}
|
|
902
|
+
async executeCommand(document, command, args) {
|
|
903
|
+
if (!(args?.[1]?.type === 'refactor')) {
|
|
904
|
+
return null;
|
|
905
|
+
}
|
|
906
|
+
const { lang, tsDoc, userPreferences } = await this.getLSAndTSDoc(document);
|
|
907
|
+
const path = document.getFilePath() || '';
|
|
908
|
+
const { refactorName, originalRange, textRange } = args[1];
|
|
909
|
+
const edits = lang.getEditsForRefactor(path, {}, textRange, refactorName, command, userPreferences);
|
|
910
|
+
if (!edits || edits.edits.length === 0) {
|
|
911
|
+
return null;
|
|
912
|
+
}
|
|
913
|
+
const documentChanges = edits?.edits.map((edit) => vscode_languageserver_1.TextDocumentEdit.create(vscode_languageserver_1.OptionalVersionedTextDocumentIdentifier.create(document.uri, null), edit.textChanges.map((edit) => {
|
|
914
|
+
const range = (0, documents_1.mapRangeToOriginal)(tsDoc, (0, utils_2.convertRange)(tsDoc, edit.span));
|
|
915
|
+
return vscode_languageserver_1.TextEdit.replace(this.checkEndOfFileCodeInsert(range, originalRange, document), edit.newText);
|
|
916
|
+
})));
|
|
917
|
+
return { documentChanges };
|
|
918
|
+
}
|
|
919
|
+
/**
|
|
920
|
+
* Some refactorings place the new code at the end of svelte2tsx' render function,
|
|
921
|
+
* which is unmapped. In this case, add it to the end of the script tag ourselves.
|
|
922
|
+
*/
|
|
923
|
+
checkEndOfFileCodeInsert(resultRange, targetRange, document) {
|
|
924
|
+
if (resultRange.start.line < 0 || resultRange.end.line < 0) {
|
|
925
|
+
if (document.moduleScriptInfo &&
|
|
926
|
+
(!targetRange || (0, documents_1.isRangeInTag)(targetRange, document.moduleScriptInfo))) {
|
|
927
|
+
return vscode_languageserver_1.Range.create(document.moduleScriptInfo.endPos, document.moduleScriptInfo.endPos);
|
|
928
|
+
}
|
|
929
|
+
if (document.scriptInfo) {
|
|
930
|
+
return vscode_languageserver_1.Range.create(document.scriptInfo.endPos, document.scriptInfo.endPos);
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
// don't add script tag here because the code action is calculated
|
|
934
|
+
// when the file is treated as js
|
|
935
|
+
// but user might want a ts version of the code action
|
|
936
|
+
return resultRange;
|
|
937
|
+
}
|
|
938
|
+
checkTsNoCheckCodeInsert(document, edit) {
|
|
939
|
+
const scriptInfo = document.moduleScriptInfo ?? document.scriptInfo;
|
|
940
|
+
if (!scriptInfo) {
|
|
941
|
+
return undefined;
|
|
942
|
+
}
|
|
943
|
+
const newText = typescript_1.default.sys.newLine + edit.newText;
|
|
944
|
+
return vscode_languageserver_1.TextEdit.insert(scriptInfo.startPos, newText);
|
|
945
|
+
}
|
|
946
|
+
checkDisableJsDiagnosticsCodeInsert(originalRange, document, edit) {
|
|
947
|
+
const inModuleScript = (0, documents_1.isInTag)(originalRange.start, document.moduleScriptInfo);
|
|
948
|
+
if (!(0, documents_1.isInTag)(originalRange.start, document.scriptInfo) && !inModuleScript) {
|
|
949
|
+
return null;
|
|
950
|
+
}
|
|
951
|
+
const position = inModuleScript
|
|
952
|
+
? originalRange.start
|
|
953
|
+
: (this.fixPropsCodeActionRange(originalRange.start, document) ?? originalRange.start);
|
|
954
|
+
// fix the length of trailing indent
|
|
955
|
+
const linesOfNewText = edit.newText.split('\n');
|
|
956
|
+
if (/^[ \t]*$/.test(linesOfNewText[linesOfNewText.length - 1])) {
|
|
957
|
+
const line = (0, documents_1.getLineAtPosition)(originalRange.start, document.getText());
|
|
958
|
+
const indent = (0, utils_1.getIndent)(line);
|
|
959
|
+
linesOfNewText[linesOfNewText.length - 1] = indent;
|
|
960
|
+
}
|
|
961
|
+
return vscode_languageserver_1.TextEdit.insert(position, linesOfNewText.join('\n'));
|
|
962
|
+
}
|
|
963
|
+
/**
|
|
964
|
+
* svelte2tsx removes export in instance script
|
|
965
|
+
*/
|
|
966
|
+
fixPropsCodeActionRange(start, document) {
|
|
967
|
+
const documentText = document.getText();
|
|
968
|
+
const offset = document.offsetAt(start);
|
|
969
|
+
const exportKeywordOffset = documentText.lastIndexOf('export', offset);
|
|
970
|
+
// export let a;
|
|
971
|
+
if (exportKeywordOffset < 0 ||
|
|
972
|
+
documentText.slice(exportKeywordOffset + 'export'.length, offset).trim()) {
|
|
973
|
+
return;
|
|
974
|
+
}
|
|
975
|
+
const charBeforeExport = documentText[exportKeywordOffset - 1];
|
|
976
|
+
if ((charBeforeExport !== undefined && !charBeforeExport.trim()) ||
|
|
977
|
+
charBeforeExport === ';') {
|
|
978
|
+
return document.positionAt(exportKeywordOffset);
|
|
979
|
+
}
|
|
980
|
+
}
|
|
981
|
+
checkAddJsDocCodeActionRange(snapshot, originalRange, document) {
|
|
982
|
+
if (snapshot.scriptKind !== typescript_1.default.ScriptKind.JS &&
|
|
983
|
+
snapshot.scriptKind !== typescript_1.default.ScriptKind.JSX &&
|
|
984
|
+
!(0, documents_1.isInTag)(originalRange.start, document.scriptInfo)) {
|
|
985
|
+
return originalRange;
|
|
986
|
+
}
|
|
987
|
+
const position = this.fixPropsCodeActionRange(originalRange.start, document);
|
|
988
|
+
if (position) {
|
|
989
|
+
return {
|
|
990
|
+
start: position,
|
|
991
|
+
end: position
|
|
992
|
+
};
|
|
993
|
+
}
|
|
994
|
+
return originalRange;
|
|
995
|
+
}
|
|
996
|
+
async getLSAndTSDoc(document) {
|
|
997
|
+
return this.lsAndTsDocResolver.getLSAndTSDoc(document);
|
|
998
|
+
}
|
|
999
|
+
async addMissingImports(document, cancellationToken) {
|
|
1000
|
+
// Re-introduce LS/TSDoc resolution and diagnostic check
|
|
1001
|
+
const { lang, tsDoc } = await this.getLSAndTSDoc(document);
|
|
1002
|
+
if (cancellationToken?.isCancellationRequested) {
|
|
1003
|
+
return [];
|
|
1004
|
+
}
|
|
1005
|
+
// Check if there are any relevant "cannot find name" diagnostics
|
|
1006
|
+
const diagnostics = lang.getSemanticDiagnostics(tsDoc.filePath);
|
|
1007
|
+
const hasMissingImports = diagnostics.some((diag) => (diag.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME ||
|
|
1008
|
+
diag.code === DiagnosticsProvider_1.DiagnosticCode.CANNOT_FIND_NAME_X_DID_YOU_MEAN_Y) &&
|
|
1009
|
+
// Ensure the diagnostic is not in generated code
|
|
1010
|
+
!(0, utils_3.isTextSpanInGeneratedCode)(tsDoc.getFullText(), {
|
|
1011
|
+
start: diag.start ?? 0,
|
|
1012
|
+
length: diag.length ?? 0
|
|
1013
|
+
}));
|
|
1014
|
+
// Only return the action if there are potential imports to add
|
|
1015
|
+
if (!hasMissingImports) {
|
|
1016
|
+
return [];
|
|
1017
|
+
}
|
|
1018
|
+
// If imports might be needed, create the deferred action
|
|
1019
|
+
const codeAction = vscode_languageserver_1.CodeAction.create(FIX_IMPORT_FIX_DESCRIPTION, exports.ADD_MISSING_IMPORTS_CODE_ACTION_KIND);
|
|
1020
|
+
const data = {
|
|
1021
|
+
uri: document.uri,
|
|
1022
|
+
fixName: FIX_IMPORT_FIX_NAME,
|
|
1023
|
+
fixId: FIX_IMPORT_FIX_ID
|
|
1024
|
+
};
|
|
1025
|
+
codeAction.data = data;
|
|
1026
|
+
return [codeAction];
|
|
1027
|
+
}
|
|
1028
|
+
}
|
|
1029
|
+
exports.CodeActionsProviderImpl = CodeActionsProviderImpl;
|
|
1030
|
+
//# sourceMappingURL=CodeActionsProvider.js.map
|