@astrojs/language-server 0.28.3 → 0.29.0

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 (41) hide show
  1. package/dist/core/documents/DocumentMapper.d.ts +13 -7
  2. package/dist/core/documents/DocumentMapper.js +30 -12
  3. package/dist/core/worker/TSXService.d.ts +7 -0
  4. package/dist/core/worker/TSXService.js +12 -0
  5. package/dist/core/worker/TSXWorker.d.ts +1 -0
  6. package/dist/core/worker/TSXWorker.js +9 -0
  7. package/dist/plugins/astro/AstroPlugin.d.ts +3 -2
  8. package/dist/plugins/astro/AstroPlugin.js +5 -1
  9. package/dist/plugins/astro/features/CompletionsProvider.d.ts +2 -2
  10. package/dist/plugins/astro/features/DiagnosticsProvider.d.ts +10 -0
  11. package/dist/plugins/astro/features/DiagnosticsProvider.js +23 -0
  12. package/dist/plugins/typescript/TypeScriptPlugin.d.ts +2 -2
  13. package/dist/plugins/typescript/TypeScriptPlugin.js +8 -10
  14. package/dist/plugins/typescript/astro2tsx.d.ts +2 -4
  15. package/dist/plugins/typescript/astro2tsx.js +4 -91
  16. package/dist/plugins/typescript/features/CodeActionsProvider.js +18 -9
  17. package/dist/plugins/typescript/features/CompletionsProvider.d.ts +2 -2
  18. package/dist/plugins/typescript/features/CompletionsProvider.js +15 -15
  19. package/dist/plugins/typescript/features/DefinitionsProvider.d.ts +1 -1
  20. package/dist/plugins/typescript/features/DefinitionsProvider.js +13 -11
  21. package/dist/plugins/typescript/features/DiagnosticsProvider.d.ts +0 -1
  22. package/dist/plugins/typescript/features/DiagnosticsProvider.js +8 -24
  23. package/dist/plugins/typescript/features/DocumentSymbolsProvider.js +4 -7
  24. package/dist/plugins/typescript/features/FileReferencesProvider.js +4 -5
  25. package/dist/plugins/typescript/features/FoldingRangesProvider.js +6 -2
  26. package/dist/plugins/typescript/features/HoverProvider.js +4 -5
  27. package/dist/plugins/typescript/features/ImplementationsProvider.js +10 -8
  28. package/dist/plugins/typescript/features/InlayHintsProvider.js +3 -4
  29. package/dist/plugins/typescript/features/ReferencesProvider.js +9 -8
  30. package/dist/plugins/typescript/features/SemanticTokenProvider.js +8 -9
  31. package/dist/plugins/typescript/features/SignatureHelpProvider.js +1 -2
  32. package/dist/plugins/typescript/features/TypeDefinitionsProvider.js +7 -7
  33. package/dist/plugins/typescript/features/utils.d.ts +5 -16
  34. package/dist/plugins/typescript/features/utils.js +11 -18
  35. package/dist/plugins/typescript/snapshots/DocumentSnapshot.d.ts +30 -45
  36. package/dist/plugins/typescript/snapshots/DocumentSnapshot.js +50 -43
  37. package/dist/plugins/typescript/snapshots/SnapshotManager.js +0 -4
  38. package/dist/plugins/typescript/snapshots/utils.js +3 -2
  39. package/dist/plugins/typescript/utils.d.ts +2 -2
  40. package/dist/utils.js +3 -2
  41. package/package.json +5 -3
@@ -56,13 +56,14 @@ class CompletionsProviderImpl {
56
56
  this.lastCompletion = undefined;
57
57
  }
58
58
  const html = document.html;
59
- const offset = document.offsetAt(position);
60
- const node = html.findNodeAt(offset);
59
+ const documentOffset = document.offsetAt(position);
60
+ const node = html.findNodeAt(documentOffset);
61
61
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
62
+ const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
62
63
  let filePath = tsDoc.filePath;
63
64
  let completions;
64
- const isCompletionInsideFrontmatter = (0, utils_1.isInsideFrontmatter)(document.getText(), offset);
65
- const isCompletionInsideExpression = (0, utils_1.isInsideExpression)(document.getText(), node.start, offset);
65
+ const isCompletionInsideFrontmatter = (0, utils_1.isInsideFrontmatter)(document.getText(), documentOffset);
66
+ const isCompletionInsideExpression = (0, utils_1.isInsideExpression)(document.getText(), node.start, documentOffset);
66
67
  const tsPreferences = await this.configManager.getTSPreferences(document);
67
68
  const formatOptions = await this.configManager.getTSFormatConfig(document);
68
69
  let scriptTagIndex = undefined;
