@astrojs/language-server 0.18.1 → 0.19.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,5 +1,30 @@
1
1
  # @astrojs/language-server
2
2
 
3
+ ## 0.19.2
4
+
5
+ ### Patch Changes
6
+
7
+ - 7de4967: Add better error messages for Vue and Svelte components with syntax errors
8
+ - Updated dependencies [7de4967]
9
+ - @astrojs/svelte-language-integration@0.1.6
10
+ - @astrojs/vue-language-integration@0.1.1
11
+
12
+ ## 0.19.1
13
+
14
+ ### Patch Changes
15
+
16
+ - 729dff5: Add support for giving linked editing ranges
17
+ - 05a48c2: Fix some TypeScript diagnostics not showing up in certain cases
18
+ - fe2d26b: Add support for showing Svelte components documentation on hover
19
+ - Updated dependencies [fe2d26b]
20
+ - @astrojs/svelte-language-integration@0.1.5
21
+
22
+ ## 0.19.0
23
+
24
+ ### Minor Changes
25
+
26
+ - a97b9a4: Add support for Inlay Hints. Minimum VS Code version supported starting from this update is 1.67.0 (April 2022)
27
+
3
28
  ## 0.18.1
4
29
 
5
30
  ### Patch Changes
@@ -2,7 +2,7 @@ import { VSCodeEmmetConfig } from '@vscode/emmet-helper';
2
2
  import { LSConfig, LSCSSConfig, LSFormatConfig, LSHTMLConfig, LSTypescriptConfig } from './interfaces';
3
3
  import { Connection, FormattingOptions } from 'vscode-languageserver';
4
4
  import { TextDocument } from 'vscode-languageserver-textdocument';
5
- import { FormatCodeSettings, UserPreferences } from 'typescript';
5
+ import { FormatCodeSettings, InlayHintsOptions, UserPreferences } from 'typescript';
6
6
  export declare const defaultLSConfig: LSConfig;
7
7
  declare type DeepPartial<T> = T extends Record<string, unknown> ? {
8
8
  [P in keyof T]?: DeepPartial<T[P]>;
@@ -25,14 +25,18 @@ export declare class ConfigManager {
25
25
  getAstroFormatConfig(document: TextDocument): Promise<LSFormatConfig>;
26
26
  getTSFormatConfig(document: TextDocument, vscodeOptions?: FormattingOptions): Promise<FormatCodeSettings>;
27
27
  getTSPreferences(document: TextDocument): Promise<UserPreferences>;
28
+ getTSInlayHintsPreferences(document: TextDocument): Promise<InlayHintsOptions>;
28
29
  /**
29
30
  * Return true if a plugin and an optional feature is enabled
30
31
  */
31
32
  isEnabled(document: TextDocument, plugin: keyof LSConfig, feature?: keyof LSTypescriptConfig | keyof LSCSSConfig | keyof LSHTMLConfig): Promise<boolean>;
32
33
  /**
33
34
  * Updating the global config should only be done in cases where the client doesn't support `workspace/configuration`
34
- * or inside of tests
35
+ * or inside of tests.
36
+ *
37
+ * The `outsideAstro` parameter can be set to true to change configurations in the global scope.
38
+ * For example, to change TypeScript settings
35
39
  */
36
- updateGlobalConfig(config: DeepPartial<LSConfig>): void;
40
+ updateGlobalConfig(config: DeepPartial<LSConfig> | any, outsideAstro?: boolean): void;
37
41
  }
38
42
  export {};
@@ -124,6 +124,20 @@ class ConfigManager {
124
124
  includeCompletionsWithInsertText: true,
125
125
  };
126
126
  }
127
+ async getTSInlayHintsPreferences(document) {
128
+ const config = (await this.getConfig('typescript', document.uri)) ?? {};
129
+ const tsPreferences = this.getTSPreferences(document);
130
+ return {
131
+ ...tsPreferences,
132
+ includeInlayParameterNameHints: getInlayParameterNameHintsPreference(config),
133
+ includeInlayParameterNameHintsWhenArgumentMatchesName: !(config.inlayHints?.parameterNames?.suppressWhenArgumentMatchesName ?? true),
134
+ includeInlayFunctionParameterTypeHints: config.inlayHints?.parameterTypes?.enabled ?? false,
135
+ includeInlayVariableTypeHints: config.inlayHints?.variableTypes?.enabled ?? false,
136
+ includeInlayPropertyDeclarationTypeHints: config.inlayHints?.propertyDeclarationTypes?.enabled ?? false,
137
+ includeInlayFunctionLikeReturnTypeHints: config.inlayHints?.functionLikeReturnTypes?.enabled ?? false,
138
+ includeInlayEnumMemberValueHints: config.inlayHints?.enumMemberValues?.enabled ?? false,
139
+ };
140
+ }
127
141
  /**
128
142
  * Return true if a plugin and an optional feature is enabled
129
143
  */
@@ -133,10 +147,18 @@ class ConfigManager {
133
147
  }
134
148
  /**
135
149
  * Updating the global config should only be done in cases where the client doesn't support `workspace/configuration`
136
- * or inside of tests
150
+ * or inside of tests.
151
+ *
152
+ * The `outsideAstro` parameter can be set to true to change configurations in the global scope.
153
+ * For example, to change TypeScript settings
137
154
  */
