@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.
Files changed (256) hide show
  1. package/README.md +331 -0
  2. package/bin/server.js +5 -0
  3. package/dist/src/importPackage.d.ts +16 -0
  4. package/dist/src/importPackage.js +76 -0
  5. package/dist/src/importPackage.js.map +1 -0
  6. package/dist/src/index.d.ts +3 -0
  7. package/dist/src/index.js +23 -0
  8. package/dist/src/index.js.map +1 -0
  9. package/dist/src/lib/DiagnosticsManager.d.ts +20 -0
  10. package/dist/src/lib/DiagnosticsManager.js +71 -0
  11. package/dist/src/lib/DiagnosticsManager.js.map +1 -0
  12. package/dist/src/lib/FallbackWatcher.d.ts +15 -0
  13. package/dist/src/lib/FallbackWatcher.js +66 -0
  14. package/dist/src/lib/FallbackWatcher.js.map +1 -0
  15. package/dist/src/lib/documentHighlight/wordHighlight.d.ts +3 -0
  16. package/dist/src/lib/documentHighlight/wordHighlight.js +62 -0
  17. package/dist/src/lib/documentHighlight/wordHighlight.js.map +1 -0
  18. package/dist/src/lib/documents/Document.d.ts +63 -0
  19. package/dist/src/lib/documents/Document.js +138 -0
  20. package/dist/src/lib/documents/Document.js.map +1 -0
  21. package/dist/src/lib/documents/DocumentBase.d.ts +65 -0
  22. package/dist/src/lib/documents/DocumentBase.js +69 -0
  23. package/dist/src/lib/documents/DocumentBase.js.map +1 -0
  24. package/dist/src/lib/documents/DocumentManager.d.ts +28 -0
  25. package/dist/src/lib/documents/DocumentManager.js +122 -0
  26. package/dist/src/lib/documents/DocumentManager.js.map +1 -0
  27. package/dist/src/lib/documents/DocumentMapper.d.ts +88 -0
  28. package/dist/src/lib/documents/DocumentMapper.js +258 -0
  29. package/dist/src/lib/documents/DocumentMapper.js.map +1 -0
  30. package/dist/src/lib/documents/configLoader.d.ts +80 -0
  31. package/dist/src/lib/documents/configLoader.js +265 -0
  32. package/dist/src/lib/documents/configLoader.js.map +1 -0
  33. package/dist/src/lib/documents/fileCollection.d.ts +41 -0
  34. package/dist/src/lib/documents/fileCollection.js +87 -0
  35. package/dist/src/lib/documents/fileCollection.js.map +1 -0
  36. package/dist/src/lib/documents/index.d.ts +5 -0
  37. package/dist/src/lib/documents/index.js +22 -0
  38. package/dist/src/lib/documents/index.js.map +1 -0
  39. package/dist/src/lib/documents/parseHtml.d.ts +13 -0
  40. package/dist/src/lib/documents/parseHtml.js +160 -0
  41. package/dist/src/lib/documents/parseHtml.js.map +1 -0
  42. package/dist/src/lib/documents/utils.d.ts +105 -0
  43. package/dist/src/lib/documents/utils.js +410 -0
  44. package/dist/src/lib/documents/utils.js.map +1 -0
  45. package/dist/src/lib/foldingRange/indentFolding.d.ts +26 -0
  46. package/dist/src/lib/foldingRange/indentFolding.js +142 -0
  47. package/dist/src/lib/foldingRange/indentFolding.js.map +1 -0
  48. package/dist/src/lib/semanticToken/semanticTokenLegend.d.ts +33 -0
  49. package/dist/src/lib/semanticToken/semanticTokenLegend.js +37 -0
  50. package/dist/src/lib/semanticToken/semanticTokenLegend.js.map +1 -0
  51. package/dist/src/logger.d.ts +9 -0
  52. package/dist/src/logger.js +28 -0
  53. package/dist/src/logger.js.map +1 -0
  54. package/dist/src/ls-config.d.ts +326 -0
  55. package/dist/src/ls-config.js +386 -0
  56. package/dist/src/ls-config.js.map +1 -0
  57. package/dist/src/plugins/PluginHost.d.ts +68 -0
  58. package/dist/src/plugins/PluginHost.js +447 -0
  59. package/dist/src/plugins/PluginHost.js.map +1 -0
  60. package/dist/src/plugins/css/CSSDocument.d.ts +46 -0
  61. package/dist/src/plugins/css/CSSDocument.js +78 -0
  62. package/dist/src/plugins/css/CSSDocument.js.map +1 -0
  63. package/dist/src/plugins/css/CSSPlugin.d.ts +35 -0
  64. package/dist/src/plugins/css/CSSPlugin.js +407 -0
  65. package/dist/src/plugins/css/CSSPlugin.js.map +1 -0
  66. package/dist/src/plugins/css/FileSystemProvider.d.ts +10 -0
  67. package/dist/src/plugins/css/FileSystemProvider.js +75 -0
  68. package/dist/src/plugins/css/FileSystemProvider.js.map +1 -0
  69. package/dist/src/plugins/css/StyleAttributeDocument.d.ts +41 -0
  70. package/dist/src/plugins/css/StyleAttributeDocument.js +65 -0
  71. package/dist/src/plugins/css/StyleAttributeDocument.js.map +1 -0
  72. package/dist/src/plugins/css/features/getIdClassCompletion.d.ts +19 -0
  73. package/dist/src/plugins/css/features/getIdClassCompletion.js +56 -0
  74. package/dist/src/plugins/css/features/getIdClassCompletion.js.map +1 -0
  75. package/dist/src/plugins/css/features/svelte-selectors.d.ts +2 -0
  76. package/dist/src/plugins/css/features/svelte-selectors.js +18 -0
  77. package/dist/src/plugins/css/features/svelte-selectors.js.map +1 -0
  78. package/dist/src/plugins/css/global-vars.d.ts +16 -0
  79. package/dist/src/plugins/css/global-vars.js +82 -0
  80. package/dist/src/plugins/css/global-vars.js.map +1 -0
  81. package/dist/src/plugins/css/service.d.ts +5 -0
  82. package/dist/src/plugins/css/service.js +66 -0
  83. package/dist/src/plugins/css/service.js.map +1 -0
  84. package/dist/src/plugins/documentContext.d.ts +3 -0
  85. package/dist/src/plugins/documentContext.js +36 -0
  86. package/dist/src/plugins/documentContext.js.map +1 -0
  87. package/dist/src/plugins/html/HTMLPlugin.d.ts +36 -0
  88. package/dist/src/plugins/html/HTMLPlugin.js +363 -0
  89. package/dist/src/plugins/html/HTMLPlugin.js.map +1 -0
  90. package/dist/src/plugins/html/dataProvider.d.ts +1 -0
  91. package/dist/src/plugins/html/dataProvider.js +481 -0
  92. package/dist/src/plugins/html/dataProvider.js.map +1 -0
  93. package/dist/src/plugins/index.d.ts +7 -0
  94. package/dist/src/plugins/index.js +24 -0
  95. package/dist/src/plugins/index.js.map +1 -0
  96. package/dist/src/plugins/interfaces.d.ts +132 -0
  97. package/dist/src/plugins/interfaces.js +3 -0
  98. package/dist/src/plugins/interfaces.js.map +1 -0
  99. package/dist/src/plugins/svelte/SvelteDocument.d.ts +98 -0
  100. package/dist/src/plugins/svelte/SvelteDocument.js +318 -0
  101. package/dist/src/plugins/svelte/SvelteDocument.js.map +1 -0
  102. package/dist/src/plugins/svelte/SveltePlugin.d.ts +24 -0
  103. package/dist/src/plugins/svelte/SveltePlugin.js +306 -0
  104. package/dist/src/plugins/svelte/SveltePlugin.js.map +1 -0
  105. package/dist/src/plugins/svelte/features/SvelteTags.d.ts +28 -0
  106. package/dist/src/plugins/svelte/features/SvelteTags.js +136 -0
  107. package/dist/src/plugins/svelte/features/SvelteTags.js.map +1 -0
  108. package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.d.ts +11 -0
  109. package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.js +140 -0
  110. package/dist/src/plugins/svelte/features/getCodeActions/getQuickfixes.js.map +1 -0
  111. package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.d.ts +9 -0
  112. package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.js +140 -0
  113. package/dist/src/plugins/svelte/features/getCodeActions/getRefactorings.js.map +1 -0
  114. package/dist/src/plugins/svelte/features/getCodeActions/index.d.ts +4 -0
  115. package/dist/src/plugins/svelte/features/getCodeActions/index.js +19 -0
  116. package/dist/src/plugins/svelte/features/getCodeActions/index.js.map +1 -0
  117. package/dist/src/plugins/svelte/features/getCompletions.d.ts +4 -0
  118. package/dist/src/plugins/svelte/features/getCompletions.js +184 -0
  119. package/dist/src/plugins/svelte/features/getCompletions.js.map +1 -0
  120. package/dist/src/plugins/svelte/features/getDiagnostics.d.ts +9 -0
  121. package/dist/src/plugins/svelte/features/getDiagnostics.js +284 -0
  122. package/dist/src/plugins/svelte/features/getDiagnostics.js.map +1 -0
  123. package/dist/src/plugins/svelte/features/getHoverInfo.d.ts +7 -0
  124. package/dist/src/plugins/svelte/features/getHoverInfo.js +93 -0
  125. package/dist/src/plugins/svelte/features/getHoverInfo.js.map +1 -0
  126. package/dist/src/plugins/svelte/features/getModifierData.d.ts +7 -0
  127. package/dist/src/plugins/svelte/features/getModifierData.js +56 -0
  128. package/dist/src/plugins/svelte/features/getModifierData.js.map +1 -0
  129. package/dist/src/plugins/svelte/features/getSelectionRanges.d.ts +3 -0
  130. package/dist/src/plugins/svelte/features/getSelectionRanges.js +46 -0
  131. package/dist/src/plugins/svelte/features/getSelectionRanges.js.map +1 -0
  132. package/dist/src/plugins/svelte/features/utils.d.ts +5 -0
  133. package/dist/src/plugins/svelte/features/utils.js +18 -0
  134. package/dist/src/plugins/svelte/features/utils.js.map +1 -0
  135. package/dist/src/plugins/typescript/ComponentInfoProvider.d.ts +27 -0
  136. package/dist/src/plugins/typescript/ComponentInfoProvider.js +116 -0
  137. package/dist/src/plugins/typescript/ComponentInfoProvider.js.map +1 -0
  138. package/dist/src/plugins/typescript/DocumentMapper.d.ts +10 -0
  139. package/dist/src/plugins/typescript/DocumentMapper.js +25 -0
  140. package/dist/src/plugins/typescript/DocumentMapper.js.map +1 -0
  141. package/dist/src/plugins/typescript/DocumentSnapshot.d.ts +173 -0
  142. package/dist/src/plugins/typescript/DocumentSnapshot.js +623 -0
  143. package/dist/src/plugins/typescript/DocumentSnapshot.js.map +1 -0
  144. package/dist/src/plugins/typescript/LSAndTSDocResolver.d.ts +100 -0
  145. package/dist/src/plugins/typescript/LSAndTSDocResolver.js +301 -0
  146. package/dist/src/plugins/typescript/LSAndTSDocResolver.js.map +1 -0
  147. package/dist/src/plugins/typescript/SnapshotManager.d.ts +59 -0
  148. package/dist/src/plugins/typescript/SnapshotManager.js +238 -0
  149. package/dist/src/plugins/typescript/SnapshotManager.js.map +1 -0
  150. package/dist/src/plugins/typescript/TypeScriptPlugin.d.ts +65 -0
  151. package/dist/src/plugins/typescript/TypeScriptPlugin.js +332 -0
  152. package/dist/src/plugins/typescript/TypeScriptPlugin.js.map +1 -0
  153. package/dist/src/plugins/typescript/features/CallHierarchyProvider.d.ts +24 -0
  154. package/dist/src/plugins/typescript/features/CallHierarchyProvider.js +325 -0
  155. package/dist/src/plugins/typescript/features/CallHierarchyProvider.js.map +1 -0
  156. package/dist/src/plugins/typescript/features/CodeActionsProvider.d.ts +72 -0
  157. package/dist/src/plugins/typescript/features/CodeActionsProvider.js +1030 -0
  158. package/dist/src/plugins/typescript/features/CodeActionsProvider.js.map +1 -0
  159. package/dist/src/plugins/typescript/features/CodeLensProvider.d.ts +28 -0
  160. package/dist/src/plugins/typescript/features/CodeLensProvider.js +205 -0
  161. package/dist/src/plugins/typescript/features/CodeLensProvider.js.map +1 -0
  162. package/dist/src/plugins/typescript/features/CompletionProvider.d.ts +57 -0
  163. package/dist/src/plugins/typescript/features/CompletionProvider.js +791 -0
  164. package/dist/src/plugins/typescript/features/CompletionProvider.js.map +1 -0
  165. package/dist/src/plugins/typescript/features/DiagnosticsProvider.d.ts +36 -0
  166. package/dist/src/plugins/typescript/features/DiagnosticsProvider.js +497 -0
  167. package/dist/src/plugins/typescript/features/DiagnosticsProvider.js.map +1 -0
  168. package/dist/src/plugins/typescript/features/DocumentHighlightProvider.d.ts +17 -0
  169. package/dist/src/plugins/typescript/features/DocumentHighlightProvider.js +211 -0
  170. package/dist/src/plugins/typescript/features/DocumentHighlightProvider.js.map +1 -0
  171. package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.d.ts +9 -0
  172. package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.js +66 -0
  173. package/dist/src/plugins/typescript/features/FindComponentReferencesProvider.js.map +1 -0
  174. package/dist/src/plugins/typescript/features/FindFileReferencesProvider.d.ts +9 -0
  175. package/dist/src/plugins/typescript/features/FindFileReferencesProvider.js +38 -0
  176. package/dist/src/plugins/typescript/features/FindFileReferencesProvider.js.map +1 -0
  177. package/dist/src/plugins/typescript/features/FindReferencesProvider.d.ts +20 -0
  178. package/dist/src/plugins/typescript/features/FindReferencesProvider.js +149 -0
  179. package/dist/src/plugins/typescript/features/FindReferencesProvider.js.map +1 -0
  180. package/dist/src/plugins/typescript/features/FoldingRangeProvider.d.ts +28 -0
  181. package/dist/src/plugins/typescript/features/FoldingRangeProvider.js +247 -0
  182. package/dist/src/plugins/typescript/features/FoldingRangeProvider.js.map +1 -0
  183. package/dist/src/plugins/typescript/features/HoverProvider.d.ts +11 -0
  184. package/dist/src/plugins/typescript/features/HoverProvider.js +75 -0
  185. package/dist/src/plugins/typescript/features/HoverProvider.js.map +1 -0
  186. package/dist/src/plugins/typescript/features/ImplementationProvider.d.ts +9 -0
  187. package/dist/src/plugins/typescript/features/ImplementationProvider.js +47 -0
  188. package/dist/src/plugins/typescript/features/ImplementationProvider.js.map +1 -0
  189. package/dist/src/plugins/typescript/features/InlayHintProvider.d.ts +22 -0
  190. package/dist/src/plugins/typescript/features/InlayHintProvider.js +225 -0
  191. package/dist/src/plugins/typescript/features/InlayHintProvider.js.map +1 -0
  192. package/dist/src/plugins/typescript/features/RenameProvider.d.ts +53 -0
  193. package/dist/src/plugins/typescript/features/RenameProvider.js +423 -0
  194. package/dist/src/plugins/typescript/features/RenameProvider.js.map +1 -0
  195. package/dist/src/plugins/typescript/features/SelectionRangeProvider.d.ts +18 -0
  196. package/dist/src/plugins/typescript/features/SelectionRangeProvider.js +62 -0
  197. package/dist/src/plugins/typescript/features/SelectionRangeProvider.js.map +1 -0
  198. package/dist/src/plugins/typescript/features/SemanticTokensProvider.d.ts +15 -0
  199. package/dist/src/plugins/typescript/features/SemanticTokensProvider.js +116 -0
  200. package/dist/src/plugins/typescript/features/SemanticTokensProvider.js.map +1 -0
  201. package/dist/src/plugins/typescript/features/SignatureHelpProvider.d.ts +22 -0
  202. package/dist/src/plugins/typescript/features/SignatureHelpProvider.js +110 -0
  203. package/dist/src/plugins/typescript/features/SignatureHelpProvider.js.map +1 -0
  204. package/dist/src/plugins/typescript/features/TypeDefinitionProvider.d.ts +9 -0
  205. package/dist/src/plugins/typescript/features/TypeDefinitionProvider.js +35 -0
  206. package/dist/src/plugins/typescript/features/TypeDefinitionProvider.js.map +1 -0
  207. package/dist/src/plugins/typescript/features/UpdateImportsProvider.d.ts +11 -0
  208. package/dist/src/plugins/typescript/features/UpdateImportsProvider.js +109 -0
  209. package/dist/src/plugins/typescript/features/UpdateImportsProvider.js.map +1 -0
  210. package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.d.ts +25 -0
  211. package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.js +176 -0
  212. package/dist/src/plugins/typescript/features/WorkspaceSymbolProvider.js.map +1 -0
  213. package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.d.ts +13 -0
  214. package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.js +58 -0
  215. package/dist/src/plugins/typescript/features/getDirectiveCommentCompletions.js.map +1 -0
  216. package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.d.ts +4 -0
  217. package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.js +57 -0
  218. package/dist/src/plugins/typescript/features/getJsDocTemplateCompletion.js.map +1 -0
  219. package/dist/src/plugins/typescript/features/utils.d.ts +81 -0
  220. package/dist/src/plugins/typescript/features/utils.js +331 -0
  221. package/dist/src/plugins/typescript/features/utils.js.map +1 -0
  222. package/dist/src/plugins/typescript/macroforgeAugmenter.d.ts +23 -0
  223. package/dist/src/plugins/typescript/macroforgeAugmenter.js +41 -0
  224. package/dist/src/plugins/typescript/macroforgeAugmenter.js.map +1 -0
  225. package/dist/src/plugins/typescript/module-loader.d.ts +28 -0
  226. package/dist/src/plugins/typescript/module-loader.js +254 -0
  227. package/dist/src/plugins/typescript/module-loader.js.map +1 -0
  228. package/dist/src/plugins/typescript/previewer.d.ts +7 -0
  229. package/dist/src/plugins/typescript/previewer.js +120 -0
  230. package/dist/src/plugins/typescript/previewer.js.map +1 -0
  231. package/dist/src/plugins/typescript/service.d.ts +105 -0
  232. package/dist/src/plugins/typescript/service.js +1073 -0
  233. package/dist/src/plugins/typescript/service.js.map +1 -0
  234. package/dist/src/plugins/typescript/serviceCache.d.ts +90 -0
  235. package/dist/src/plugins/typescript/serviceCache.js +50 -0
  236. package/dist/src/plugins/typescript/serviceCache.js.map +1 -0
  237. package/dist/src/plugins/typescript/svelte-ast-utils.d.ts +77 -0
  238. package/dist/src/plugins/typescript/svelte-ast-utils.js +100 -0
  239. package/dist/src/plugins/typescript/svelte-ast-utils.js.map +1 -0
  240. package/dist/src/plugins/typescript/svelte-sys.d.ts +9 -0
  241. package/dist/src/plugins/typescript/svelte-sys.js +79 -0
  242. package/dist/src/plugins/typescript/svelte-sys.js.map +1 -0
  243. package/dist/src/plugins/typescript/utils.d.ts +48 -0
  244. package/dist/src/plugins/typescript/utils.js +334 -0
  245. package/dist/src/plugins/typescript/utils.js.map +1 -0
  246. package/dist/src/server.d.ts +19 -0
  247. package/dist/src/server.js +434 -0
  248. package/dist/src/server.js.map +1 -0
  249. package/dist/src/svelte-check.d.ts +65 -0
  250. package/dist/src/svelte-check.js +288 -0
  251. package/dist/src/svelte-check.js.map +1 -0
  252. package/dist/src/utils.d.ts +111 -0
  253. package/dist/src/utils.js +337 -0
  254. package/dist/src/utils.js.map +1 -0
  255. package/dist/tsconfig.tsbuildinfo +1 -0
  256. package/package.json +79 -0