@@ -105,11 +106,10 @@ class CompletionsProviderImpl {
105
106
  ? vscode_languageserver_1.Range.create(document.positionAt(completions.optionalReplacementSpan.start), document.positionAt(completions.optionalReplacementSpan.start + completions.optionalReplacementSpan.length))
106
107
  : undefined;
107
108
  const wordRangeStartPosition = wordRange?.start;
108
- const fragment = await tsDoc.createFragment();
109
109
  const existingImports = this.getExistingImports(document);
110
110
  const completionItems = completions.entries
111
111
  .filter((completion) => this.isValidCompletion(completion, this.ts))
112
- .map((entry) => this.toCompletionItem(fragment, entry, filePath, offset, isCompletionInsideFrontmatter, scriptTagIndex, existingImports))
112
+ .map((entry) => this.toCompletionItem(tsDoc, entry, filePath, offset, isCompletionInsideFrontmatter, scriptTagIndex, existingImports))
113
113
  .filter(utils_2.isNotNullOrUndefined)
114
114
  .map((comp) => this.fixTextEditRange(wordRangeStartPosition, comp));
115
115
  const completionList = vscode_languageserver_1.CompletionList.create(completionItems, true);
@@ -123,7 +123,6 @@ class CompletionsProviderImpl {
123
123
  if (!data || !data.filePath || cancellationToken?.isCancellationRequested) {
124
124
  return item;
125
125
  }
126
- const fragment = await tsDoc.createFragment();
127
126
  const detail = lang.getCompletionEntryDetails(data.filePath, // fileName
128
127
  data.offset, // position
129
128
  data.originalItem.name, // entryName
@@ -154,17 +153,18 @@ class CompletionsProviderImpl {
154
153
  for (const change of action.changes) {
155
154
  if (isInsideScriptTag) {
156
155
  change.textChanges.forEach((textChange) => {
157
- textChange.span.start = fragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(textChange.span.start)));
156
+ const originalPosition = scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(textChange.span.start));
157
+ textChange.span.start = tsDoc.offsetAt(tsDoc.getGeneratedPosition(originalPosition));
158
158
  });
159
159
  }
160
- edit.push(...change.textChanges.map((textChange) => codeActionChangeToTextEdit(document, fragment, isInsideScriptTag, textChange, this.ts)));
160
+ edit.push(...change.textChanges.map((textChange) => codeActionChangeToTextEdit(document, tsDoc, isInsideScriptTag, textChange, this.ts)));
161
161
  }
162
162
  }
163
163
  item.additionalTextEdits = (item.additionalTextEdits ?? []).concat(edit);
164
164
  }
165
165
  return item;
166
166
  }