138
- updateGlobalConfig(config) {
139
- this.globalConfig.astro = (0, lodash_1.merge)({}, exports.defaultLSConfig, this.globalConfig.astro, config);
155
+ updateGlobalConfig(config, outsideAstro) {
156
+ if (outsideAstro) {
157
+ this.globalConfig = (0, lodash_1.merge)({}, this.globalConfig, config);
158
+ }
159
+ else {
160
+ this.globalConfig.astro = (0, lodash_1.merge)({}, exports.defaultLSConfig, this.globalConfig.astro, config);
161
+ }
140
162
  }
141
163
  }
142
164
  exports.ConfigManager = ConfigManager;
@@ -174,3 +196,15 @@ function getImportModuleSpecifierEndingPreference(config) {
174
196
  return 'auto';
175
197
  }
176
198
  }
199
+ function getInlayParameterNameHintsPreference(config) {
200
+ switch (config.inlayHints?.parameterNames?.enabled) {
201
+ case 'none':
202
+ return 'none';
203
+ case 'literals':
204
+ return 'literals';
205
+ case 'all':
206
+ return 'all';
207
+ default:
208
+ return undefined;
209
+ }
210
+ }
@@ -1,4 +1,4 @@
1
- import { CancellationToken, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FoldingRange, Hover, Position, Range, Location, SignatureHelp, SignatureHelpContext, TextDocumentContentChangeEvent, TextDocumentIdentifier, WorkspaceEdit, SymbolInformation, SemanticTokens, CodeActionContext, CodeAction, FormattingOptions, TextEdit } from 'vscode-languageserver';
1
+ import { CancellationToken, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FoldingRange, Hover, Position, Range, Location, SignatureHelp, SignatureHelpContext, TextDocumentContentChangeEvent, TextDocumentIdentifier, WorkspaceEdit, SymbolInformation, SemanticTokens, CodeActionContext, CodeAction, InlayHint, FormattingOptions, TextEdit, LinkedEditingRanges } from 'vscode-languageserver';
2
2
  import type { AppCompletionItem, Plugin } from './interfaces';
3
3
  import { DocumentManager } from '../core/documents/DocumentManager';