@@ -0,0 +1,791 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.CompletionsProviderImpl = void 0;
7
+ const path_1 = require("path");
8
+ const typescript_1 = __importDefault(require("typescript"));
9
+ const vscode_languageserver_1 = require("vscode-languageserver");
10
+ const documents_1 = require("../../../lib/documents");
11
+ const parseHtml_1 = require("../../../lib/documents/parseHtml");
12
+ const utils_1 = require("../../../utils");
13
+ const previewer_1 = require("../previewer");
14
+ const utils_2 = require("../utils");
15
+ const getJsDocTemplateCompletion_1 = require("./getJsDocTemplateCompletion");
16
+ const utils_3 = require("./utils");
17
+ const svelte_ast_utils_1 = require("../svelte-ast-utils");
18
+ class CompletionsProviderImpl {
19
+ constructor(lsAndTsDocResolver, configManager) {
20
+ this.lsAndTsDocResolver = lsAndTsDocResolver;
21
+ this.configManager = configManager;
22
+ /**
23
+ * The language service throws an error if the character is not a valid trigger character.
24
+ * Also, the completions are worse.
25
+ * Therefore, only use the characters the typescript compiler treats as valid.
26
+ */
27
+ this.validTriggerCharacters = ['.', '"', "'", '`', '/', '@', '<', '#'];
28
+ this.commitCharacters = ['.', ',', ';', '('];
29
+ }
30
+ isValidTriggerCharacter(character) {
31
+ return this.validTriggerCharacters.includes(character);
32
+ }
33
+ async getCompletions(document, position, completionContext, cancellationToken) {
34
+ if ((0, documents_1.isInTag)(position, document.styleInfo)) {
35
+ return null;
36
+ }
37
+ const { lang: langForSyntheticOperations, tsDoc, userPreferences } = await this.lsAndTsDocResolver.getLsForSyntheticOperations(document);
38
+ const filePath = tsDoc.filePath;
39
+ if (!filePath) {
40
+ return null;
41
+ }
42
+ const triggerCharacter = completionContext?.triggerCharacter;
43
+ const triggerKind = completionContext?.triggerKind;
44
+ const validTriggerCharacter = this.isValidTriggerCharacter(triggerCharacter)
45
+ ? triggerCharacter
46
+ : undefined;
47
+ const isCustomTriggerCharacter = triggerKind === vscode_languageserver_1.CompletionTriggerKind.TriggerCharacter;
48
+ const isJsDocTriggerCharacter = triggerCharacter === '*';
49
+ const isEventOrSlotLetTriggerCharacter = triggerCharacter === ':';
50
+ // ignore any custom trigger character specified in server capabilities
51
+ // and is not allow by ts
52
+ if (isCustomTriggerCharacter &&
53
+ !validTriggerCharacter &&
54
+ !isJsDocTriggerCharacter &&
55
+ !isEventOrSlotLetTriggerCharacter) {
56
+ return null;
57
+ }
58
+ if (this.canReuseLastCompletion(this.lastCompletion, triggerKind, triggerCharacter, document, position)) {
59
+ this.lastCompletion.position = position;
60
+ return this.lastCompletion.completionList;
61
+ }
62
+ else {
63
+ this.lastCompletion = undefined;
64
+ }
65
+ if (!tsDoc.isInGenerated(position)) {
66
+ return null;
67
+ }
68
+ const originalOffset = document.offsetAt(position);
69
+ let offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
70
+ if (isJsDocTriggerCharacter) {
71
+ return (0, getJsDocTemplateCompletion_1.getJsDocTemplateCompletion)(tsDoc, langForSyntheticOperations, filePath, offset);
72
+ }
73
+ const svelteNode = tsDoc.svelteNodeAt(originalOffset);
74
+ if (
75
+ // Cursor is somewhere in regular HTML text
76
+ (svelteNode?.type === 'Text' &&
77
+ [
78
+ 'Element',
79
+ 'InlineComponent',
80
+ 'Fragment',
81
+ 'SlotTemplate',
82
+ 'SnippetBlock',
83
+ 'IfBlock',
84
+ 'EachBlock',
85
+ 'AwaitBlock'
86
+ ].includes(svelteNode.parent?.type)) ||
87
+ // Cursor is at <div>|</div> in which case there's no TextNode inbetween
88
+ document.getText().substring(originalOffset - 1, originalOffset + 2) === '></') {
89
+ return null;
90
+ }
91
+ const { lang, lsContainer } = await this.lsAndTsDocResolver.getLSAndTSDoc(document);
92
+ if (cancellationToken?.isCancellationRequested) {
93
+ return null;
94
+ }
95
+ const inScript = (0, utils_2.isInScript)(position, tsDoc);
96
+ const wordInfo = this.getWordAtPosition(document, originalOffset);
97
+ if (!inScript &&
98
+ wordInfo.word[0] === '{' &&
99
+ (wordInfo.word[1] === '#' ||
100
+ wordInfo.word[1] === '@' ||
101
+ wordInfo.word[1] === ':' ||
102
+ wordInfo.word[1] === '/')) {
103
+ // Typing something like {/if}
104
+ return null;
105
+ }
106
+ // Special case: completion at `<Comp.` -> mapped one character too short -> adjust
107
+ if (!inScript &&
108
+ wordInfo.word === '' &&
109
+ document.getText()[originalOffset - 1] === '.' &&
110
+ tsDoc.getFullText()[offset] === '.') {
111
+ offset++;
112
+ }
113
+ const componentInfo = (0, utils_3.getComponentAtPosition)(lang, document, tsDoc, position);
114
+ const attributeContext = componentInfo && (0, parseHtml_1.getAttributeContextAtPosition)(document, position);
115
+ const eventAndSlotLetCompletions = this.getEventAndSlotLetCompletions(componentInfo, attributeContext, wordInfo.defaultTextEditRange);
116
+ if (isEventOrSlotLetTriggerCharacter) {
117
+ return vscode_languageserver_1.CompletionList.create(eventAndSlotLetCompletions, !!tsDoc.parserError);
118
+ }
119
+ const tagCompletions = componentInfo || eventAndSlotLetCompletions.length > 0
120
+ ? []
121
+ : this.getCustomElementCompletions(lang, lsContainer, document, tsDoc, position);
122
+ const formatSettings = await this.configManager.getFormatCodeSettingsForFile(document, tsDoc.scriptKind);
123
+ if (cancellationToken?.isCancellationRequested) {
124
+ return null;
125
+ }
126
+ // one or two characters after start tag might be mapped to the component name
127
+ if (svelteNode?.type === 'InlineComponent' &&
128
+ 'name' in svelteNode &&
129
+ typeof svelteNode.name === 'string') {
130
+ const name = svelteNode.name;
131
+ const nameEnd = svelteNode.start + 1 + name.length;
132
+ const isWhitespaceAfterStartTag = document.getText().slice(nameEnd, originalOffset).trim() === '' &&
133
+ this.mightBeAtStartTagWhitespace(document, originalOffset);
134
+ if (isWhitespaceAfterStartTag) {
135
+ // We can be sure only to get completions for directives and props here
136
+ // so don't bother with the expensive global completions
137
+ return this.getCompletionListForDirectiveOrProps(attributeContext, componentInfo, wordInfo.defaultTextEditRange, eventAndSlotLetCompletions, tsDoc);
138
+ }
139
+ }
140
+ const response = lang.getCompletionsAtPosition(filePath, offset, {
141
+ ...userPreferences,
142
+ triggerCharacter: validTriggerCharacter
143
+ }, formatSettings);
144
+ const commitCharactersOptions = this.getCommitCharactersOptions(response, tsDoc, position);
145
+ let completions = response?.entries || [];
146
+ const customCompletions = eventAndSlotLetCompletions.concat(tagCompletions ?? []);
147
+ if (completions.length === 0 && customCompletions.length === 0) {
148
+ return tsDoc.parserError ? vscode_languageserver_1.CompletionList.create([], true) : null;
149
+ }
150
+ if (completions.length > 500 &&
151
+ svelteNode?.type === 'Element' &&
152
+ completions[0].kind !== typescript_1.default.ScriptElementKind.memberVariableElement) {
153
+ // False global completions inside element start tag
154
+ return null;
155
+ }
156
+ if (completions.length > 500 &&
157
+ svelteNode?.type === 'InlineComponent' &&
158
+ this.mightBeAtStartTagWhitespace(document, originalOffset)) {
159
+ // Very likely false global completions inside component start tag -> narrow
160
+ return this.getCompletionListForDirectiveOrProps(attributeContext, componentInfo, wordInfo.defaultTextEditRange, eventAndSlotLetCompletions, tsDoc);
161
+ }
162
+ // moved here due to perf reasons
163
+ const existingImports = this.getExistingImports(document);
164
+ const fileUrl = (0, utils_1.pathToUrl)(tsDoc.filePath);
165
+ const isCompletionInTag = (0, svelte_ast_utils_1.isInTag)(svelteNode, originalOffset);
166
+ const isHandlerCompletion = svelteNode?.type === 'EventHandler' && svelteNode.parent?.type === 'Element';
167
+ const preferComponents = wordInfo.word[0] === '<' || inScript;
168
+ const completionItems = customCompletions;
169
+ const isValidCompletion = createIsValidCompletion(document, position, !!tsDoc.parserError);
170
+ const addCompletion = (entry, asStore) => {
171
+ if (isValidCompletion(entry)) {
172
+ let completion = this.toCompletionItem(tsDoc, entry, fileUrl, position, isCompletionInTag, commitCharactersOptions, asStore, existingImports, preferComponents);
173
+ if (completion) {
174
+ completionItems.push(this.fixTextEditRange(wordInfo.range, (0, documents_1.mapCompletionItemToOriginal)(tsDoc, completion), isHandlerCompletion, completion.textEdit, tsDoc));
175
+ }
176
+ }
177
+ };
178
+ // If completion is about a store which is not imported yet, do another
179
+ // completion request at the beginning of the file to get all global
180
+ // import completions and then filter them down to likely matches.
181
+ if (wordInfo.word.charAt(0) === '$') {
182
+ const storeName = wordInfo.word.substring(1);
183
+ const text = '__sveltets_2_store_get(' + storeName;
184
+ if (!tsDoc.getFullText().includes(text)) {
185
+ const pos = (tsDoc.scriptInfo || tsDoc.moduleScriptInfo)?.endPos ?? {
186
+ line: 0,
187
+ character: 0
188
+ };
189
+ const virtualOffset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(pos));
190
+ const storeCompletions = lang.getCompletionsAtPosition(filePath, virtualOffset, {
191
+ ...userPreferences,
192
+ triggerCharacter: validTriggerCharacter
193
+ }, formatSettings);
194
+ for (const entry of storeCompletions?.entries || []) {
195
+ if (entry.name.startsWith(storeName)) {
196
+ addCompletion(entry, true);
197
+ }
198
+ }
199
+ }
200
+ }
201
+ for (const entry of completions) {
202
+ addCompletion(entry, false);
203
+ }
204
+ // Add ./$types imports for SvelteKit since TypeScript is bad at it
205
+ if ((0, path_1.basename)(filePath).startsWith('+')) {
206
+ const $typeImports = new Map();
207
+ for (const c of completionItems) {
208
+ if ((0, utils_3.isKitTypePath)(c.data?.source)) {
209
+ $typeImports.set(c.label, c);
210
+ }
211
+ }
212
+ for (const $typeImport of $typeImports.values()) {
213
+ // resolve path from filePath to svelte-kit/types
214
+ // src/routes/foo/+page.svelte -> .svelte-kit/types/foo/$types.d.ts
215
+ const routesFolder = document.config?.kit?.files?.routes || 'src/routes';
216
+ const relativeFileName = filePath.split(routesFolder)[1]?.slice(1);
217
+ if (relativeFileName) {
218
+ const relativePath = (0, path_1.dirname)(relativeFileName) === '.' ? '' : `${(0, path_1.dirname)(relativeFileName)}/`;
219
+ const modifiedSource = $typeImport.data.source.split('.svelte-kit/types')[0] +
220
+ // note the missing .d.ts at the end - TS wants it that way for some reason
221
+ `.svelte-kit/types/${routesFolder}/${relativePath}$types`;
222
+ completionItems.push({
223
+ ...$typeImport,
224
+ // Ensure it's sorted above the other imports
225
+ sortText: !isNaN(Number($typeImport.sortText))
226
+ ? String(Number($typeImport.sortText) - 1)
227
+ : $typeImport.sortText,
228
+ data: {
229
+ ...$typeImport.data,
230
+ __is_sveltekit$typeImport: true,
231
+ source: modifiedSource,
232
+ data: undefined
233
+ }
234
+ });
235
+ }
236
+ }
237
+ }
238
+ const completionList = vscode_languageserver_1.CompletionList.create(completionItems, !!tsDoc.parserError);
239
+ if (commitCharactersOptions.checkCommitCharacters &&
240
+ commitCharactersOptions.defaultCommitCharacters?.length) {
241
+ const clientSupportsItemsDefault = this.configManager
242
+ .getClientCapabilities()
243
+ ?.textDocument?.completion?.completionList?.itemDefaults?.includes('commitCharacters');
244
+ if (clientSupportsItemsDefault) {
245
+ completionList.itemDefaults = {
246
+ commitCharacters: commitCharactersOptions.defaultCommitCharacters
247
+ };
248
+ }
249
+ else {
250
+ completionList.items.forEach((item) => {
251
+ item.commitCharacters ??= commitCharactersOptions.defaultCommitCharacters;
252
+ });
253
+ }
254
+ }
255
+ this.lastCompletion = { key: document.getFilePath() || '', position, completionList };
256
+ return completionList;
257
+ }
258
+ getWordAtPosition(document, offset) {
259
+ const wordRange = (0, documents_1.getWordRangeAt)(document.getText(), offset, {
260
+ left: /[^\s.]+$/,
261
+ right: /[^\w$:]/
262
+ });
263
+ const range = vscode_languageserver_1.Range.create(document.positionAt(wordRange.start), document.positionAt(wordRange.end));
264
+ return {
265
+ wordRange,
266
+ word: document.getText().slice(wordRange.start, wordRange.end),
267
+ range,
268
+ defaultTextEditRange: wordRange.start === wordRange.end ? undefined : range
269
+ };
270
+ }
271
+ mightBeAtStartTagWhitespace(document, originalOffset) {
272
+ return /\s[\s>/]/.test(document.getText().substring(originalOffset - 1, originalOffset + 1));
273
+ }
274
+ canReuseLastCompletion(lastCompletion, triggerKind, triggerCharacter, document, position) {
275
+ return (!!lastCompletion &&
276
+ lastCompletion.key === document.getFilePath() &&
277
+ lastCompletion.position.line === position.line &&
278
+ ((Math.abs(lastCompletion.position.character - position.character) < 2 &&
279
+ (triggerKind === vscode_languageserver_1.CompletionTriggerKind.TriggerForIncompleteCompletions ||
280
+ // Special case: `.` is a trigger character, but inside import path completions
281
+ // it shouldn't trigger another completion because we can reuse the old one
282
+ (triggerCharacter === '.' &&
283
+ (0, utils_3.isPartOfImportStatement)(document.getText(), position)))) ||
284
+ // `let:` or `on:` -> up to 3 previous characters allowed
285
+ (Math.abs(lastCompletion.position.character - position.character) < 4 &&
286
+ triggerCharacter === ':' &&
287
+ !!(0, documents_1.getNodeIfIsInStartTag)(document.html, document.offsetAt(position)))));
288
+ }
289
+ getExistingImports(document) {
290
+ const rawImports = (0, utils_1.getRegExpMatches)(scriptImportRegex, document.getText()).map((match) => (match[1] ?? match[2]).split(','));
291
+ const tidiedImports = (0, utils_1.flatten)(rawImports).map((match) => match.trim());
292
+ return new Set(tidiedImports);
293
+ }
294
+ getEventAndSlotLetCompletions(componentInfo, attributeContext, defaultTextEditRange) {
295
+ if (componentInfo === null) {
296
+ return [];
297
+ }
298
+ if (attributeContext?.inValue) {
299
+ return [];
300
+ }
301
+ return [
302
+ ...componentInfo
303
+ .getEvents()
304
+ .map((event) => this.componentInfoToCompletionEntry(event, 'on:', undefined, defaultTextEditRange)),
305
+ ...componentInfo
306
+ .getSlotLets()
307
+ .map((slot) => this.componentInfoToCompletionEntry(slot, 'let:', undefined, defaultTextEditRange))
308
+ ];
309
+ }
310
+ getCustomElementCompletions(lang, lsContainer, document, tsDoc, position) {
311
+ const offset = document.offsetAt(position);
312
+ const tag = (0, documents_1.getNodeIfIsInHTMLStartTag)(document.html, offset);
313
+ if (!tag) {
314
+ return;
315
+ }
316
+ const tagNameEnd = tag.start + 1 + (tag.tag?.length ?? 0);
317
+ if (offset > tagNameEnd) {
318
+ return;
319
+ }
320
+ const program = lang.getProgram();
321
+ const sourceFile = program?.getSourceFile(tsDoc.filePath);
322
+ const typeChecker = program?.getTypeChecker();
323
+ if (!typeChecker || !sourceFile) {
324
+ return;
325
+ }
326
+ const typingsNamespace = lsContainer.getTsConfigSvelteOptions().namespace;
327
+ const typingsNamespaceSymbol = this.findTypingsNamespaceSymbol(typingsNamespace, typeChecker, sourceFile);
328
+ if (!typingsNamespaceSymbol) {
329
+ return;
330
+ }
331
+ const elements = typeChecker
332
+ .getExportsOfModule(typingsNamespaceSymbol)
333
+ .find((symbol) => symbol.name === 'IntrinsicElements');
334
+ if (!elements || !(elements.flags & typescript_1.default.SymbolFlags.Interface)) {
335
+ return;
336
+ }
337
+ let tagNames = typeChecker
338
+ .getDeclaredTypeOfSymbol(elements)
339
+ .getProperties()
340
+ .map((p) => typescript_1.default.symbolName(p));
341
+ if (tagNames.length && tag.tag) {
342
+ tagNames = tagNames.filter((name) => name.startsWith(tag.tag ?? ''));
343
+ }
344
+ const replacementRange = (0, documents_1.toRange)(document, tag.start + 1, tagNameEnd);
345
+ return tagNames.map((name) => ({
346
+ label: name,
347
+ kind: vscode_languageserver_1.CompletionItemKind.Property,
348
+ textEdit: vscode_languageserver_1.TextEdit.replace((0, utils_2.cloneRange)(replacementRange), name),
349
+ commitCharacters: []
350
+ }));
351
+ }
352
+ findTypingsNamespaceSymbol(namespaceExpression, typeChecker, sourceFile) {
353
+ if (!namespaceExpression || typeof namespaceExpression !== 'string') {
354
+ return;
355
+ }
356
+ const [first, ...rest] = namespaceExpression.split('.');
357
+ let symbol = typeChecker
358
+ .getSymbolsInScope(sourceFile, typescript_1.default.SymbolFlags.Namespace)
359
+ .find((symbol) => symbol.name === first);
360
+ for (const part of rest) {
361
+ if (!symbol) {
362
+ return;
363
+ }
364
+ symbol = typeChecker.getExportsOfModule(symbol).find((symbol) => symbol.name === part);
365
+ }
366
+ return symbol;
367
+ }
368
+ componentInfoToCompletionEntry(info, prefix, kind, defaultTextEditRange) {
369
+ const name = prefix + info.name;
370
+ return {
371
+ label: name,
372
+ kind,
373
+ sortText: '-1',
374
+ detail: info.name + ': ' + info.type,
375
+ documentation: info.doc && { kind: vscode_languageserver_1.MarkupKind.Markdown, value: info.doc },
376
+ commitCharacters: [],
377
+ textEdit: defaultTextEditRange
378
+ ? vscode_languageserver_1.TextEdit.replace((0, utils_2.cloneRange)(defaultTextEditRange), name)
379
+ : undefined
380
+ };
381
+ }
382
+ getCompletionListForDirectiveOrProps(attributeContext, componentInfo, defaultTextEditRange, eventAndSlotLetCompletions, tsDoc) {
383
+ const props = (!attributeContext?.inValue &&
384
+ componentInfo
385
+ ?.getProps()
386
+ .map((entry) => this.componentInfoToCompletionEntry(entry, '', vscode_languageserver_1.CompletionItemKind.Field, defaultTextEditRange))) ||
387
+ [];
388
+ return vscode_languageserver_1.CompletionList.create([...eventAndSlotLetCompletions, ...props], !!tsDoc.parserError);
389
+ }
390
+ toCompletionItem(snapshot, comp, uri, position, isCompletionInTag, commitCharactersOptions, asStore, existingImports, preferComponents) {
391
+ const completionLabelAndInsert = this.getCompletionLabelAndInsert(snapshot, comp);
392
+ if (!completionLabelAndInsert) {
393
+ return null;
394
+ }
395
+ let { label, insertText, isSvelteComp, isRunesCompletion, replacementSpan } = completionLabelAndInsert;
396
+ // TS may suggest another Svelte component even if there already exists an import
397
+ // with the same name, because under the hood every Svelte component is postfixed
398
+ // with `__SvelteComponent`. In this case, filter out this completion by returning null.
399
+ if (isSvelteComp && existingImports.has(label)) {
400
+ return null;
401
+ }
402
+ // Remove wrong quotes, for example when using --css-props
403
+ if (isCompletionInTag &&
404
+ !insertText &&
405
+ label[0] === '"' &&
406
+ label[label.length - 1] === '"') {
407
+ label = label.slice(1, -1);
408
+ }
409
+ else if (asStore) {
410
+ // only modify label, so that the data property is untouched, which is important so the resolving still works
411
+ label = `$${label}`;
412
+ }
413
+ const textEdit = replacementSpan
414
+ ? vscode_languageserver_1.TextEdit.replace((0, utils_2.convertRange)(snapshot, replacementSpan), insertText ?? label)
415
+ : undefined;
416
+ const labelDetails = comp.labelDetails ??
417
+ (comp.sourceDisplay
418
+ ? {
419
+ description: typescript_1.default.displayPartsToString(comp.sourceDisplay)
420
+ }
421
+ : undefined);
422
+ return {
423
+ label,
424
+ insertText,
425
+ kind: (0, utils_2.scriptElementKindToCompletionItemKind)(comp.kind),
426
+ commitCharacters: this.getCommitCharacters(comp, commitCharactersOptions, isSvelteComp),
427
+ // Make sure svelte component and runes take precedence
428
+ sortText: preferComponents && (isRunesCompletion || isSvelteComp) ? '-1' : comp.sortText,
429
+ preselect: preferComponents && (isRunesCompletion || isSvelteComp) ? true : comp.isRecommended,
430
+ insertTextFormat: comp.isSnippet ? vscode_languageserver_1.InsertTextFormat.Snippet : undefined,
431
+ labelDetails,
432
+ textEdit,
433
+ // pass essential data for resolving completion
434
+ data: {
435
+ name: comp.name,
436
+ source: comp.source,
437
+ data: comp.data,
438
+ uri,
439
+ position
440
+ }
441
+ };
442
+ }
443
+ getCompletionLabelAndInsert(snapshot, comp) {
444
+ let { name, insertText, kindModifiers } = comp;
445
+ const isScriptElement = comp.kind === typescript_1.default.ScriptElementKind.scriptElement;
446
+ const hasModifier = Boolean(comp.kindModifiers);
447
+ const isRunesCompletion = name === '$props' || name === '$state' || name === '$derived' || name === '$effect';
448
+ const isSvelteComp = !isRunesCompletion && (0, utils_2.isGeneratedSvelteComponentName)(name);
449
+ if (isSvelteComp) {
450
+ name = (0, utils_2.changeSvelteComponentName)(name);
451
+ if (this.isExistingSvelteComponentImport(snapshot, name, comp.source)) {
452
+ return null;
453
+ }
454
+ }
455
+ if (isScriptElement && hasModifier) {
456
+ const label = kindModifiers && !name.endsWith(kindModifiers) ? name + kindModifiers : name;
457
+ return {
458
+ insertText: name,
459
+ label,
460
+ isSvelteComp,
461
+ isRunesCompletion
462
+ };
463
+ }
464
+ if (comp.replacementSpan) {
465
+ return {
466
+ label: name,
467
+ isSvelteComp,
468
+ isRunesCompletion,
469
+ insertText: insertText ? (0, utils_2.changeSvelteComponentName)(insertText) : undefined,
470
+ replacementSpan: comp.replacementSpan
471
+ };
472
+ }
473
+ return {
474
+ label: name,
475
+ insertText,
476
+ isSvelteComp,
477
+ isRunesCompletion
478
+ };
479
+ }
480
+ getCommitCharactersOptions(response, tsDoc, position) {
481
+ if ((!(0, utils_2.isInScript)(position, tsDoc) && tsDoc.parserError) || !response) {
482
+ return {
483
+ checkCommitCharacters: false
484
+ };
485
+ }
486
+ const isNewIdentifierLocation = response.isNewIdentifierLocation;
487
+ // TypeScript 5.7+ reused the same array for different completions
488
+ let defaultCommitCharacters = response.defaultCommitCharacters
489
+ ? Array.from(response.defaultCommitCharacters)
490
+ : undefined;
491
+ if (!isNewIdentifierLocation) {
492
+ // This actually always exists although it's optional in the type, at least in ts 5.6,
493
+ // so our commit characters are mostly fallback for older ts versions
494
+ if (defaultCommitCharacters) {
495
+ // this is controlled by a vscode setting that isn't available in the ts server so it isn't added to the language service
496
+ defaultCommitCharacters?.push('(');
497
+ }
498
+ else {
499
+ defaultCommitCharacters = this.commitCharacters;
500
+ }
501
+ }
502
+ return {
503
+ checkCommitCharacters: true,
504
+ defaultCommitCharacters,
505
+ isNewIdentifierLocation
506
+ };
507
+ }
508
+ getCommitCharacters(entry, options, isSvelteComp) {
509
+ // Because Svelte components take precedence, we leave out commit characters to not auto complete
510
+ // in weird places (e.g. when you have foo.filter(a => a)) and get autocomplete for component A,
511
+ // then a commit character of `.` would auto import the component which is not what we want
512
+ if (isSvelteComp) {
513
+ return ['>'];
514
+ }
515
+ // https://github.com/microsoft/vscode/blob/d012408e88ffabd6456c367df4d343654da2eb10/extensions/typescript-language-features/src/languageFeatures/completions.ts#L504
516
+ if (!options.checkCommitCharacters) {
517
+ return undefined;
518
+ }
519
+ const commitCharacters = entry.commitCharacters;
520
+ // Ambient JS word based suggestions
521
+ const skipCommitCharacters = entry.kind === typescript_1.default.ScriptElementKind.warning ||
522
+ entry.kind === typescript_1.default.ScriptElementKind.string;
523
+ if (commitCharacters) {
524
+ if (!options.isNewIdentifierLocation && !skipCommitCharacters) {
525
+ return commitCharacters.concat('(');
526
+ }
527
+ return commitCharacters;
528
+ }
529
+ return skipCommitCharacters ? [] : undefined;
530
+ }
531
+ isExistingSvelteComponentImport(snapshot, name, source) {
532
+ const importStatement = new RegExp(`import ${name} from ["'\`][\\s\\S]+\\.svelte["'\`]`);
533
+ return !!source && !!snapshot.getFullText().match(importStatement);
534
+ }
535
+ fixTextEditRange(wordRange, completionItem, isHandlerCompletion, generatedTextEdit, tsDoc) {
536
+ if (isHandlerCompletion && completionItem.label.startsWith('on:')) {
537
+ completionItem.textEdit = vscode_languageserver_1.TextEdit.replace((0, utils_2.cloneRange)(wordRange), completionItem.label);
538
+ return completionItem;
539
+ }
540
+ const { textEdit } = completionItem;
541
+ if (!textEdit || !vscode_languageserver_1.TextEdit.is(textEdit)) {
542
+ return completionItem;
543
+ }
544
+ if (vscode_languageserver_1.TextEdit.is(generatedTextEdit)) {
545
+ (0, utils_3.checkRangeMappingWithGeneratedSemi)(textEdit.range, generatedTextEdit.range, tsDoc);
546
+ }
547
+ const { newText, range: { start } } = textEdit;
548
+ //If the textEdit is out of the word range of the triggered position
549
+ // vscode would refuse to show the completions
550
+ // split those edits into additionalTextEdit to fix it
551
+ if (start.line !== wordRange.start.line || start.character > wordRange.start.character) {
552
+ return completionItem;
553
+ }
554
+ textEdit.newText = newText.substring(wordRange.start.character - start.character);
555
+ textEdit.range.start = {
556
+ line: start.line,
557
+ character: wordRange.start.character
558
+ };
559
+ completionItem.additionalTextEdits = [
560
+ vscode_languageserver_1.TextEdit.replace({
561
+ start,
562
+ end: {
563
+ line: start.line,
564
+ character: wordRange.start.character
565
+ }
566
+ }, newText.substring(0, wordRange.start.character - start.character))
567
+ ];
568
+ return completionItem;
569
+ }
570
+ /**
571
+ * TypeScript throws a debug assertion error if the importModuleSpecifierEnding config is
572
+ * 'js' and there's an unknown file extension - which is the case for `.svelte`. Therefore
573
+ * rewrite the importModuleSpecifierEnding for this case to silence the error.
574
+ */
575
+ fixUserPreferencesForSvelteComponentImport(userPreferences) {
576
+ if (userPreferences.importModuleSpecifierEnding === 'js') {
577
+ return {
578
+ ...userPreferences,
579
+ importModuleSpecifierEnding: 'index'
580
+ };
581
+ }
582
+ return userPreferences;
583
+ }
584
+ async resolveCompletion(document, completionItem, cancellationToken) {
585
+ const { data: comp } = completionItem;
586
+ const { tsDoc, lang, userPreferences } = await this.lsAndTsDocResolver.getLSAndTSDoc(document);
587
+ const filePath = tsDoc.filePath;
588
+ const formatCodeOptions = await this.configManager.getFormatCodeSettingsForFile(document, tsDoc.scriptKind);
589
+ if (!comp || !filePath || cancellationToken?.isCancellationRequested) {
590
+ return completionItem;
591
+ }
592
+ const is$typeImport = !!comp.__is_sveltekit$typeImport;
593
+ const errorPreventingUserPreferences = comp.source?.endsWith('.svelte')
594
+ ? this.fixUserPreferencesForSvelteComponentImport(userPreferences)
595
+ : userPreferences;
596
+ const detail = lang.getCompletionEntryDetails(filePath, tsDoc.offsetAt(tsDoc.getGeneratedPosition(comp.position)), comp.name, formatCodeOptions, comp.source, errorPreventingUserPreferences, comp.data);
597
+ if (detail) {
598
+ const { detail: itemDetail, documentation: itemDocumentation } = this.getCompletionDocument(tsDoc, detail, is$typeImport);
599
+ // VSCode + tsserver won't have this pop-in effect
600
+ // because tsserver has internal APIs for caching
601
+ // TODO: consider if we should adopt the internal APIs
602
+ if (detail.sourceDisplay && !completionItem.labelDetails) {
603
+ completionItem.labelDetails = {
604
+ description: typescript_1.default.displayPartsToString(detail.sourceDisplay)
605
+ };
606
+ }
607
+ completionItem.detail = itemDetail;
608
+ completionItem.documentation = itemDocumentation;
609
+ }
610
+ const actions = detail?.codeActions;
611
+ const isImport = !!detail?.source;
612
+ if (actions) {
613
+ const edit = [];
614
+ const formatCodeBasis = (0, utils_3.getFormatCodeBasis)(formatCodeOptions);
615
+ for (const action of actions) {
616
+ for (const change of action.changes) {
617
+ edit.push(...this.codeActionChangesToTextEdit(document, tsDoc, change, isImport, comp.position, formatCodeBasis.newLine, is$typeImport));
618
+ }
619
+ }
620
+ completionItem.additionalTextEdits = (completionItem.additionalTextEdits ?? []).concat(edit);
621
+ }
622
+ return completionItem;
623
+ }
624
+ getCompletionDocument(tsDoc, compDetail, is$typeImport) {
625
+ const { sourceDisplay, documentation: tsDocumentation, displayParts, tags } = compDetail;
626
+ let parts = compDetail.codeActions?.map((codeAction) => codeAction.description) ?? [];
627
+ if (sourceDisplay && is$typeImport) {
628
+ const importPath = typescript_1.default.displayPartsToString(sourceDisplay);
629
+ // Take into account Node16 moduleResolution
630
+ parts = parts.map((detail) => detail.replace(importPath, `'./$types${importPath.endsWith('.js') ? '.js' : ''}'`));
631
+ }
632
+ let text = (0, utils_2.changeSvelteComponentName)(typescript_1.default.displayPartsToString(displayParts));
633
+ if (tsDoc.isSvelte5Plus && text.includes('(alias)')) {
634
+ // The info contains both the const and type export along with a bunch of gibberish we want to hide
635
+ if (text.includes('__SvelteComponent_')) {
636
+ // import - remove completely
637
+ text = '';
638
+ }
639
+ else if (text.includes('__sveltets_2_IsomorphicComponent')) {
640
+ // already imported - only keep the last part
641
+ text = text.substring(text.lastIndexOf('import'));
642
+ }
643
+ }
644
+ parts.push(text);
645
+ const markdownDoc = (0, previewer_1.getMarkdownDocumentation)(tsDocumentation, tags);
646
+ const documentation = markdownDoc
647
+ ? { value: markdownDoc, kind: vscode_languageserver_1.MarkupKind.Markdown }
648
+ : undefined;
649
+ return {
650
+ documentation,
651
+ detail: parts.filter(Boolean).join('\n\n')
652
+ };
653
+ }
654
+ codeActionChangesToTextEdit(doc, snapshot, changes, isImport, originalTriggerPosition, newLine, is$typeImport) {
655
+ return changes.textChanges.map((change) => this.codeActionChangeToTextEdit(doc, snapshot, change, isImport, originalTriggerPosition, newLine, is$typeImport));
656
+ }
657
+ codeActionChangeToTextEdit(doc, snapshot, change, isImport, originalTriggerPosition, newLine, is$typeImport, isCombinedCodeAction) {
658
+ change.newText = isCombinedCodeAction
659
+ ? (0, utils_1.modifyLines)(change.newText, (line) => this.fixImportNewText(line, (0, utils_2.isInScript)(originalTriggerPosition, doc), is$typeImport))
660
+ : this.fixImportNewText(change.newText, (0, utils_2.isInScript)(originalTriggerPosition, doc), is$typeImport);
661
+ const scriptTagInfo = snapshot.scriptInfo || snapshot.moduleScriptInfo;
662
+ // no script tag defined yet, add it.
663
+ if (!scriptTagInfo) {
664
+ if (isCombinedCodeAction) {
665
+ return vscode_languageserver_1.TextEdit.insert(vscode_languageserver_1.Position.create(0, 0), change.newText);
666
+ }
667
+ const config = this.configManager.getConfig();
668
+ // Remove the empty line after the script tag because getNewScriptStartTag will always add one
669
+ let newText = change.newText;
670
+ if (newText[0] === '\r') {
671
+ newText = newText.substring(1);
672
+ }
673
+ if (newText[0] === '\n') {
674
+ newText = newText.substring(1);
675
+ }
676
+ return vscode_languageserver_1.TextEdit.replace(beginOfDocumentRange, `${(0, utils_3.getNewScriptStartTag)(config, newLine)}${newText}</script>${newLine}`);
677
+ }
678
+ const { span } = change;
679
+ const virtualRange = (0, utils_2.convertRange)(snapshot, span);
680
+ let range;
681
+ const isNewImport = isImport && virtualRange.start.character === 0;
682
+ // Since new import always can't be mapped, we'll have special treatment here
683
+ // but only hack this when there is multiple line in script
684
+ if (isNewImport && virtualRange.start.line > 1) {
685
+ range = this.mapRangeForNewImport(snapshot, virtualRange);
686
+ }
687
+ else {
688
+ range = (0, documents_1.mapRangeToOriginal)(snapshot, virtualRange);
689
+ }
690
+ // If range is somehow not mapped in parent,
691
+ // the import is mapped wrong or is outside script tag,
692
+ // use script starting point instead.
693
+ // This happens among other things if the completion is the first import of the file.
694
+ if (range.start.line === -1 ||
695
+ (range.start.line === 0 && range.start.character <= 1 && span.length === 0) ||
696
+ !(0, utils_2.isInScript)(range.start, snapshot)) {
697
+ range = (0, utils_2.convertRange)(doc, {
698
+ start: (0, documents_1.isInTag)(originalTriggerPosition, doc.scriptInfo)
699
+ ? snapshot.scriptInfo?.start || scriptTagInfo.start
700
+ : (0, documents_1.isInTag)(originalTriggerPosition, doc.moduleScriptInfo)
701
+ ? snapshot.moduleScriptInfo?.start || scriptTagInfo.start
702
+ : scriptTagInfo.start,
703
+ length: span.length
704
+ });
705
+ }
706
+ // prevent newText from being placed like this: <script>import {} from ''
707
+ const editOffset = doc.offsetAt(range.start);
708
+ if ((editOffset === snapshot.scriptInfo?.start ||
709
+ editOffset === snapshot.moduleScriptInfo?.start) &&
710
+ !change.newText.startsWith('\r\n') &&
711
+ !change.newText.startsWith('\n')) {
712
+ change.newText = newLine + change.newText;
713
+ }
714
+ const after = doc.getText().slice(doc.offsetAt(range.end));
715
+ // typescript add empty line after import when the generated ts file
716
+ // doesn't have new line at the start of the file
717
+ if (after.startsWith('\r\n') || after.startsWith('\n')) {
718
+ change.newText = change.newText.trimEnd() + newLine;
719
+ }
720
+ return vscode_languageserver_1.TextEdit.replace(range, change.newText);
721
+ }
722
+ mapRangeForNewImport(snapshot, virtualRange) {
723
+ const sourceMappableRange = this.offsetLinesAndMovetoStartOfLine(virtualRange, -1);
724
+ const mappableRange = (0, documents_1.mapRangeToOriginal)(snapshot, sourceMappableRange);
725
+ return this.offsetLinesAndMovetoStartOfLine(mappableRange, 1);
726
+ }
727
+ offsetLinesAndMovetoStartOfLine({ start, end }, offsetLines) {
728
+ return vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(start.line + offsetLines, 0), vscode_languageserver_1.Position.create(end.line + offsetLines, 0));
729
+ }
730
+ fixImportNewText(importText, actionTriggeredInScript, is$typeImport) {
731
+ if (is$typeImport && importText.trim().startsWith('import ')) {
732
+ // Take into account Node16 moduleResolution
733
+ return importText.replace(/(['"])(.+?)['"]/, (_match, quote, path) => `${quote}./$types${path.endsWith('.js') ? '.js' : ''}${quote}`);
734
+ }
735
+ const changedName = (0, utils_2.changeSvelteComponentName)(importText);
736
+ if (importText !== changedName || !actionTriggeredInScript) {
737
+ // For some reason, TS sometimes adds the `type` modifier. Remove it
738
+ // in case of Svelte component imports or if import triggered from markup.
739
+ return changedName.replace(' type ', ' ');
740
+ }
741
+ return importText;
742
+ }
743
+ }
744
+ exports.CompletionsProviderImpl = CompletionsProviderImpl;
745
+ const beginOfDocumentRange = vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(0, 0), vscode_languageserver_1.Position.create(0, 0));
746
+ // `import {...} from '..'` or `import ... from '..'`
747
+ // Note: Does not take into account if import is within a comment.
748
+ const scriptImportRegex = /\bimport\s+{([^}]*?)}\s+?from\s+['"`].+?['"`]|\bimport\s+(\w+?)\s+from\s+['"`].+?['"`]/g;
749
+ // Type definitions from svelte-shims.d.ts that shouldn't appear in completion suggestions
750
+ // because they are meant to be used "behind the scenes"
751
+ const svelte2tsxTypes = new Set([
752
+ 'Svelte2TsxComponent',
753
+ 'Svelte2TsxComponentConstructorParameters',
754
+ 'SvelteComponentConstructor',
755
+ 'SvelteActionReturnType',
756
+ 'SvelteTransitionConfig',
757
+ 'SvelteTransitionReturnType',
758
+ 'SvelteAnimationReturnType',
759
+ 'SvelteWithOptionalProps',
760
+ 'SvelteAllProps',
761
+ 'SveltePropsAnyFallback',
762
+ 'SvelteSlotsAnyFallback',
763
+ 'SvelteRestProps',
764
+ 'SvelteSlots',
765
+ 'SvelteStore'
766
+ ]);
767
+ const startsWithUppercase = /^[A-Z]/;
768
+ function createIsValidCompletion(document, position, hasParserError) {
769
+ // Make fallback completions for tags inside the template a bit better
770
+ const isAtStartTag = !(0, documents_1.isInTag)(position, document.scriptInfo) &&
771
+ /<\w*$/.test(document.getText(vscode_languageserver_1.Range.create(position.line, 0, position.line, position.character)));
772
+ const noWrongCompletionAtStartTag = isAtStartTag && hasParserError
773
+ ? (value) => startsWithUppercase.test(value.name)
774
+ : () => true;
775
+ const isNoSvelte2tsxCompletion = (value) => {
776
+ if (value.kindModifiers === 'declare') {
777
+ return !value.name.startsWith('__sveltets_') && !svelte2tsxTypes.has(value.name);
778
+ }
779
+ return !value.name.startsWith('$$_');
780
+ };
781
+ const isCompletionInHTMLStartTag = !!(0, documents_1.getNodeIfIsInHTMLStartTag)(document.html, document.offsetAt(position));
782
+ if (!isCompletionInHTMLStartTag) {
783
+ return isNoSvelte2tsxCompletion;
784
+ }
785
+ // TODO with the new transformation this is ts.ScriptElementKind.memberVariableElement
786
+ // which is also true for all properties of any other object -> how reliably filter this out?
787
+ // ---> another /*ignore*/ pragma?
788
+ // ---> OR: make these lower priority if we find out they are inside a html start tag
789
+ return (value) => isNoSvelte2tsxCompletion(value) && noWrongCompletionAtStartTag(value);
790
+ }
791
+ //# sourceMappingURL=CompletionProvider.js.map