167
- toCompletionItem(fragment, comp, filePath, offset, insideFrontmatter, scriptTagIndex, existingImports) {
167
+ toCompletionItem(snapshot, comp, filePath, offset, insideFrontmatter, scriptTagIndex, existingImports) {
168
168
  let item = vscode_languageserver_protocol_1.CompletionItem.create(comp.name);
169
169
  const isAstroComponent = this.isAstroComponentImport(comp.name);
170
170
  const isImport = comp.insertText?.includes('import');
@@ -212,13 +212,13 @@ class CompletionsProviderImpl {
212
212
  item.insertText = comp.insertText ? (0, utils_3.removeAstroComponentSuffix)(comp.insertText) : undefined;
213
213
  item.insertTextFormat = comp.isSnippet ? vscode_languageserver_1.InsertTextFormat.Snippet : vscode_languageserver_1.InsertTextFormat.PlainText;
214
214
  item.textEdit = comp.replacementSpan
215
- ? vscode_languageserver_1.TextEdit.replace((0, utils_3.convertRange)(fragment, comp.replacementSpan), item.insertText ?? item.label)
215
+ ? vscode_languageserver_1.TextEdit.replace((0, utils_3.convertRange)(snapshot, comp.replacementSpan), item.insertText ?? item.label)
216
216
  : undefined;
217
217
  }
218
218
  return {
219
219
  ...item,
220
220
  data: {
221
- uri: fragment.getURL(),
221
+ uri: snapshot.getURL(),
222
222
  filePath,
223
223
  scriptTagIndex,
224
224
  offset,
@@ -303,12 +303,12 @@ class CompletionsProviderImpl {
303
303
  }
304
304
  }
305
305
  exports.CompletionsProviderImpl = CompletionsProviderImpl;
306
- function codeActionChangeToTextEdit(document, fragment, isInsideScriptTag, change, ts) {
306
+ function codeActionChangeToTextEdit(document, snapshot, isInsideScriptTag, change, ts) {
307
307
  change.newText = (0, utils_3.removeAstroComponentSuffix)(change.newText);
308
308
  const { span } = change;
309
309
  let range;
310
- const virtualRange = (0, utils_3.convertRange)(fragment, span);
311
- range = (0, documents_1.mapRangeToOriginal)(fragment, virtualRange);
310
+ const virtualRange = (0, utils_3.convertRange)(snapshot, span);
311
+ range = (0, documents_1.mapRangeToOriginal)(snapshot, virtualRange);
312
312
  if (!isInsideScriptTag) {
313
313
  // If we don't have a frontmatter already, create one with the import
314
314
  const frontmatterState = document.astroMeta.frontmatter.state;
@@ -1,5 +1,5 @@
1
1
  import { LocationLink, Position } from 'vscode-languageserver-types';
2
- import type { AstroDocument } from '../../../core/documents';
2
+ import { AstroDocument } from '../../../core/documents';
3
3
  import type { DefinitionsProvider } from '../../interfaces';
4
4
  import type { LanguageServiceManager } from '../LanguageServiceManager';
5
5
  export declare class DefinitionsProviderImpl implements DefinitionsProvider {
@@ -2,6 +2,7 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DefinitionsProviderImpl = void 0;
4
4
  const vscode_languageserver_types_1 = require("vscode-languageserver-types");
5
+ const documents_1 = require("../../../core/documents");
5
6
  const utils_1 = require("../../../utils");
6
7
  const utils_2 = require("../utils");
7
8
  const utils_3 = require("./utils");
@@ -11,9 +12,8 @@ class DefinitionsProviderImpl {
11
12
  }
12
13
  async getDefinitions(document, position) {
13
14
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
14
- const mainFragment = await tsDoc.createFragment();
15
- const fragmentPosition = mainFragment.getGeneratedPosition(position);
16
- const fragmentOffset = mainFragment.offsetAt(fragmentPosition);
15
+ const fragmentPosition = tsDoc.getGeneratedPosition(position);
16
+ const fragmentOffset = tsDoc.offsetAt(fragmentPosition);
17
17
  let defs;
18
18
  const html = document.html;
19
19
  const offset = document.offsetAt(position);
@@ -26,11 +26,11 @@ class DefinitionsProviderImpl {
26
26
  const isInSameFile = def.fileName === scriptFilePath;
27
27
  def.fileName = isInSameFile ? tsDoc.filePath : def.fileName;
28
28
  if (isInSameFile) {
29
- def.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(def.textSpan.start)));
29
+ def.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(def.textSpan, scriptTagSnapshot, tsDoc);
30
30
  }
31
31
  return def;
32
32
  });
33
- defs.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(defs.textSpan.start)));
33
+ defs.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(defs.textSpan, scriptTagSnapshot, tsDoc);
34
34
  }
35
35
  }
36
36
  else {
@@ -39,16 +39,18 @@ class DefinitionsProviderImpl {
39
39
  if (!defs || !defs.definitions) {
40
40
  return [];
41
41
  }
42
- const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
43
- docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
42
+ const snapshots = new utils_3.SnapshotMap(this.languageServiceManager);
43
+ snapshots.set(tsDoc.filePath, tsDoc);
44
44
  const result = await Promise.all(defs.definitions.map(async (def) => {
45
- const { fragment, snapshot } = await docs.retrieve(def.fileName);
45
+ const snapshot = await snapshots.retrieve(def.fileName);
46
46
  const fileName = (0, utils_2.ensureRealFilePath)(def.fileName);
47
47
  // For Astro, Svelte and Vue, the position is wrongly mapped to the end of the file due to the TSX output
48
48
  // So we'll instead redirect to the beginning of the file
49
- const isFramework = (0, utils_2.isFrameworkFilePath)(def.fileName) || (0, utils_2.isAstroFilePath)(def.fileName);
50
- const textSpan = isFramework && tsDoc.filePath !== def.fileName ? { start: 0, length: 0 } : def.textSpan;
51
- return vscode_languageserver_types_1.LocationLink.create((0, utils_1.pathToUrl)(fileName), (0, utils_2.convertToLocationRange)(fragment, textSpan), (0, utils_2.convertToLocationRange)(fragment, textSpan), (0, utils_2.convertToLocationRange)(mainFragment, defs.textSpan));
49
+ const isFramework = ((0, utils_2.isFrameworkFilePath)(def.fileName) || (0, utils_2.isAstroFilePath)(def.fileName)) && tsDoc.filePath !== def.fileName;
50
+ const targetRange = isFramework
51
+ ? (0, utils_2.convertRange)(document, { start: 0, length: 0 })
52
+ : (0, utils_2.convertToLocationRange)(snapshot, def.textSpan);
53
+ return vscode_languageserver_types_1.LocationLink.create((0, utils_1.pathToUrl)(fileName), targetRange, targetRange, (0, utils_2.convertToLocationRange)(tsDoc, defs.textSpan));
52
54
  }));
53
55
  return result.filter(utils_1.isNotNullOrUndefined);
54
56
  }
@@ -7,7 +7,6 @@ export declare enum DiagnosticCodes {
7
7
  SPREAD_EXPECTED = 1005,
8
8
  IS_NOT_A_MODULE = 2306,
9
9
  DUPLICATED_JSX_ATTRIBUTES = 17001,
10
- MUST_HAVE_PARENT_ELEMENT = 2657,
11
10
  CANT_RETURN_OUTSIDE_FUNC = 1108,
12
11
  ISOLATED_MODULE_COMPILE_ERR = 1208,
13
12
  TYPE_NOT_ASSIGNABLE = 2322,
@@ -12,7 +12,6 @@ var DiagnosticCodes;
12
12
  DiagnosticCodes[DiagnosticCodes["SPREAD_EXPECTED"] = 1005] = "SPREAD_EXPECTED";
13
13
  DiagnosticCodes[DiagnosticCodes["IS_NOT_A_MODULE"] = 2306] = "IS_NOT_A_MODULE";
14
14
  DiagnosticCodes[DiagnosticCodes["DUPLICATED_JSX_ATTRIBUTES"] = 17001] = "DUPLICATED_JSX_ATTRIBUTES";
15
- DiagnosticCodes[DiagnosticCodes["MUST_HAVE_PARENT_ELEMENT"] = 2657] = "MUST_HAVE_PARENT_ELEMENT";
16
15
  DiagnosticCodes[DiagnosticCodes["CANT_RETURN_OUTSIDE_FUNC"] = 1108] = "CANT_RETURN_OUTSIDE_FUNC";
17
16
  DiagnosticCodes[DiagnosticCodes["ISOLATED_MODULE_COMPILE_ERR"] = 1208] = "ISOLATED_MODULE_COMPILE_ERR";
18
17
  DiagnosticCodes[DiagnosticCodes["TYPE_NOT_ASSIGNABLE"] = 2322] = "TYPE_NOT_ASSIGNABLE";
@@ -31,7 +30,11 @@ class DiagnosticsProviderImpl {
31
30
  return [];
32
31
  }
33
32
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
34
- const fragment = await tsDoc.createFragment();
33
+ // If we have compiler errors, our TSX isn't valid so don't bother showing TS errors
34
+ if (tsDoc.compilerDiagnostics.filter((diag) => diag.severity === vscode_languageserver_1.DiagnosticSeverity.Error).length >
35
+ 0) {
36
+ return [];
37
+ }
35
38
  let scriptDiagnostics = [];
36
39
  document.scriptTags.forEach((scriptTag) => {
37
40
  const { filePath: scriptFilePath, snapshot: scriptTagSnapshot } = (0, utils_1.getScriptTagSnapshot)(tsDoc, document, scriptTag.container);
@@ -71,7 +74,7 @@ class DiagnosticsProviderImpl {
71
74
  code: diagnostic.code,
72
75
  tags: getDiagnosticTag(diagnostic),
73
76
  }))
74
- .map(mapRange(fragment, document)),
77
+ .map(mapRange(tsDoc, document)),
75
78
  ...scriptDiagnostics,
76
79
  ]
77
80
  .filter((diag) => {
@@ -79,8 +82,6 @@ class DiagnosticsProviderImpl {
79
82
  // Make sure the diagnostic is inside the document and not in generated code
80
83
  diag.range.start.line <= document.lineCount &&
81
84
  hasNoNegativeLines(diag) &&
82
- isNoJSXMustHaveOneParent(diag) &&
83
- isNoSpreadExpected(diag, document) &&
84
85
  isNoCantReturnOutsideFunction(diag) &&
85
86
  isNoIsolatedModuleError(diag) &&
86
87
  isNoJsxCannotHaveMultipleAttrsError(diag));
@@ -151,9 +152,9 @@ function diagnosticIsWithinBoundaries(sourceFile, boundaries, diagnostic, ts) {
151
152
  function isNoWithinBoundary(boundaries, diagnostic, ts) {
152
153
  return !diagnosticIsWithinBoundaries(undefined, boundaries, diagnostic, ts);
153
154
  }
154
- function mapRange(fragment, _document) {
155
+ function mapRange(snapshot, _document) {
155
156
  return (diagnostic) => {
156
- let range = (0, documents_1.mapRangeToOriginal)(fragment, diagnostic.range);
157
+ let range = (0, documents_1.mapRangeToOriginal)(snapshot, diagnostic.range);
157
158
  return { ...diagnostic, range };
158
159
  };
159
160
  }
@@ -171,23 +172,6 @@ function hasNoNegativeLines(diagnostic) {
171
172
  function isNoJsxCannotHaveMultipleAttrsError(diagnostic) {
172
173
  return diagnostic.code !== DiagnosticCodes.DUPLICATED_JSX_ATTRIBUTES;
173
174
  }
174
- /** Astro allows component with multiple root elements */
175
- function isNoJSXMustHaveOneParent(diagnostic) {
176
- return diagnostic.code !== DiagnosticCodes.MUST_HAVE_PARENT_ELEMENT;
177
- }
178
- /**
179
- * When using the shorthand syntax for props TSX expects you to use the spread operator
180
- * Since the shorthand syntax works differently in Astro and this is not required, hide this message
181
- * However, the error code used here is quite generic, as such we need to make we only ignore in valid cases
182
- */
183
- function isNoSpreadExpected(diagnostic, document) {
184
- if (diagnostic.code === DiagnosticCodes.SPREAD_EXPECTED &&
185
- diagnostic.message.includes('...') &&
186
- document.offsetAt(diagnostic.range.start) > (document.astroMeta.frontmatter.endOffset ?? 0)) {
187
- return false;
188
- }
189
- return true;
190
- }
191
175
  /**
192
176
  * Ignore "Can't return outside of function body"
193
177
  * Since the frontmatter is at the top level, users trying to return a Response for SSR mode run into this
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.DocumentSymbolsProviderImpl = void 0;
4
4
  const vscode_languageserver_types_1 = require("vscode-languageserver-types");
5
- const documents_1 = require("../../../core/documents");
6
5
  const utils_1 = require("../utils");
7
6
  class DocumentSymbolsProviderImpl {
8
7
  constructor(languageServiceManager) {
@@ -11,13 +10,12 @@ class DocumentSymbolsProviderImpl {
11
10
  }
12
11
  async getDocumentSymbols(document) {
13
12
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
14
- const fragment = await tsDoc.createFragment();
15
13
  const navTree = lang.getNavigationTree(tsDoc.filePath + '?documentSymbols');
16
14
  if (!navTree) {
17
15
  return [];
18
16
  }
19
17
  const symbols = [];
20
- this.collectSymbols(navTree, fragment, undefined, (symbol) => symbols.push(symbol));
18
+ this.collectSymbols(navTree, document, undefined, (symbol) => symbols.push(symbol));
21
19
  const originalContainerName = symbols[0].name;
22
20
  const result = [];
23
21
  // Add a "Frontmatter" namespace for the frontmatter if we have a closed one
@@ -27,7 +25,6 @@ class DocumentSymbolsProviderImpl {
27
25
  // Add a "Template" namespace for everything under the frontmatter
28
26
  result.push(vscode_languageserver_types_1.SymbolInformation.create('Template', vscode_languageserver_types_1.SymbolKind.Namespace, vscode_languageserver_types_1.Range.create(document.positionAt(document.astroMeta.frontmatter.endOffset ?? 0), document.positionAt(document.getTextLength())), document.getURL()));
29
27
  for (let symbol of symbols.splice(1)) {
30
- symbol = (0, documents_1.mapSymbolInformationToOriginal)(fragment, symbol);
31
28
  if (document.offsetAt(symbol.location.range.end) >= (document.astroMeta.content.firstNonWhitespaceOffset ?? 0)) {
32
29
  if (symbol.containerName === originalContainerName) {
33
30
  symbol.containerName = 'Template';
@@ -48,9 +45,9 @@ class DocumentSymbolsProviderImpl {
48
45
  }
49
46
  return result;
50
47
  }
51
- collectSymbols(item, fragment, container, cb) {
48
+ collectSymbols(item, document, container, cb) {
52
49
  for (const span of item.spans) {
53
- const symbol = vscode_languageserver_types_1.SymbolInformation.create(item.text, (0, utils_1.symbolKindFromString)(item.kind), vscode_languageserver_types_1.Range.create(fragment.positionAt(span.start), fragment.positionAt(span.start + span.length)), fragment.getURL(), container);
50
+ const symbol = vscode_languageserver_types_1.SymbolInformation.create(item.text, (0, utils_1.symbolKindFromString)(item.kind), vscode_languageserver_types_1.Range.create(document.positionAt(span.start), document.positionAt(span.start + span.length)), document.getURL(), container);
54
51
  // TypeScript gives us kind modifiers as a string instead of an array
55
52
  const kindModifiers = new Set(item.kindModifiers.split(/,|\s+/g));
56
53
  if (kindModifiers.has(this.ts.ScriptElementKindModifier.deprecatedModifier)) {
@@ -62,7 +59,7 @@ class DocumentSymbolsProviderImpl {
62
59
  }
63
60
  if (item.childItems) {
64
61
  for (const child of item.childItems) {
65
- this.collectSymbols(child, fragment, item.text, cb);
62
+ this.collectSymbols(child, document, item.text, cb);
66
63
  }
67
64
  }
68
65
  }
@@ -11,16 +11,15 @@ class FileReferencesProviderImpl {
11
11
  }
12
12
  async fileReferences(document) {
13
13
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
14
- const mainFragment = await tsDoc.createFragment();
15
14
  const references = lang.getFileReferences(tsDoc.filePath);
16
15
  if (!references) {
17
16
  return null;
18
17
  }
19
- const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
20
- docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
18
+ const snapshots = new utils_3.SnapshotMap(this.languageServiceManager);
19
+ snapshots.set(tsDoc.filePath, tsDoc);
21
20
  const locations = await Promise.all(references.map(async (ref) => {
22
- const defDoc = await docs.retrieveFragment(ref.fileName);
23
- return vscode_languageserver_1.Location.create((0, utils_1.pathToUrl)(ref.fileName), (0, utils_2.convertToLocationRange)(defDoc, ref.textSpan));
21
+ const snapshot = await snapshots.retrieve(ref.fileName);
22
+ return vscode_languageserver_1.Location.create((0, utils_1.pathToUrl)(ref.fileName), (0, utils_2.convertToLocationRange)(snapshot, ref.textSpan));
24
23
  }));
25
24
  return locations;
26
25
  }
@@ -27,13 +27,17 @@ class FoldingRangesProviderImpl {
27
27
  });
28
28
  const foldingRanges = [];
29
29
  for (const span of [...outliningSpans, ...scriptOutliningSpans]) {
30
- const start = document.positionAt(span.textSpan.start);
31
- const end = adjustFoldingEnd(start, document.positionAt(span.textSpan.start + span.textSpan.length), document);
30
+ const start = tsDoc.getOriginalPosition(tsDoc.positionAt(span.textSpan.start));
31
+ const end = adjustFoldingEnd(start, document.positionAt(document.offsetAt(start) + span.textSpan.length), document);
32
32
  // When using this method for generating folding ranges, TypeScript tend to return some
33
33
  // one line / one character ones that we should be able to safely ignore
34
34
  if (start.line === end.line && start.character === end.character) {
35
35
  continue;
36
36
  }
37
+ // Ignore folding ranges that are from unmapped regions
38
+ if (start.line < 0 || end.line < 0) {
39
+ continue;
40
+ }
37
41
  foldingRanges.push(vscode_languageserver_1.FoldingRange.create(start.line, end.line, start.character, end.character, this.transformFoldingRangeKind(span.kind)));
38
42
  }
39
43
  return foldingRanges;
@@ -12,8 +12,7 @@ class HoverProviderImpl {
12
12
  }
13
13
  async doHover(document, position) {
14
14
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
15
- const fragment = await tsDoc.createFragment();
16
- const offset = fragment.offsetAt(fragment.getGeneratedPosition(position));
15
+ const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
17
16
  const html = document.html;
18
17
  const documentOffset = document.offsetAt(position);
19
18
  const node = html.findNodeAt(documentOffset);
@@ -22,7 +21,7 @@ class HoverProviderImpl {
22
21
  const { snapshot: scriptTagSnapshot, filePath: scriptFilePath, offset: scriptOffset, } = (0, utils_1.getScriptTagSnapshot)(tsDoc, document, node, position);
23
22
  info = lang.getQuickInfoAtPosition(scriptFilePath, scriptOffset);
24
23
  if (info) {
25
- info.textSpan.start = fragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(info.textSpan.start)));
24
+ info.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(info.textSpan, scriptTagSnapshot, tsDoc);
26
25
  }
27
26
  }
28
27
  else {
@@ -42,8 +41,8 @@ class HoverProviderImpl {
42
41
  const contents = ['```typescript', declaration, '```']
43
42
  .concat(documentation ? ['---', documentation] : [])
44
43
  .join('\n');
45
- return (0, documents_1.mapObjWithRangeToOriginal)(fragment, {
46
- range: (0, utils_1.convertRange)(fragment, textSpan),
44
+ return (0, documents_1.mapObjWithRangeToOriginal)(tsDoc, {
45
+ range: (0, utils_1.convertRange)(tsDoc, textSpan),
47
46
  contents,
48
47
  });
49
48
  }
@@ -12,8 +12,10 @@ class ImplementationsProviderImpl {
12
12
  }
13
13
  async getImplementation(document, position) {
14
14
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
15
- const mainFragment = await tsDoc.createFragment();
16
- const offset = mainFragment.offsetAt(mainFragment.getGeneratedPosition(position));
15
+ const fragmentPosition = tsDoc.getGeneratedPosition(position);
16
+ const fragmentOffset = tsDoc.offsetAt(fragmentPosition);
17
+ const html = document.html;
18
+ const offset = document.offsetAt(position);
17
19
  const node = document.html.findNodeAt(offset);
18
20
  let implementations;
19
21
  if (node.tag === 'script') {
@@ -24,23 +26,23 @@ class ImplementationsProviderImpl {
24
26
  const isInSameFile = impl.fileName === scriptFilePath;
25
27
  impl.fileName = isInSameFile ? tsDoc.filePath : impl.fileName;
26
28
  if (isInSameFile) {
27
- impl.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(impl.textSpan.start)));
29
+ impl.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(impl.textSpan, scriptTagSnapshot, tsDoc);
28
30
  }
29
31
  return impl;
30
32
  });
31
33
  }
32
34
  }
33
35
  else {
34
- implementations = lang.getImplementationAtPosition(tsDoc.filePath, offset);
36
+ implementations = lang.getImplementationAtPosition(tsDoc.filePath, fragmentOffset);
35
37
  }
36
- const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
37
- docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
38
+ const snapshots = new utils_3.SnapshotMap(this.languageServiceManager);
39
+ snapshots.set(tsDoc.filePath, tsDoc);
38
40
  if (!implementations) {
39
41
  return null;
40
42
  }
41
43
  const result = await Promise.all(implementations.map(async (implementation) => {
42
- const { fragment } = await docs.retrieve(implementation.fileName);
43
- const range = (0, documents_1.mapRangeToOriginal)(fragment, (0, utils_2.convertRange)(fragment, implementation.textSpan));
44
+ const snapshot = await snapshots.retrieve(implementation.fileName);
45
+ const range = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, implementation.textSpan));
44
46
  if (range.start.line >= 0 && range.end.line >= 0) {
45
47
  return vscode_languageserver_types_1.Location.create((0, utils_1.pathToUrl)(implementation.fileName), range);
46
48
  }
@@ -11,13 +11,12 @@ class InlayHintsProviderImpl {
11
11
  }
12
12
  async getInlayHints(document, range) {
13
13
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
14
- const fragment = await tsDoc.createFragment();
15
- const start = fragment.offsetAt(fragment.getGeneratedPosition(range.start));
16
- const end = fragment.offsetAt(fragment.getGeneratedPosition(range.end));
14
+ const start = tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.start));
15
+ const end = tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.end));
17
16
  const tsPreferences = await this.configManager.getTSPreferences(document);
18
17
  const inlayHints = lang.provideInlayHints(tsDoc.filePath, { start, length: end - start }, tsPreferences);
19
18
  return inlayHints.map((hint) => {
20
- const result = vscode_languageserver_1.InlayHint.create(fragment.getOriginalPosition(fragment.positionAt(hint.position)), hint.text, hint.kind === this.ts.InlayHintKind.Type
19
+ const result = vscode_languageserver_1.InlayHint.create(tsDoc.getOriginalPosition(tsDoc.positionAt(hint.position)), hint.text, hint.kind === this.ts.InlayHintKind.Type
21
20
  ? vscode_languageserver_types_1.InlayHintKind.Type
22
21
  : hint.kind === this.ts.InlayHintKind.Parameter
23
22
  ? vscode_languageserver_types_1.InlayHintKind.Parameter
@@ -12,8 +12,9 @@ class FindReferencesProviderImpl {
12
12
  }
13
13
  async findReferences(document, position, context) {
14
14
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
15
- const mainFragment = await tsDoc.createFragment();
16
- const offset = mainFragment.offsetAt(mainFragment.getGeneratedPosition(position));
15
+ const fragmentPosition = tsDoc.getGeneratedPosition(position);
16
+ const fragmentOffset = tsDoc.offsetAt(fragmentPosition);
17
+ const offset = document.offsetAt(position);
17
18
  const node = document.html.findNodeAt(offset);
18
19
  let references;
19
20
  if (node.tag === 'script') {
@@ -24,26 +25,26 @@ class FindReferencesProviderImpl {
24
25
  const isInSameFile = ref.fileName === scriptFilePath;
25
26
  ref.fileName = isInSameFile ? tsDoc.filePath : ref.fileName;
26
27
  if (isInSameFile) {
27
- ref.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(ref.textSpan.start)));
28
+ ref.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(ref.textSpan, scriptTagSnapshot, tsDoc);
28
29
  }
29
30
  return ref;
30
31
  });
31
32
  }
32
33
  }
33
34
  else {
34
- references = lang.getReferencesAtPosition(tsDoc.filePath, offset);
35
+ references = lang.getReferencesAtPosition(tsDoc.filePath, fragmentOffset);
35
36
  }
36
37
  if (!references) {
37
38
  return null;
38
39
  }
39
- const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
40
- docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
40
+ const snapshots = new utils_3.SnapshotMap(this.languageServiceManager);
41
+ snapshots.set(tsDoc.filePath, tsDoc);
41
42
  const result = await Promise.all(references.map(async (reference) => {
42
43
  if (!context.includeDeclaration) {
43
44
  return null;
44
45
  }
45
- const { fragment } = await docs.retrieve(reference.fileName);
46
- const range = (0, documents_1.mapRangeToOriginal)(fragment, (0, utils_2.convertRange)(fragment, reference.textSpan));
46
+ const snapshot = await snapshots.retrieve(reference.fileName);
47
+ const range = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, reference.textSpan));
47
48
  if (range.start.line >= 0 && range.end.line >= 0) {
48
49
  return vscode_languageserver_types_1.Location.create((0, utils_1.pathToUrl)(reference.fileName), range);
49
50
  }
@@ -10,17 +10,16 @@ class SemanticTokensProviderImpl {
10
10
  }
11
11
  async getSemanticTokens(document, range, cancellationToken) {
12
12
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
13
- const fragment = (await tsDoc.createFragment());
14
13
  if (cancellationToken?.isCancellationRequested) {
15
14
  return null;
16
15
  }
17
- const start = range ? fragment.offsetAt(fragment.getGeneratedPosition(range.start)) : 0;
16
+ const start = range ? tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.start)) : 0;
18
17
  const { spans } = lang.getEncodedSemanticClassifications(tsDoc.filePath, {
19
18
  start,
20
19
  length: range
21
- ? fragment.offsetAt(fragment.getGeneratedPosition(range.end)) - start
20
+ ? tsDoc.offsetAt(tsDoc.getGeneratedPosition(range.end)) - start
22
21
  : // We don't want tokens for things added by astro2tsx
23
- fragment.text.lastIndexOf('export default function ') || fragment.text.length,
22
+ tsDoc.getFullText().lastIndexOf('export default function ') || tsDoc.getLength(),
24
23
  }, this.ts.SemanticClassificationFormat.TwentyTwenty);
25
24
  const tokens = [];
26
25
  let i = 0;
@@ -28,7 +27,7 @@ class SemanticTokensProviderImpl {
28
27
  const offset = spans[i++];
29
28
  const generatedLength = spans[i++];
30
29
  const classification = spans[i++];
31
- const originalPosition = this.mapToOrigin(document, fragment, offset, generatedLength);
30
+ const originalPosition = this.mapToOrigin(document, tsDoc, offset, generatedLength);
32
31
  if (!originalPosition) {
33
32
  continue;
34
33
  }
@@ -50,12 +49,12 @@ class SemanticTokensProviderImpl {
50
49
  const build = builder.build();
51
50
  return build;
52
51
  }
53
- mapToOrigin(document, fragment, generatedOffset, generatedLength) {
52
+ mapToOrigin(document, snapshot, generatedOffset, generatedLength) {
54
53
  const range = {
55
- start: fragment.positionAt(generatedOffset),
56
- end: fragment.positionAt(generatedOffset + generatedLength),
54
+ start: snapshot.positionAt(generatedOffset),
55
+ end: snapshot.positionAt(generatedOffset + generatedLength),
57
56
  };
58
- const { start: startPosition, end: endPosition } = (0, documents_1.mapRangeToOriginal)(fragment, range);
57
+ const { start: startPosition, end: endPosition } = (0, documents_1.mapRangeToOriginal)(snapshot, range);
59
58
  if (startPosition.line < 0 || endPosition.line < 0) {
60
59
  return;
61
60
  }
@@ -11,11 +11,10 @@ class SignatureHelpProviderImpl {
11
11
  }
12
12
  async getSignatureHelp(document, position, context, cancellationToken) {
13
13
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
14
- const fragment = await tsDoc.createFragment();
15
14
  if (cancellationToken?.isCancellationRequested) {
16
15
  return null;
17
16
  }
18
- const offset = fragment.offsetAt(fragment.getGeneratedPosition(position));
17
+ const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
19
18
  const node = document.html.findNodeAt(offset);
20
19
  let info;
21
20
  const triggerReason = this.toTsTriggerReason(context);
@@ -12,8 +12,8 @@ class TypeDefinitionsProviderImpl {
12
12
  }
13
13
  async getTypeDefinitions(document, position) {
14
14
  const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
15
- const mainFragment = await tsDoc.createFragment();
16
- const fragmentOffset = mainFragment.offsetAt(mainFragment.getGeneratedPosition(position));
15
+ const fragmentPosition = tsDoc.getGeneratedPosition(position);
16
+ const fragmentOffset = tsDoc.offsetAt(fragmentPosition);
17
17
  const html = document.html;
18
18
  const offset = document.offsetAt(position);
19
19
  const node = html.findNodeAt(offset);
@@ -26,7 +26,7 @@ class TypeDefinitionsProviderImpl {
26
26
  const isInSameFile = def.fileName === scriptFilePath;
27
27
  def.fileName = isInSameFile ? tsDoc.filePath : def.fileName;
28
28
  if (isInSameFile) {
29
- def.textSpan.start = mainFragment.offsetAt(scriptTagSnapshot.getOriginalPosition(scriptTagSnapshot.positionAt(def.textSpan.start)));
29
+ def.textSpan.start = (0, documents_1.mapScriptSpanStartToSnapshot)(def.textSpan, scriptTagSnapshot, tsDoc);
30
30
  }
31
31
  return def;
32
32
  });
@@ -35,15 +35,15 @@ class TypeDefinitionsProviderImpl {
35
35
  else {
36
36
  typeDefs = lang.getTypeDefinitionAtPosition(tsDoc.filePath, fragmentOffset);
37
37
  }
38
- const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
39
- docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
38
+ const snapshots = new utils_3.SnapshotMap(this.languageServiceManager);
39
+ snapshots.set(tsDoc.filePath, tsDoc);
40
40
  if (!typeDefs) {
41
41
  return [];
42
42
  }
43
43
  const result = await Promise.all(typeDefs.map(async (typeDef) => {
44
- const { fragment } = await docs.retrieve(typeDef.fileName);
44
+ const snapshot = await snapshots.retrieve(typeDef.fileName);
45
45
  const fileName = (0, utils_2.ensureRealFilePath)(typeDef.fileName);
46
- const range = (0, documents_1.mapRangeToOriginal)(fragment, (0, utils_2.convertRange)(fragment, typeDef.textSpan));
46
+ const range = (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, typeDef.textSpan));
47
47
  if (range.start.line >= 0 && range.end.line >= 0) {
48
48
  return vscode_languageserver_protocol_1.Location.create((0, utils_1.pathToUrl)(fileName), range);
49
49
  }
@@ -1,25 +1,14 @@
1
1
  import type ts from 'typescript';
2
2
  import type { Position } from 'vscode-languageserver';
3
3
  import type { LanguageServiceManager } from '../LanguageServiceManager';
4
- import type { DocumentSnapshot, SnapshotFragment } from '../snapshots/DocumentSnapshot';
4
+ import type { DocumentSnapshot } from '../snapshots/DocumentSnapshot';
5
5
  export declare function isPartOfImportStatement(text: string, position: Position): boolean;
6
- export declare class SnapshotFragmentMap {
6
+ export declare class SnapshotMap {
7
7
  private languageServiceManager;
8
8
  private map;
9
9
  constructor(languageServiceManager: LanguageServiceManager);
10
- set(fileName: string, content: {
11
- fragment: SnapshotFragment;
12
- snapshot: DocumentSnapshot;
13
- }): void;
14
- get(fileName: string): {
15
- fragment: SnapshotFragment;
16
- snapshot: DocumentSnapshot;
17
- } | undefined;
18
- getFragment(fileName: string): SnapshotFragment | undefined;
19
- retrieve(fileName: string): Promise<{
20
- fragment: SnapshotFragment;
21
- snapshot: DocumentSnapshot;
22
- }>;
23
- retrieveFragment(fileName: string): Promise<SnapshotFragment>;
10
+ set(fileName: string, snapshot: DocumentSnapshot): void;
11
+ get(fileName: string): DocumentSnapshot | undefined;
12
+ retrieve(fileName: string): Promise<DocumentSnapshot>;
24
13
  }
25
14
  export declare function findContainingNode<T extends ts.Node>(node: ts.Node, textSpan: ts.TextSpan, predicate: (node: ts.Node) => node is T): T | undefined;