4
4
  interface PluginHostConfig {
@@ -22,9 +22,11 @@ export declare class PluginHost {
22
22
  getFoldingRanges(textDocument: TextDocumentIdentifier): Promise<FoldingRange[] | null>;
23
23
  getDocumentSymbols(textDocument: TextDocumentIdentifier, cancellationToken: CancellationToken): Promise<SymbolInformation[]>;
24
24
  getSemanticTokens(textDocument: TextDocumentIdentifier, range?: Range, cancellationToken?: CancellationToken): Promise<SemanticTokens | null>;
25
+ getLinkedEditingRanges(textDocument: TextDocumentIdentifier, position: Position): Promise<LinkedEditingRanges | null>;
25
26
  getDefinitions(textDocument: TextDocumentIdentifier, position: Position): Promise<DefinitionLink[] | Location[]>;
26
27
  rename(textDocument: TextDocumentIdentifier, position: Position, newName: string): Promise<WorkspaceEdit | null>;
27
28
  getDocumentColors(textDocument: TextDocumentIdentifier): Promise<ColorInformation[]>;
29
+ getInlayHints(textDocument: TextDocumentIdentifier, range: Range, cancellationToken: CancellationToken): Promise<InlayHint[]>;
28
30
  getColorPresentations(textDocument: TextDocumentIdentifier, range: Range, color: Color): Promise<ColorPresentation[]>;
29
31
  getSignatureHelp(textDocument: TextDocumentIdentifier, position: Position, context: SignatureHelpContext | undefined, cancellationToken: CancellationToken): Promise<SignatureHelp | null>;
30
32
  onWatchFileChanges(onWatchFileChangesParams: any[]): void;
@@ -94,6 +94,10 @@ class PluginHost {
94
94
  const document = this.getDocument(textDocument.uri);
95
95
  return await this.execute('getSemanticTokens', [document, range, cancellationToken], ExecuteMode.FirstNonNull);
96
96
  }
97
+ async getLinkedEditingRanges(textDocument, position) {
98
+ const document = this.getDocument(textDocument.uri);
99
+ return await this.execute('getLinkedEditingRanges', [document, position], ExecuteMode.FirstNonNull);
100
+ }
97
101
  async getDefinitions(textDocument, position) {
98
102
  const document = this.getDocument(textDocument.uri);
99
103
  const definitions = (0, lodash_1.flatten)(await this.execute('getDefinitions', [document, position], ExecuteMode.Collect));
@@ -112,6 +116,10 @@ class PluginHost {
112
116
  const document = this.getDocument(textDocument.uri);
113
117
  return (0, lodash_1.flatten)(await this.execute('getDocumentColors', [document], ExecuteMode.Collect));
114
118
  }
119
+ async getInlayHints(textDocument, range, cancellationToken) {
120
+ const document = this.getDocument(textDocument.uri);
121
+ return (0, lodash_1.flatten)(await this.execute('getInlayHints', [document, range], ExecuteMode.FirstNonNull));
122
+ }
115
123
  async getColorPresentations(textDocument, range, color) {
116
124
  const document = this.getDocument(textDocument.uri);
117
125
  return (0, lodash_1.flatten)(await this.execute('getColorPresentations', [document, range, color], ExecuteMode.Collect));
@@ -1,4 +1,4 @@
1
- import { CompletionList, Position, TextEdit, FoldingRange, Hover, SymbolInformation, FormattingOptions } from 'vscode-languageserver';
1
+ import { CompletionList, Position, TextEdit, FoldingRange, Hover, SymbolInformation, FormattingOptions, LinkedEditingRanges } from 'vscode-languageserver';
2
2
  import type { Plugin } from '../interfaces';
3
3
  import { ConfigManager } from '../../core/config/ConfigManager';
4
4
  import { AstroDocument } from '../../core/documents/AstroDocument';
@@ -17,6 +17,7 @@ export declare class HTMLPlugin implements Plugin {
17
17
  getCompletions(document: AstroDocument, position: Position): Promise<CompletionList | null>;
18
18
  formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
19
19
  getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
20
+ getLinkedEditingRanges(document: AstroDocument, position: Position): LinkedEditingRanges | null;
20
21
  doTagComplete(document: AstroDocument, position: Position): Promise<string | null>;
21
22
  getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
22
23
  /**
@@ -105,6 +105,17 @@ class HTMLPlugin {
105
105
  }
106
106
  return this.lang.getFoldingRanges(document);
107
107
  }
108
+ getLinkedEditingRanges(document, position) {
109
+ const html = document.html;
110
+ if (!html) {
111
+ return null;
112
+ }
113
+ const ranges = this.lang.findLinkedEditingRanges(document, position, html);
114
+ if (!ranges) {
115
+ return null;
116
+ }
117
+ return { ranges };
118
+ }
108
119
  async doTagComplete(document, position) {
109
120
  if (!(await this.featureEnabled(document, 'tagComplete'))) {
110
121
  return null;
@@ -1,4 +1,4 @@
1
- import { CodeAction, CodeActionContext, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FileChangeType, FoldingRange, FormattingOptions, Hover, LinkedEditingRanges, Position, Range, ReferenceContext, SelectionRange, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextDocumentIdentifier, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CodeAction, CodeActionContext, Color, ColorInformation, ColorPresentation, CompletionContext, CompletionItem, CompletionList, DefinitionLink, Diagnostic, FileChangeType, FoldingRange, FormattingOptions, Hover, InlayHint, LinkedEditingRanges, Position, Range, ReferenceContext, SelectionRange, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextDocumentIdentifier, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
2
2
  import { TextDocument } from 'vscode-languageserver-textdocument';
3
3
  export declare type Resolvable<T> = T | Promise<T>;
4
4
  export interface AppCompletionItem<T extends TextDocumentIdentifier = any> extends CompletionItem {
@@ -52,6 +52,9 @@ export interface FileRename {
52
52
  export interface UpdateImportsProvider {
53
53
  updateImports(fileRename: FileRename): Resolvable<WorkspaceEdit | null>;
54
54
  }
55
+ export interface InlayHintsProvider {
56
+ getInlayHints(document: TextDocument, range: Range): Resolvable<InlayHint[]>;
57
+ }
55
58
  export interface RenameProvider {
56
59
  rename(document: TextDocument, position: Position, newName: string): Resolvable<WorkspaceEdit | null>;
57
60
  prepareRename(document: TextDocument, position: Position): Resolvable<Range | null>;
@@ -81,7 +84,7 @@ export interface OnWatchFileChangesProvider {
81
84
  export interface UpdateNonAstroFile {
82
85
  updateNonAstroFile(fileName: string, changes: TextDocumentContentChangeEvent[]): void;
83
86
  }
84
- declare type ProviderBase = DiagnosticsProvider & HoverProvider & CompletionsProvider & DefinitionsProvider & FormattingProvider & FoldingRangesProvider & TagCompleteProvider & DocumentColorsProvider & ColorPresentationsProvider & DocumentSymbolsProvider & UpdateImportsProvider & CodeActionsProvider & FindReferencesProvider & RenameProvider & SignatureHelpProvider & SemanticTokensProvider & SelectionRangeProvider & OnWatchFileChangesProvider & LinkedEditingRangesProvider & UpdateNonAstroFile;
87
+ declare type ProviderBase = DiagnosticsProvider & HoverProvider & CompletionsProvider & DefinitionsProvider & FormattingProvider & FoldingRangesProvider & TagCompleteProvider & DocumentColorsProvider & ColorPresentationsProvider & DocumentSymbolsProvider & UpdateImportsProvider & CodeActionsProvider & FindReferencesProvider & RenameProvider & SignatureHelpProvider & SemanticTokensProvider & SelectionRangeProvider & OnWatchFileChangesProvider & LinkedEditingRangesProvider & InlayHintsProvider & UpdateNonAstroFile;
85
88
  export declare type LSProvider = ProviderBase;
86
89
  export declare type Plugin = Partial<ProviderBase> & {
87
90
  __name: string;
@@ -1,4 +1,4 @@
1
- import { CancellationToken, CodeAction, CodeActionContext, CompletionContext, DefinitionLink, Diagnostic, FoldingRange, FormattingOptions, Hover, Position, Range, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
1
+ import { CancellationToken, CodeAction, CodeActionContext, CompletionContext, DefinitionLink, Diagnostic, FoldingRange, FormattingOptions, Hover, InlayHint, Position, Range, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, TextEdit, WorkspaceEdit } from 'vscode-languageserver';
2
2
  import { ConfigManager } from '../../core/config';
3
3
  import { AstroDocument, DocumentManager } from '../../core/documents';
4
4
  import { AppCompletionItem, AppCompletionList, OnWatchFileChangesParam, Plugin } from '../interfaces';
@@ -14,6 +14,7 @@ export declare class TypeScriptPlugin implements Plugin {
14
14
  private readonly signatureHelpProvider;
15
15
  private readonly diagnosticsProvider;
16
16
  private readonly documentSymbolsProvider;
17
+ private readonly inlayHintsProvider;
17
18
  private readonly semanticTokensProvider;
18
19
  private readonly foldingRangesProvider;
19
20
  private readonly formattingProvider;
@@ -27,6 +28,7 @@ export declare class TypeScriptPlugin implements Plugin {
27
28
  getCodeActions(document: AstroDocument, range: Range, context: CodeActionContext, cancellationToken?: CancellationToken): Promise<CodeAction[]>;
28
29
  getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext, cancellationToken?: CancellationToken): Promise<AppCompletionList<CompletionItemData> | null>;
29
30
  resolveCompletion(document: AstroDocument, completionItem: AppCompletionItem<CompletionItemData>, cancellationToken?: CancellationToken): Promise<AppCompletionItem<CompletionItemData>>;
31
+ getInlayHints(document: AstroDocument, range: Range): Promise<InlayHint[]>;
30
32
  getDefinitions(document: AstroDocument, position: Position): Promise<DefinitionLink[]>;
31
33
  getDiagnostics(document: AstroDocument, cancellationToken?: CancellationToken): Promise<Diagnostic[]>;
32
34
  onWatchFileChanges(onWatchFileChangesParas: OnWatchFileChangesParam[]): Promise<void>;
@@ -17,6 +17,7 @@ const SemanticTokenProvider_1 = require("./features/SemanticTokenProvider");
17
17
  const FoldingRangesProvider_1 = require("./features/FoldingRangesProvider");
18
18
  const CodeActionsProvider_1 = require("./features/CodeActionsProvider");
19
19
  const DefinitionsProvider_1 = require("./features/DefinitionsProvider");
20
+ const InlayHintsProvider_1 = require("./features/InlayHintsProvider");
20
21
  const FormattingProvider_1 = require("./features/FormattingProvider");
21
22
  class TypeScriptPlugin {
22
23
  constructor(docManager, configManager, workspaceUris) {
@@ -31,6 +32,7 @@ class TypeScriptPlugin {
31
32
  this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.languageServiceManager);
32
33
  this.documentSymbolsProvider = new DocumentSymbolsProvider_1.DocumentSymbolsProviderImpl(this.languageServiceManager);
33
34
  this.semanticTokensProvider = new SemanticTokenProvider_1.SemanticTokensProviderImpl(this.languageServiceManager);
35
+ this.inlayHintsProvider = new InlayHintsProvider_1.InlayHintsProviderImpl(this.languageServiceManager, this.configManager);
34
36
  this.foldingRangesProvider = new FoldingRangesProvider_1.FoldingRangesProviderImpl(this.languageServiceManager);
35
37
  this.formattingProvider = new FormattingProvider_1.FormattingProviderImpl(this.languageServiceManager, this.configManager);
36
38
  }
@@ -98,6 +100,9 @@ class TypeScriptPlugin {
98
100
  async resolveCompletion(document, completionItem, cancellationToken) {
99
101
  return this.completionProvider.resolveCompletion(document, completionItem, cancellationToken);
100
102
  }
103
+ async getInlayHints(document, range) {
104
+ return this.inlayHintsProvider.getInlayHints(document, range);
105
+ }
101
106
  async getDefinitions(document, position) {
102
107
  return this.definitionsProvider.getDefinitions(document, position);
103
108
  }
@@ -3,6 +3,18 @@ import { Diagnostic } from 'vscode-languageserver-types';
3
3
  import { AstroDocument } from '../../../core/documents';
4
4
  import { DiagnosticsProvider } from '../../interfaces';
5
5
  import { LanguageServiceManager } from '../LanguageServiceManager';
6
+ export declare enum DiagnosticCodes {
7
+ SPREAD_EXPECTED = 1005,
8
+ DUPLICATED_JSX_ATTRIBUTES = 17001,
9
+ MUST_HAVE_PARENT_ELEMENT = 2657,
10
+ CANNOT_IMPORT_TS_EXT = 2691,
11
+ CANT_RETURN_OUTSIDE_FUNC = 1108,
12
+ ISOLATED_MODULE_COMPILE_ERR = 1208,
13
+ TYPE_NOT_ASSIGNABLE = 2322,
14
+ JSX_NO_CLOSING_TAG = 17008,
15
+ NO_DECL_IMPLICIT_ANY_TYPE = 7016,
16
+ JSX_ELEMENT_NO_CALL = 2604
17
+ }
6
18
  export declare class DiagnosticsProviderImpl implements DiagnosticsProvider {
7
19
  private readonly languageServiceManager;
8
20
  constructor(languageServiceManager: LanguageServiceManager);
@@ -3,11 +3,26 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.DiagnosticsProviderImpl = void 0;
6
+ exports.DiagnosticsProviderImpl = exports.DiagnosticCodes = void 0;
7
7
  const typescript_1 = __importDefault(require("typescript"));
8
8
  const vscode_languageserver_types_1 = require("vscode-languageserver-types");
9
9
  const documents_1 = require("../../../core/documents");
10
10
  const utils_1 = require("../utils");
11
+ // List of codes:
12
+ // https://github.com/Microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json
13
+ var DiagnosticCodes;
14
+ (function (DiagnosticCodes) {
15
+ DiagnosticCodes[DiagnosticCodes["SPREAD_EXPECTED"] = 1005] = "SPREAD_EXPECTED";
16
+ DiagnosticCodes[DiagnosticCodes["DUPLICATED_JSX_ATTRIBUTES"] = 17001] = "DUPLICATED_JSX_ATTRIBUTES";
17
+ DiagnosticCodes[DiagnosticCodes["MUST_HAVE_PARENT_ELEMENT"] = 2657] = "MUST_HAVE_PARENT_ELEMENT";
18
+ DiagnosticCodes[DiagnosticCodes["CANNOT_IMPORT_TS_EXT"] = 2691] = "CANNOT_IMPORT_TS_EXT";
19
+ DiagnosticCodes[DiagnosticCodes["CANT_RETURN_OUTSIDE_FUNC"] = 1108] = "CANT_RETURN_OUTSIDE_FUNC";
20
+ DiagnosticCodes[DiagnosticCodes["ISOLATED_MODULE_COMPILE_ERR"] = 1208] = "ISOLATED_MODULE_COMPILE_ERR";
21
+ DiagnosticCodes[DiagnosticCodes["TYPE_NOT_ASSIGNABLE"] = 2322] = "TYPE_NOT_ASSIGNABLE";
22
+ DiagnosticCodes[DiagnosticCodes["JSX_NO_CLOSING_TAG"] = 17008] = "JSX_NO_CLOSING_TAG";
23
+ DiagnosticCodes[DiagnosticCodes["NO_DECL_IMPLICIT_ANY_TYPE"] = 7016] = "NO_DECL_IMPLICIT_ANY_TYPE";
24
+ DiagnosticCodes[DiagnosticCodes["JSX_ELEMENT_NO_CALL"] = 2604] = "JSX_ELEMENT_NO_CALL";
25
+ })(DiagnosticCodes = exports.DiagnosticCodes || (exports.DiagnosticCodes = {}));
11
26
  class DiagnosticsProviderImpl {
12
27
  constructor(languageServiceManager) {
13
28
  this.languageServiceManager = languageServiceManager;
@@ -39,17 +54,15 @@ class DiagnosticsProviderImpl {
39
54
  code: diagnostic.code,
40
55
  tags: getDiagnosticTag(diagnostic),
41
56
  }))
57
+ .filter(isNoCantEndWithTS)
42
58
  .map(mapRange(scriptTagSnapshot, document));
43
59
  scriptDiagnostics.push(...scriptDiagnostic);
44
60
  });
45
61
  const { script: scriptBoundaries } = this.getTagBoundaries(lang, filePath);
46
- const syntaxDiagnostics = lang.getSyntacticDiagnostics(filePath);
47
- const suggestionDiagnostics = lang.getSuggestionDiagnostics(filePath);
48
- const semanticDiagnostics = lang.getSemanticDiagnostics(filePath);
49
62
  const diagnostics = [
50
- ...syntaxDiagnostics,
51
- ...suggestionDiagnostics,
52
- ...semanticDiagnostics,
63
+ ...lang.getSyntacticDiagnostics(filePath),
64
+ ...lang.getSuggestionDiagnostics(filePath),
65
+ ...lang.getSemanticDiagnostics(filePath),
53
66
  ].filter((diag) => {
54
67
  return isNoWithinBoundary(scriptBoundaries, diag);
55
68
  });
@@ -67,14 +80,15 @@ class DiagnosticsProviderImpl {
67
80
  ...scriptDiagnostics,
68
81
  ]
69
82
  .filter((diag) => {
70
- return (hasNoNegativeLines(diag) &&
71
- isNoJSXImplicitRuntimeWarning(diag) &&
83
+ return (
84
+ // Make sure the diagnostic is inside the document and not in generated code
85
+ diag.range.start.line <= document.lineCount &&
86
+ hasNoNegativeLines(diag) &&
72
87
  isNoJSXMustHaveOneParent(diag) &&
73
- isNoCantEndWithTS(diag) &&
74
- isNoSpreadExpected(diag) &&
75
- isNoCantResolveJSONModule(diag) &&
88
+ isNoSpreadExpected(diag, document) &&
76
89
  isNoCantReturnOutsideFunction(diag) &&
77
90
  isNoIsolatedModuleError(diag) &&
91
+ isNoImportImplicitAnyType(diag) &&
78
92
  isNoJsxCannotHaveMultipleAttrsError(diag));
79
93
  })
80
94
  .map(enhanceIfNecessary);
@@ -113,30 +127,39 @@ class DiagnosticsProviderImpl {
113
127
  }
114
128
  }
115
129
  exports.DiagnosticsProviderImpl = DiagnosticsProviderImpl;
116
- function getDiagnosticTag(diagnostic) {
117
- const tags = [];
118
- if (diagnostic.reportsUnnecessary) {
119
- tags.push(vscode_languageserver_types_1.DiagnosticTag.Unnecessary);
130
+ function isWithinBoundaries(boundaries, start) {
131
+ for (let [bstart, bend] of boundaries) {
132
+ if (start > bstart && start < bend) {
133
+ return true;
134
+ }
120
135
  }
121
- if (diagnostic.reportsDeprecated) {
122
- tags.push(vscode_languageserver_types_1.DiagnosticTag.Deprecated);
136
+ return false;
137
+ }
138
+ function diagnosticIsWithinBoundaries(sourceFile, boundaries, diagnostic) {
139
+ if ('start' in diagnostic) {
140
+ if (diagnostic.start == null)
141
+ return false;
142
+ return isWithinBoundaries(boundaries, diagnostic.start);
123
143
  }
124
- return tags;
144
+ if (!sourceFile)
145
+ return false;
146
+ let startRange = diagnostic.range.start;
147
+ let pos = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, startRange.line, startRange.character);
148
+ return isWithinBoundaries(boundaries, pos);
149
+ }
150
+ function isNoWithinBoundary(boundaries, diagnostic) {
151
+ return !diagnosticIsWithinBoundaries(undefined, boundaries, diagnostic);
125
152
  }
126
153
  function mapRange(fragment, _document) {
127
154
  return (diagnostic) => {
128
155
  let range = (0, documents_1.mapRangeToOriginal)(fragment, diagnostic.range);
129
- if (range.start.line < 0) {
130
- // Could be a props error?
131
- // From svelte
132
- }
133
156
  return { ...diagnostic, range };
134
157
  };
135
158
  }
136
159
  /**
137
160
  * In some rare cases mapping of diagnostics does not work and produces negative lines.
138
161
  * We filter out these diagnostics with negative lines because else the LSP
139
- * apparently has a hickup and does not show any diagnostics at all.
162
+ * apparently has a hiccup and does not show any diagnostics at all.
140
163
  */
141
164
  function hasNoNegativeLines(diagnostic) {
142
165
  return diagnostic.range.start.line >= 0 && diagnostic.range.end.line >= 0;
@@ -145,56 +168,68 @@ function hasNoNegativeLines(diagnostic) {
145
168
  * Astro allows multiple attributes to have the same name
146
169
  */
147
170
  function isNoJsxCannotHaveMultipleAttrsError(diagnostic) {
148
- return diagnostic.code !== 17001;
171
+ return diagnostic.code !== DiagnosticCodes.DUPLICATED_JSX_ATTRIBUTES;
149
172
  }
150
173
  /** Astro allows component with multiple root elements */
151
174
  function isNoJSXMustHaveOneParent(diagnostic) {
152
- return diagnostic.code !== 2657;
175
+ return diagnostic.code !== DiagnosticCodes.MUST_HAVE_PARENT_ELEMENT;
153
176
  }
154
- /** Astro allows `.ts` ending for imports, unlike TypeScript */
155
- function isNoCantEndWithTS(diagnostic) {
156
- return diagnostic.code !== 2691;
177
+ function isNoImportImplicitAnyType(diagnostic) {
178
+ return diagnostic.code !== DiagnosticCodes.NO_DECL_IMPLICIT_ANY_TYPE;
157
179
  }
158
- function isNoSpreadExpected(diagnostic) {
159
- return diagnostic.code !== 1005;
180
+ /**
181
+ * When using the shorthand syntax for props TSX expects you to use the spread operator
182
+ * Since the shorthand syntax works differently in Astro and this is not required, hide this message
183
+ * However, the error code used here is quite generic, as such we need to make we only ignore in valid cases
184
+ */
185
+ function isNoSpreadExpected(diagnostic, document) {
186
+ if (diagnostic.code === DiagnosticCodes.SPREAD_EXPECTED &&
187
+ diagnostic.message.includes('...') &&
188
+ document.offsetAt(diagnostic.range.start) > (document.astroMeta.frontmatter.endOffset ?? 0)) {
189
+ return false;
190
+ }
191
+ return true;
160
192
  }
161
- function isNoJSXImplicitRuntimeWarning(diagnostic) {
162
- return diagnostic.code !== 7016 && diagnostic.code !== 2792;
193
+ /** Inside script tags, Astro currently require the `.ts` file extension for imports */
194
+ function isNoCantEndWithTS(diagnostic) {
195
+ return diagnostic.code !== DiagnosticCodes.CANNOT_IMPORT_TS_EXT;
163
196
  }
164
197
  /**
165
198
  * Ignore "Can't return outside of function body"
166
- * This is technically a valid diagnostic, but due to how we format our TSX, the frontmatter is at top-level so we have
167
- * to ignore this. It wasn't a problem before because users didn't need to return things but they can now with SSR
199
+ * Since the frontmatter is at the top level, users trying to return a Response for SSR mode run into this
168
200
  */
169
201
  function isNoCantReturnOutsideFunction(diagnostic) {
170
- return diagnostic.code !== 1108;
171
- }
172
- /**
173
- * Astro allows users to import JSON modules
174
- */
175
- function isNoCantResolveJSONModule(diagnostic) {
176
- return diagnostic.code !== 2732;
202
+ return diagnostic.code !== DiagnosticCodes.CANT_RETURN_OUTSIDE_FUNC;
177
203
  }
178
204
  /**
179
205
  * When the content of the file is invalid and can't be parsed properly for TSX generation, TS will show an error about
180
206
  * how the current module can't be compiled under --isolatedModule, this is confusing to users so let's ignore this
181
207
  */
182
208
  function isNoIsolatedModuleError(diagnostic) {
183
- return diagnostic.code !== 1208;
209
+ return diagnostic.code !== DiagnosticCodes.ISOLATED_MODULE_COMPILE_ERR;
184
210
  }
185
211
  /**
186
212
  * Some diagnostics have JSX-specific nomenclature or unclear description. Enhance them for more clarity.
187
213
  */
188
214
  function enhanceIfNecessary(diagnostic) {
189
215
  // JSX element has no closing tag. JSX -> HTML
190
- if (diagnostic.code === 17008) {
216
+ if (diagnostic.code === DiagnosticCodes.JSX_NO_CLOSING_TAG) {
191
217
  return {
192
218
  ...diagnostic,
193
219
  message: diagnostic.message.replace('JSX', 'HTML'),
194
220
  };
195
221
  }
222
+ // JSX Element can't be constructed or called. This happens on syntax errors / invalid components
223
+ if (diagnostic.code === DiagnosticCodes.JSX_ELEMENT_NO_CALL) {
224
+ return {
225
+ ...diagnostic,
226
+ message: diagnostic.message
227
+ .replace('JSX element type', 'Component')
228
+ .replace('does not have any construct or call signatures.', 'is not a valid component.\n\nIf this is a Svelte or Vue component, it might have a syntax error that makes it impossible to parse.'),
229
+ };
230
+ }
196
231
  // For the rare case where an user might try to put a client directive on something that is not a component
197
- if (diagnostic.code === 2322) {
232
+ if (diagnostic.code === DiagnosticCodes.TYPE_NOT_ASSIGNABLE) {
198
233
  if (diagnostic.message.includes("Property 'client:") && diagnostic.message.includes("to type 'HTMLProps")) {
199
234
  return {
200
235
  ...diagnostic,
@@ -202,28 +237,23 @@ function enhanceIfNecessary(diagnostic) {
202
237
  };
203
238
  }
204
239
  }
240
+ // An import path cannot end with '.ts(x)' consider importing with no extension
241
+ // TODO: Remove this when https://github.com/withastro/astro/issues/3415 is fixed
242
+ if (diagnostic.code === DiagnosticCodes.CANNOT_IMPORT_TS_EXT) {
243
+ return {
244
+ ...diagnostic,
245
+ message: diagnostic.message.replace(/\.jsx?/, ''),
246
+ };
247
+ }
205
248
  return diagnostic;
206
249
  }
207
- function isWithinBoundaries(boundaries, start) {
208
- for (let [bstart, bend] of boundaries) {
209
- if (start > bstart && start < bend) {
210
- return true;
211
- }
250
+ function getDiagnosticTag(diagnostic) {
251
+ const tags = [];
252
+ if (diagnostic.reportsUnnecessary) {
253
+ tags.push(vscode_languageserver_types_1.DiagnosticTag.Unnecessary);
212
254
  }
213
- return false;
214
- }
215
- function diagnosticIsWithinBoundaries(sourceFile, boundaries, diagnostic) {
216
- if ('start' in diagnostic) {
217
- if (diagnostic.start == null)
218
- return false;
219
- return isWithinBoundaries(boundaries, diagnostic.start);
255
+ if (diagnostic.reportsDeprecated) {
256
+ tags.push(vscode_languageserver_types_1.DiagnosticTag.Deprecated);
220
257
  }
221
- if (!sourceFile)
222
- return false;
223
- let startRange = diagnostic.range.start;
224
- let pos = typescript_1.default.getPositionOfLineAndCharacter(sourceFile, startRange.line, startRange.character);
225
- return isWithinBoundaries(boundaries, pos);
226
- }
227
- function isNoWithinBoundary(boundaries, diagnostic) {
228
- return !diagnosticIsWithinBoundaries(undefined, boundaries, diagnostic);
258
+ return tags;
229
259
  }
@@ -0,0 +1,12 @@
1
+ import { InlayHint } from 'vscode-languageserver';
2
+ import { AstroDocument } from '../../../core/documents';
3
+ import { InlayHintsProvider } from '../../interfaces';
4
+ import { LanguageServiceManager } from '../LanguageServiceManager';
5
+ import { Range } from 'vscode-languageserver-types';
6
+ import { ConfigManager } from '../../../core/config';
7
+ export declare class InlayHintsProviderImpl implements InlayHintsProvider {
8
+ private languageServiceManager;
9
+ private configManager;
10
+ constructor(languageServiceManager: LanguageServiceManager, configManager: ConfigManager);
11
+ getInlayHints(document: AstroDocument, range: Range): Promise<InlayHint[]>;
12
+ }
@@ -0,0 +1,36 @@
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.InlayHintsProviderImpl = void 0;
7
+ const vscode_languageserver_1 = require("vscode-languageserver");
8
+ const utils_1 = require("../utils");
9
+ const vscode_languageserver_types_1 = require("vscode-languageserver-types");
10
+ const typescript_1 = __importDefault(require("typescript"));
11
+ class InlayHintsProviderImpl {
12
+ constructor(languageServiceManager, configManager) {
13
+ this.languageServiceManager = languageServiceManager;
14
+ this.configManager = configManager;
15
+ }
16
+ async getInlayHints(document, range) {
17
+ const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
18
+ const filePath = (0, utils_1.toVirtualAstroFilePath)(tsDoc.filePath);
19
+ const fragment = await tsDoc.createFragment();
20
+ const start = fragment.offsetAt(fragment.getGeneratedPosition(range.start));
21
+ const end = fragment.offsetAt(fragment.getGeneratedPosition(range.end));
22
+ const tsPreferences = await this.configManager.getTSInlayHintsPreferences(document);
23
+ const inlayHints = lang.provideInlayHints(filePath, { start, length: end - start }, tsPreferences);
24
+ return inlayHints.map((hint) => {
25
+ const result = vscode_languageserver_1.InlayHint.create(fragment.getOriginalPosition(fragment.positionAt(hint.position)), hint.text, hint.kind === typescript_1.default.InlayHintKind.Type
26
+ ? vscode_languageserver_types_1.InlayHintKind.Type
27
+ : hint.kind === typescript_1.default.InlayHintKind.Parameter
28
+ ? vscode_languageserver_types_1.InlayHintKind.Parameter
29
+ : undefined);
30
+ result.paddingLeft = hint.whitespaceBefore;
31
+ result.paddingRight = hint.whitespaceAfter;
32
+ return result;
33
+ });
34
+ }
35
+ }
36
+ exports.InlayHintsProviderImpl = InlayHintsProviderImpl;
@@ -224,6 +224,7 @@ async function createLanguageService(tsconfigPath, docContext, workspaceUris) {
224
224
  const forcedCompilerOptions = {
225
225
  noEmit: true,
226
226
  declaration: false,
227
+ resolveJsonModule: true,
227
228
  allowNonTsExtensions: true,
228
229
  allowJs: true,
229
230
  jsx: typescript_1.default.JsxEmit.Preserve,
package/dist/server.js CHANGED
@@ -129,11 +129,13 @@ function startLanguageServer(connection) {
129
129
  colorProvider: true,
130
130
  hoverProvider: true,
131
131
  documentSymbolProvider: true,
132
+ linkedEditingRangeProvider: true,
132
133
  semanticTokensProvider: {
133
134
  legend: (0, utils_2.getSemanticTokenLegend)(),
134
135
  range: true,
135
136
  full: true,
136
137
  },
138
+ inlayHintProvider: true,
137
139
  signatureHelpProvider: {
138
140
  triggerCharacters: ['(', ',', '<'],
139
141
  retriggerCharacters: [')'],
@@ -194,9 +196,11 @@ function startLanguageServer(connection) {
194
196
  connection.onDocumentSymbol((params, cancellationToken) => pluginHost.getDocumentSymbols(params.textDocument, cancellationToken));
195
197
  connection.onRequest(vscode_languageserver_1.SemanticTokensRequest.type, (evt, cancellationToken) => pluginHost.getSemanticTokens(evt.textDocument, undefined, cancellationToken));
196
198
  connection.onRequest(vscode_languageserver_1.SemanticTokensRangeRequest.type, (evt, cancellationToken) => pluginHost.getSemanticTokens(evt.textDocument, evt.range, cancellationToken));
199
+ connection.onRequest(vscode_languageserver_1.LinkedEditingRangeRequest.type, async (evt) => await pluginHost.getLinkedEditingRanges(evt.textDocument, evt.position));
197
200
  connection.onDocumentFormatting((params) => pluginHost.formatDocument(params.textDocument, params.options));
198
201
  connection.onDocumentColor((params) => pluginHost.getDocumentColors(params.textDocument));
199
202
  connection.onColorPresentation((params) => pluginHost.getColorPresentations(params.textDocument, params.range, params.color));
203
+ connection.onRequest(vscode_languageserver_1.InlayHintRequest.type, (params, cancellationToken) => pluginHost.getInlayHints(params.textDocument, params.range, cancellationToken));
200
204
  connection.onRequest(TagCloseRequest, (evt) => pluginHost.doTagComplete(evt.textDocument, evt.position));
201
205
  connection.onSignatureHelp((evt, cancellationToken) => pluginHost.getSignatureHelp(evt.textDocument, evt.position, evt.context, cancellationToken));
202
206
  connection.onRenameRequest((evt) => pluginHost.rename(evt.textDocument, evt.position, evt.newName));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@astrojs/language-server",
3
- "version": "0.18.1",
3
+ "version": "0.19.2",
4
4
  "author": "withastro",
5
5
  "license": "MIT",
6
6
  "type": "commonjs",
@@ -19,19 +19,19 @@
19
19
  "test": "cross-env TS_NODE_TRANSPILE_ONLY=true mocha --timeout 20000 --require ts-node/register \"test/**/*.ts\" --exclude \"test/**/*.d.ts\""
20
20
  },
21
21
  "dependencies": {
22
- "@astrojs/vue-language-integration": "^0.1.0",
23
- "@astrojs/svelte-language-integration": "^0.1.4",
22
+ "@astrojs/vue-language-integration": "^0.1.1",
23
+ "@astrojs/svelte-language-integration": "^0.1.6",
24
24
  "@vscode/emmet-helper": "^2.8.4",
25
25
  "lodash": "^4.17.21",
26
26
  "source-map": "^0.7.3",
27
- "typescript": "~4.6.2",
28
- "vscode-css-languageservice": "^5.1.13",
29
- "vscode-html-languageservice": "^4.2.5",
30
- "vscode-languageserver": "7.0.0",
31
- "vscode-languageserver-protocol": "^3.16.0",
32
- "vscode-languageserver-textdocument": "^1.0.1",
33
- "vscode-languageserver-types": "^3.16.0",
34
- "vscode-uri": "^3.0.2"
27
+ "typescript": "~4.6.4",
28
+ "vscode-css-languageservice": "^6.0.1",
29
+ "vscode-html-languageservice": "^5.0.0",
30
+ "vscode-languageserver": "^8.0.1",
31
+ "vscode-languageserver-protocol": "^3.17.1",
32
+ "vscode-languageserver-textdocument": "^1.0.4",
33
+ "vscode-languageserver-types": "^3.17.1",
34
+ "vscode-uri": "^3.0.3"
35
35
  },
36
36
  "devDependencies": {
37
37
  "@types/chai": "^4.3.0",