@astrojs/language-server 0.29.3 → 0.29.5
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/dist/core/worker/TSXService.d.ts +1 -1
- package/dist/plugins/PluginHost.d.ts +1 -0
- package/dist/plugins/PluginHost.js +4 -0
- package/dist/plugins/css/CSSPlugin.d.ts +3 -1
- package/dist/plugins/css/CSSPlugin.js +28 -0
- package/dist/plugins/html/HTMLPlugin.d.ts +7 -1
- package/dist/plugins/html/HTMLPlugin.js +35 -0
- package/dist/plugins/typescript/TypeScriptPlugin.d.ts +3 -1
- package/dist/plugins/typescript/TypeScriptPlugin.js +6 -20
- package/dist/plugins/typescript/astro2tsx.d.ts +1 -1
- package/dist/plugins/typescript/features/CompletionsProvider.d.ts +0 -6
- package/dist/plugins/typescript/features/CompletionsProvider.js +2 -44
- package/dist/plugins/typescript/features/DiagnosticsProvider.d.ts +1 -0
- package/dist/plugins/typescript/features/DiagnosticsProvider.js +7 -2
- package/dist/plugins/typescript/features/RenameProvider.d.ts +13 -0
- package/dist/plugins/typescript/features/RenameProvider.js +60 -0
- package/dist/plugins/typescript/snapshots/DocumentSnapshot.d.ts +2 -1
- package/dist/plugins/typescript/snapshots/DocumentSnapshot.js +3 -0
- package/dist/server.js +2 -1
- package/package.json +2 -2
|
@@ -28,6 +28,7 @@ export declare class PluginHost {
|
|
|
28
28
|
getTypeDefinitions(textDocument: TextDocumentIdentifier, position: Position): Promise<Location[] | null>;
|
|
29
29
|
getImplementations(textDocument: TextDocumentIdentifier, position: Position): Promise<Location[] | null>;
|
|
30
30
|
getReferences(textdocument: TextDocumentIdentifier, position: Position, context: ReferenceContext): Promise<Location[] | null>;
|
|
31
|
+
prepareRename(textDocument: TextDocumentIdentifier, position: Position): Promise<Range | null>;
|
|
31
32
|
rename(textDocument: TextDocumentIdentifier, position: Position, newName: string): Promise<WorkspaceEdit | null>;
|
|
32
33
|
getDocumentColors(textDocument: TextDocumentIdentifier): Promise<ColorInformation[]>;
|
|
33
34
|
getColorPresentations(textDocument: TextDocumentIdentifier, range: Range, color: Color): Promise<ColorPresentation[]>;
|
|
@@ -131,6 +131,10 @@ class PluginHost {
|
|
|
131
131
|
const document = this.getDocument(textdocument.uri);
|
|
132
132
|
return this.execute('findReferences', [document, position, context], ExecuteMode.FirstNonNull);
|
|
133
133
|
}
|
|
134
|
+
async prepareRename(textDocument, position) {
|
|
135
|
+
const document = this.getDocument(textDocument.uri);
|
|
136
|
+
return await this.execute('prepareRename', [document, position], ExecuteMode.FirstNonNull);
|
|
137
|
+
}
|
|
134
138
|
async rename(textDocument, position, newName) {
|
|
135
139
|
const document = this.getDocument(textDocument.uri);
|
|
136
140
|
return this.execute('rename', [document, position, newName], ExecuteMode.FirstNonNull);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Color, ColorInformation, ColorPresentation, CompletionContext, CompletionList, FoldingRange, Hover, Position, Range, SymbolInformation } from 'vscode-languageserver';
|
|
1
|
+
import { Color, ColorInformation, ColorPresentation, CompletionContext, CompletionList, FoldingRange, Hover, Position, Range, SymbolInformation, WorkspaceEdit } from 'vscode-languageserver';
|
|
2
2
|
import type { ConfigManager } from '../../core/config/ConfigManager';
|
|
3
3
|
import { AstroDocument } from '../../core/documents';
|
|
4
4
|
import type { Plugin } from '../interfaces';
|
|
@@ -14,6 +14,8 @@ export declare class CSSPlugin implements Plugin {
|
|
|
14
14
|
private getCompletionsInternal;
|
|
15
15
|
getDocumentColors(document: AstroDocument): Promise<ColorInformation[]>;
|
|
16
16
|
getColorPresentations(document: AstroDocument, range: Range, color: Color): Promise<ColorPresentation[]>;
|
|
17
|
+
prepareRename(document: AstroDocument, position: Position): Range | null;
|
|
18
|
+
rename(document: AstroDocument, position: Position, newName: string): WorkspaceEdit | null;
|
|
17
19
|
getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
|
|
18
20
|
getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
|
|
19
21
|
private inStyleAttributeWithoutInterpolation;
|
|
@@ -158,6 +158,34 @@ class CSSPlugin {
|
|
|
158
158
|
});
|
|
159
159
|
return allColorPres;
|
|
160
160
|
}
|
|
161
|
+
prepareRename(document, position) {
|
|
162
|
+
const styleTag = this.getStyleTagForPosition(document, position);
|
|
163
|
+
if (!styleTag) {
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
const cssDocument = this.getCSSDocumentForStyleTag(styleTag, document);
|
|
167
|
+
const cssLang = extractLanguage(cssDocument);
|
|
168
|
+
const langService = (0, language_service_1.getLanguageService)(cssLang);
|
|
169
|
+
const range = langService.prepareRename(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
|
|
170
|
+
if (!range) {
|
|
171
|
+
return null;
|
|
172
|
+
}
|
|
173
|
+
return (0, documents_1.mapRangeToOriginal)(cssDocument, range);
|
|
174
|
+
}
|
|
175
|
+
rename(document, position, newName) {
|
|
176
|
+
const styleTag = this.getStyleTagForPosition(document, position);
|
|
177
|
+
if (!styleTag) {
|
|
178
|
+
return null;
|
|
179
|
+
}
|
|
180
|
+
const cssDocument = this.getCSSDocumentForStyleTag(styleTag, document);
|
|
181
|
+
const cssLang = extractLanguage(cssDocument);
|
|
182
|
+
const langService = (0, language_service_1.getLanguageService)(cssLang);
|
|
183
|
+
const renames = langService.doRename(cssDocument, cssDocument.getGeneratedPosition(position), newName, cssDocument.stylesheet);
|
|
184
|
+
if (renames?.changes?.[document.uri]) {
|
|
185
|
+
renames.changes[document.uri] = renames?.changes?.[document.uri].map((edit) => (0, documents_1.mapObjWithRangeToOriginal)(cssDocument, edit));
|
|
186
|
+
}
|
|
187
|
+
return renames;
|
|
188
|
+
}
|
|
161
189
|
getFoldingRanges(document) {
|
|
162
190
|
const allFoldingRanges = this.getCSSDocumentsForDocument(document).flatMap((cssDoc) => {
|
|
163
191
|
const cssLang = extractLanguage(cssDoc);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompletionList, FoldingRange, Hover, LinkedEditingRanges, Position, SymbolInformation } from 'vscode-languageserver';
|
|
1
|
+
import { CompletionList, FoldingRange, Hover, LinkedEditingRanges, Position, Range, SymbolInformation, WorkspaceEdit } from 'vscode-languageserver';
|
|
2
2
|
import type { ConfigManager } from '../../core/config/ConfigManager';
|
|
3
3
|
import type { AstroDocument } from '../../core/documents/AstroDocument';
|
|
4
4
|
import type { Plugin } from '../interfaces';
|
|
@@ -18,10 +18,16 @@ export declare class HTMLPlugin implements Plugin {
|
|
|
18
18
|
getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
|
|
19
19
|
getLinkedEditingRanges(document: AstroDocument, position: Position): LinkedEditingRanges | null;
|
|
20
20
|
doTagComplete(document: AstroDocument, position: Position): Promise<string | null>;
|
|
21
|
+
prepareRename(document: AstroDocument, position: Position): Range | null;
|
|
22
|
+
rename(document: AstroDocument, position: Position, newName: string): WorkspaceEdit | null;
|
|
21
23
|
getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
|
|
22
24
|
/**
|
|
23
25
|
* Get lang completions for style tags (ex: `<style lang="scss">`)
|
|
24
26
|
*/
|
|
25
27
|
private getLangCompletions;
|
|
28
|
+
/**
|
|
29
|
+
* Returns true if rename happens at the tag name, not anywhere inbetween.
|
|
30
|
+
*/
|
|
31
|
+
private isRenameAtTag;
|
|
26
32
|
private featureEnabled;
|
|
27
33
|
}
|
|
@@ -118,6 +118,29 @@ class HTMLPlugin {
|
|
|
118
118
|
}
|
|
119
119
|
return this.lang.doTagComplete(document, position, html);
|
|
120
120
|
}
|
|
121
|
+
prepareRename(document, position) {
|
|
122
|
+
const html = document.html;
|
|
123
|
+
const offset = document.offsetAt(position);
|
|
124
|
+
const node = html.findNodeAt(offset);
|
|
125
|
+
if (!node || (0, utils_1.isPossibleComponent)(node) || !node.tag || !this.isRenameAtTag(node, offset)) {
|
|
126
|
+
return null;
|
|
127
|
+
}
|
|
128
|
+
const tagNameStart = node.start + '<'.length;
|
|
129
|
+
return vscode_languageserver_1.Range.create(document.positionAt(tagNameStart), document.positionAt(tagNameStart + node.tag.length));
|
|
130
|
+
}
|
|
131
|
+
rename(document, position, newName) {
|
|
132
|
+
const html = document.html;
|
|
133
|
+
const offset = document.offsetAt(position);
|
|
134
|
+
if (!html || (0, utils_1.isInsideFrontmatter)(document.getText(), offset)) {
|
|
135
|
+
return null;
|
|
136
|
+
}
|
|
137
|
+
const node = html.findNodeAt(offset);
|
|
138
|
+
// The TypeScript plugin handles renaming for components
|
|
139
|
+
if (!node || (0, utils_1.isPossibleComponent)(node) || !this.isRenameAtTag(node, offset)) {
|
|
140
|
+
return null;
|
|
141
|
+
}
|
|
142
|
+
return this.lang.doRename(document, position, newName, html);
|
|
143
|
+
}
|
|
121
144
|
async getDocumentSymbols(document) {
|
|
122
145
|
if (!(await this.featureEnabled(document, 'documentSymbols'))) {
|
|
123
146
|
return [];
|
|
@@ -155,6 +178,18 @@ class HTMLPlugin {
|
|
|
155
178
|
}));
|
|
156
179
|
}
|
|
157
180
|
}
|
|
181
|
+
/**
|
|
182
|
+
* Returns true if rename happens at the tag name, not anywhere inbetween.
|
|
183
|
+
*/
|
|
184
|
+
isRenameAtTag(node, offset) {
|
|
185
|
+
if (!node.tag) {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
const startTagNameEnd = node.start + `<${node.tag}`.length;
|
|
189
|
+
const isAtStartTag = offset > node.start && offset <= startTagNameEnd;
|
|
190
|
+
const isAtEndTag = node.endTagStart !== undefined && offset >= node.endTagStart && offset < node.end;
|
|
191
|
+
return isAtStartTag || isAtEndTag;
|
|
192
|
+
}
|
|
158
193
|
async featureEnabled(document, feature) {
|
|
159
194
|
return ((await this.configManager.isEnabled(document, 'html')) &&
|
|
160
195
|
(await this.configManager.isEnabled(document, 'html', feature)));
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { TSXResult } from '@astrojs/compiler/
|
|
1
|
+
import type { TSXResult } from '@astrojs/compiler/types';
|
|
2
2
|
import { CancellationToken, CodeAction, CodeActionContext, CompletionContext, DefinitionLink, Diagnostic, FoldingRange, Hover, InlayHint, Location, Position, Range, ReferenceContext, SemanticTokens, SignatureHelp, SignatureHelpContext, SymbolInformation, TextDocumentContentChangeEvent, WorkspaceEdit } from 'vscode-languageserver';
|
|
3
3
|
import type { ConfigManager } from '../../core/config';
|
|
4
4
|
import type { AstroDocument } from '../../core/documents';
|
|
@@ -23,9 +23,11 @@ export declare class TypeScriptPlugin implements Plugin {
|
|
|
23
23
|
private readonly inlayHintsProvider;
|
|
24
24
|
private readonly semanticTokensProvider;
|
|
25
25
|
private readonly foldingRangesProvider;
|
|
26
|
+
private readonly renameProvider;
|
|
26
27
|
private readonly ts;
|
|
27
28
|
constructor(configManager: ConfigManager, languageServiceManager: LanguageServiceManager);
|
|
28
29
|
doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
|
|
30
|
+
prepareRename(document: AstroDocument, position: Position): Promise<Range | null>;
|
|
29
31
|
rename(document: AstroDocument, position: Position, newName: string): Promise<WorkspaceEdit | null>;
|
|
30
32
|
getFoldingRanges(document: AstroDocument): Promise<FoldingRange[] | null>;
|
|
31
33
|
getSemanticTokens(document: AstroDocument, range?: Range, cancellationToken?: CancellationToken): Promise<SemanticTokens | null>;
|
|
@@ -17,6 +17,7 @@ const HoverProvider_1 = require("./features/HoverProvider");
|
|
|
17
17
|
const ImplementationsProvider_1 = require("./features/ImplementationsProvider");
|
|
18
18
|
const InlayHintsProvider_1 = require("./features/InlayHintsProvider");
|
|
19
19
|
const ReferencesProvider_1 = require("./features/ReferencesProvider");
|
|
20
|
+
const RenameProvider_1 = require("./features/RenameProvider");
|
|
20
21
|
const SemanticTokenProvider_1 = require("./features/SemanticTokenProvider");
|
|
21
22
|
const SignatureHelpProvider_1 = require("./features/SignatureHelpProvider");
|
|
22
23
|
const TypeDefinitionsProvider_1 = require("./features/TypeDefinitionsProvider");
|
|
@@ -41,6 +42,7 @@ class TypeScriptPlugin {
|
|
|
41
42
|
this.semanticTokensProvider = new SemanticTokenProvider_1.SemanticTokensProviderImpl(this.languageServiceManager);
|
|
42
43
|
this.inlayHintsProvider = new InlayHintsProvider_1.InlayHintsProviderImpl(this.languageServiceManager, this.configManager);
|
|
43
44
|
this.foldingRangesProvider = new FoldingRangesProvider_1.FoldingRangesProviderImpl(this.languageServiceManager);
|
|
45
|
+
this.renameProvider = new RenameProvider_1.RenameProviderImpl(this.languageServiceManager, this.configManager);
|
|
44
46
|
}
|
|
45
47
|
async doHover(document, position) {
|
|
46
48
|
if (!(await this.featureEnabled(document, 'hover'))) {
|
|
@@ -48,27 +50,11 @@ class TypeScriptPlugin {
|
|
|
48
50
|
}
|
|
49
51
|
return this.hoverProvider.doHover(document, position);
|
|
50
52
|
}
|
|
53
|
+
async prepareRename(document, position) {
|
|
54
|
+
return this.renameProvider.prepareRename(document, position);
|
|
55
|
+
}
|
|
51
56
|
async rename(document, position, newName) {
|
|
52
|
-
|
|
53
|
-
const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
|
|
54
|
-
let renames = lang.findRenameLocations(tsDoc.filePath, offset, false, false, true);
|
|
55
|
-
if (!renames) {
|
|
56
|
-
return null;
|
|
57
|
-
}
|
|
58
|
-
let edit = {
|
|
59
|
-
changes: {},
|
|
60
|
-
};
|
|
61
|
-
renames.forEach((rename) => {
|
|
62
|
-
const filePath = (0, utils_1.ensureRealFilePath)(rename.fileName);
|
|
63
|
-
if (!(filePath in edit.changes)) {
|
|
64
|
-
edit.changes[filePath] = [];
|
|
65
|
-
}
|
|
66
|
-
edit.changes[filePath].push({
|
|
67
|
-
newText: newName,
|
|
68
|
-
range: (0, utils_1.convertToLocationRange)(tsDoc, rename.textSpan),
|
|
69
|
-
});
|
|
70
|
-
});
|
|
71
|
-
return edit;
|
|
57
|
+
return this.renameProvider.rename(document, position, newName);
|
|
72
58
|
}
|
|
73
59
|
async getFoldingRanges(document) {
|
|
74
60
|
return this.foldingRangesProvider.getFoldingRanges(document);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { TSXResult } from '@astrojs/compiler/
|
|
1
|
+
import { TSXResult } from '@astrojs/compiler/types';
|
|
2
2
|
export default function (content: string, fileName: string): TSXResult;
|
|
@@ -23,12 +23,6 @@ export declare class CompletionsProviderImpl implements CompletionsProvider<Comp
|
|
|
23
23
|
resolveCompletion(document: AstroDocument, item: AppCompletionItem<CompletionItemData>, cancellationToken?: CancellationToken): Promise<AppCompletionItem<CompletionItemData>>;
|
|
24
24
|
private toCompletionItem;
|
|
25
25
|
private getCompletionDocument;
|
|
26
|
-
/**
|
|
27
|
-
* If the textEdit is out of the word range of the triggered position
|
|
28
|
-
* vscode would refuse to show the completions
|
|
29
|
-
* split those edits into additionalTextEdit to fix it
|
|
30
|
-
*/
|
|
31
|
-
private fixTextEditRange;
|
|
32
26
|
private canReuseLastCompletion;
|
|
33
27
|
private getExistingImports;
|
|
34
28
|
private isAstroComponentImport;
|
|
@@ -79,12 +79,6 @@ class CompletionsProviderImpl {
|
|
|
79
79
|
else {
|
|
80
80
|
// PERF: Getting TS completions is fairly slow and I am currently not sure how to speed it up
|
|
81
81
|
// As such, we'll try to avoid getting them when unneeded, such as when we're doing HTML stuff
|
|
82
|
-
// When at the root of the document TypeScript offer all kinds of completions, because it doesn't know yet that
|
|
83
|
-
// it's JSX and not JS. As such, people who are using Emmet to write their template suffer from a very degraded experience
|
|
84
|
-
// from what they're used to in HTML files (which is instant completions). So let's disable ourselves when we're at the root
|
|
85
|
-
if (!isCompletionInsideFrontmatter && !node.parent && !isCompletionInsideExpression) {
|
|
86
|
-
return null;
|
|
87
|
-
}
|
|
88
82
|
// If the user just typed `<` with nothing else, let's disable ourselves until we're more sure if the user wants TS completions
|
|
89
83
|
if (!isCompletionInsideFrontmatter && node.parent && node.tag === undefined && !isCompletionInsideExpression) {
|
|
90
84
|
return null;
|
|
@@ -102,16 +96,11 @@ class CompletionsProviderImpl {
|
|
|
102
96
|
if (completions === undefined || completions.entries.length === 0) {
|
|
103
97
|
return null;
|
|
104
98
|
}
|
|
105
|
-
const wordRange = completions.optionalReplacementSpan
|
|
106
|
-
? vscode_languageserver_1.Range.create(document.positionAt(completions.optionalReplacementSpan.start), document.positionAt(completions.optionalReplacementSpan.start + completions.optionalReplacementSpan.length))
|
|
107
|
-
: undefined;
|
|
108
|
-
const wordRangeStartPosition = wordRange?.start;
|
|
109
99
|
const existingImports = this.getExistingImports(document);
|
|
110
100
|
const completionItems = completions.entries
|
|
111
101
|
.filter((completion) => this.isValidCompletion(completion, this.ts))
|
|
112
102
|
.map((entry) => this.toCompletionItem(tsDoc, entry, filePath, offset, isCompletionInsideFrontmatter, scriptTagIndex, existingImports))
|
|
113
|
-
.filter(utils_2.isNotNullOrUndefined)
|
|
114
|
-
.map((comp) => this.fixTextEditRange(wordRangeStartPosition, comp));
|
|
103
|
+
.filter(utils_2.isNotNullOrUndefined);
|
|
115
104
|
const completionList = vscode_languageserver_1.CompletionList.create(completionItems, true);
|
|
116
105
|
this.lastCompletion = { key: document.getFilePath() || '', position, completionList };
|
|
117
106
|
return completionList;
|
|
@@ -212,7 +201,7 @@ class CompletionsProviderImpl {
|
|
|
212
201
|
item.insertText = comp.insertText ? (0, utils_3.removeAstroComponentSuffix)(comp.insertText) : undefined;
|
|
213
202
|
item.insertTextFormat = comp.isSnippet ? vscode_languageserver_1.InsertTextFormat.Snippet : vscode_languageserver_1.InsertTextFormat.PlainText;
|
|
214
203
|
item.textEdit = comp.replacementSpan
|
|
215
|
-
? vscode_languageserver_1.TextEdit.replace((0, utils_3.
|
|
204
|
+
? vscode_languageserver_1.TextEdit.replace((0, utils_3.convertToLocationRange)(snapshot, comp.replacementSpan), item.insertText ?? item.label)
|
|
216
205
|
: undefined;
|
|
217
206
|
}
|
|
218
207
|
return {
|
|
@@ -242,37 +231,6 @@ class CompletionsProviderImpl {
|
|
|
242
231
|
detail,
|
|
243
232
|
};
|
|
244
233
|
}
|
|
245
|
-
/**
|
|
246
|
-
* If the textEdit is out of the word range of the triggered position
|
|
247
|
-
* vscode would refuse to show the completions
|
|
248
|
-
* split those edits into additionalTextEdit to fix it
|
|
249
|
-
*/
|
|
250
|
-
fixTextEditRange(wordRangePosition, completionItem) {
|
|
251
|
-
const { textEdit } = completionItem;
|
|
252
|
-
if (!textEdit || !vscode_languageserver_1.TextEdit.is(textEdit) || !wordRangePosition) {
|
|
253
|
-
return completionItem;
|
|
254
|
-
}
|
|
255
|
-
const { newText, range: { start }, } = textEdit;
|
|
256
|
-
const wordRangeStartCharacter = wordRangePosition.character;
|
|
257
|
-
if (wordRangePosition.line !== wordRangePosition.line || start.character > wordRangePosition.character) {
|
|
258
|
-
return completionItem;
|
|
259
|
-
}
|
|
260
|
-
textEdit.newText = newText.substring(wordRangeStartCharacter - start.character);
|
|
261
|
-
textEdit.range.start = {
|
|
262
|
-
line: start.line,
|
|
263
|
-
character: wordRangeStartCharacter,
|
|
264
|
-
};
|
|
265
|
-
completionItem.additionalTextEdits = [
|
|
266
|
-
vscode_languageserver_1.TextEdit.replace({
|
|
267
|
-
start,
|
|
268
|
-
end: {
|
|
269
|
-
line: start.line,
|
|
270
|
-
character: wordRangeStartCharacter,
|
|
271
|
-
},
|
|
272
|
-
}, newText.substring(0, wordRangeStartCharacter - start.character)),
|
|
273
|
-
];
|
|
274
|
-
return completionItem;
|
|
275
|
-
}
|
|
276
234
|
canReuseLastCompletion(lastCompletion, triggerKind, triggerCharacter, document, position) {
|
|
277
235
|
return (!!lastCompletion &&
|
|
278
236
|
lastCompletion.key === document.getFilePath() &&
|
|
@@ -6,6 +6,7 @@ import type { LanguageServiceManager } from '../LanguageServiceManager';
|
|
|
6
6
|
export declare enum DiagnosticCodes {
|
|
7
7
|
SPREAD_EXPECTED = 1005,
|
|
8
8
|
IS_NOT_A_MODULE = 2306,
|
|
9
|
+
CANNOT_FIND_MODULE = 2307,
|
|
9
10
|
DUPLICATED_JSX_ATTRIBUTES = 17001,
|
|
10
11
|
CANT_RETURN_OUTSIDE_FUNC = 1108,
|
|
11
12
|
ISOLATED_MODULE_COMPILE_ERR = 1208,
|
|
@@ -11,6 +11,7 @@ var DiagnosticCodes;
|
|
|
11
11
|
(function (DiagnosticCodes) {
|
|
12
12
|
DiagnosticCodes[DiagnosticCodes["SPREAD_EXPECTED"] = 1005] = "SPREAD_EXPECTED";
|
|
13
13
|
DiagnosticCodes[DiagnosticCodes["IS_NOT_A_MODULE"] = 2306] = "IS_NOT_A_MODULE";
|
|
14
|
+
DiagnosticCodes[DiagnosticCodes["CANNOT_FIND_MODULE"] = 2307] = "CANNOT_FIND_MODULE";
|
|
14
15
|
DiagnosticCodes[DiagnosticCodes["DUPLICATED_JSX_ATTRIBUTES"] = 17001] = "DUPLICATED_JSX_ATTRIBUTES";
|
|
15
16
|
DiagnosticCodes[DiagnosticCodes["CANT_RETURN_OUTSIDE_FUNC"] = 1108] = "CANT_RETURN_OUTSIDE_FUNC";
|
|
16
17
|
DiagnosticCodes[DiagnosticCodes["ISOLATED_MODULE_COMPILE_ERR"] = 1208] = "ISOLATED_MODULE_COMPILE_ERR";
|
|
@@ -31,8 +32,7 @@ class DiagnosticsProviderImpl {
|
|
|
31
32
|
}
|
|
32
33
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
33
34
|
// If we have compiler errors, our TSX isn't valid so don't bother showing TS errors
|
|
34
|
-
if (tsDoc.
|
|
35
|
-
0) {
|
|
35
|
+
if (tsDoc.isInErrorState) {
|
|
36
36
|
return [];
|
|
37
37
|
}
|
|
38
38
|
let scriptDiagnostics = [];
|
|
@@ -203,6 +203,11 @@ function enhanceIfNecessary(diagnostic) {
|
|
|
203
203
|
}
|
|
204
204
|
return diagnostic;
|
|
205
205
|
}
|
|
206
|
+
if (diagnostic.code === DiagnosticCodes.CANNOT_FIND_MODULE && diagnostic.message.includes('astro:content')) {
|
|
207
|
+
diagnostic.message +=
|
|
208
|
+
"\n\nIf you're using content collections, make sure to run `astro dev`, `astro build` or `astro sync` to first generate the types so you can import from them. If you already ran one of those commands, restarting the language server might be necessary in order for the change to take effect";
|
|
209
|
+
return diagnostic;
|
|
210
|
+
}
|
|
206
211
|
// JSX element has no closing tag. JSX -> HTML
|
|
207
212
|
if (diagnostic.code === DiagnosticCodes.JSX_NO_CLOSING_TAG) {
|
|
208
213
|
return {
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Position, Range, WorkspaceEdit } from 'vscode-languageserver-types';
|
|
2
|
+
import type { ConfigManager } from '../../../core/config';
|
|
3
|
+
import { AstroDocument } from '../../../core/documents';
|
|
4
|
+
import type { RenameProvider } from '../../interfaces';
|
|
5
|
+
import type { LanguageServiceManager } from '../LanguageServiceManager';
|
|
6
|
+
export declare class RenameProviderImpl implements RenameProvider {
|
|
7
|
+
private languageServiceManager;
|
|
8
|
+
private configManager;
|
|
9
|
+
private ts;
|
|
10
|
+
constructor(languageServiceManager: LanguageServiceManager, configManager: ConfigManager);
|
|
11
|
+
prepareRename(document: AstroDocument, position: Position): Promise<Range | null>;
|
|
12
|
+
rename(document: AstroDocument, position: Position, newName: string): Promise<WorkspaceEdit | null>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.RenameProviderImpl = void 0;
|
|
4
|
+
const documents_1 = require("../../../core/documents");
|
|
5
|
+
const utils_1 = require("../../../utils");
|
|
6
|
+
const utils_2 = require("../utils");
|
|
7
|
+
const utils_3 = require("./utils");
|
|
8
|
+
class RenameProviderImpl {
|
|
9
|
+
constructor(languageServiceManager, configManager) {
|
|
10
|
+
this.languageServiceManager = languageServiceManager;
|
|
11
|
+
this.configManager = configManager;
|
|
12
|
+
this.ts = languageServiceManager.docContext.ts;
|
|
13
|
+
}
|
|
14
|
+
async prepareRename(document, position) {
|
|
15
|
+
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
16
|
+
const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
|
|
17
|
+
// If our TSX isn't valid, we can't rename safely, so let's abort
|
|
18
|
+
if (tsDoc.isInErrorState) {
|
|
19
|
+
return null;
|
|
20
|
+
}
|
|
21
|
+
// TODO: Allow renaming of import paths
|
|
22
|
+
// This requires a bit of work, because we need to create files for the new import paths
|
|
23
|
+
const renameInfo = lang.getRenameInfo(tsDoc.filePath, offset, { allowRenameOfImportPath: false });
|
|
24
|
+
if (!renameInfo.canRename) {
|
|
25
|
+
return null;
|
|
26
|
+
}
|
|
27
|
+
return (0, documents_1.mapRangeToOriginal)(tsDoc, (0, utils_2.convertRange)(tsDoc, renameInfo.triggerSpan));
|
|
28
|
+
}
|
|
29
|
+
async rename(document, position, newName) {
|
|
30
|
+
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
31
|
+
const offset = tsDoc.offsetAt(tsDoc.getGeneratedPosition(position));
|
|
32
|
+
const { providePrefixAndSuffixTextForRename } = await this.configManager.getTSPreferences(document);
|
|
33
|
+
let renames = lang.findRenameLocations(tsDoc.filePath, offset, false, false, providePrefixAndSuffixTextForRename);
|
|
34
|
+
if (!renames) {
|
|
35
|
+
return null;
|
|
36
|
+
}
|
|
37
|
+
const docs = new utils_3.SnapshotMap(this.languageServiceManager);
|
|
38
|
+
docs.set(tsDoc.filePath, tsDoc);
|
|
39
|
+
const mappedRenames = await Promise.all(renames.map(async (rename) => {
|
|
40
|
+
const snapshot = await docs.retrieve(rename.fileName);
|
|
41
|
+
return {
|
|
42
|
+
...rename,
|
|
43
|
+
range: (0, documents_1.mapRangeToOriginal)(snapshot, (0, utils_2.convertRange)(snapshot, rename.textSpan)),
|
|
44
|
+
newName,
|
|
45
|
+
};
|
|
46
|
+
}));
|
|
47
|
+
return mappedRenames.reduce((acc, loc) => {
|
|
48
|
+
const uri = (0, utils_1.pathToUrl)(loc.fileName);
|
|
49
|
+
if (!acc.changes[uri]) {
|
|
50
|
+
acc.changes[uri] = [];
|
|
51
|
+
}
|
|
52
|
+
acc.changes[uri].push({
|
|
53
|
+
newText: (loc.prefixText || '') + (loc.newName || newName) + (loc.suffixText || ''),
|
|
54
|
+
range: loc.range,
|
|
55
|
+
});
|
|
56
|
+
return acc;
|
|
57
|
+
}, { changes: {} });
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
exports.RenameProviderImpl = RenameProviderImpl;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { DiagnosticMessage } from '@astrojs/compiler/types';
|
|
2
2
|
import { EncodedSourceMap, TraceMap } from '@jridgewell/trace-mapping';
|
|
3
3
|
import { Position, TextDocumentContentChangeEvent } from 'vscode-languageserver';
|
|
4
4
|
import { AstroDocument, DocumentMapper, FragmentMapper, IdentityMapper, SourceMapDocumentMapper, TagInformation } from '../../../core/documents';
|
|
@@ -28,6 +28,7 @@ export declare class AstroSnapshot implements DocumentSnapshot {
|
|
|
28
28
|
scriptTagSnapshots: ScriptTagDocumentSnapshot[];
|
|
29
29
|
version: number;
|
|
30
30
|
constructor(parent: AstroDocument, text: string, tsxMap: EncodedSourceMap, scriptKind: ts.ScriptKind, compilerDiagnostics: DiagnosticMessage[]);
|
|
31
|
+
get isInErrorState(): boolean;
|
|
31
32
|
isInGenerated(pos: Position): boolean;
|
|
32
33
|
getURL(): string;
|
|
33
34
|
get filePath(): string;
|
|
@@ -19,6 +19,9 @@ class AstroSnapshot {
|
|
|
19
19
|
this.scriptTagSnapshots = [];
|
|
20
20
|
this.version = this.parent.version;
|
|
21
21
|
}
|
|
22
|
+
get isInErrorState() {
|
|
23
|
+
return this.compilerDiagnostics.filter((diag) => diag.severity === vscode_languageserver_1.DiagnosticSeverity.Error).length > 0;
|
|
24
|
+
}
|
|
22
25
|
isInGenerated(pos) {
|
|
23
26
|
throw new Error('Method not implemented.');
|
|
24
27
|
}
|
package/dist/server.js
CHANGED
|
@@ -105,7 +105,7 @@ function startLanguageServer(connection, env) {
|
|
|
105
105
|
typeDefinitionProvider: true,
|
|
106
106
|
referencesProvider: true,
|
|
107
107
|
implementationProvider: true,
|
|
108
|
-
renameProvider: true,
|
|
108
|
+
renameProvider: params.capabilities.textDocument?.rename?.prepareSupport ? { prepareProvider: true } : true,
|
|
109
109
|
documentFormattingProvider: true,
|
|
110
110
|
codeActionProvider: {
|
|
111
111
|
codeActionKinds: [
|
|
@@ -225,6 +225,7 @@ function startLanguageServer(connection, env) {
|
|
|
225
225
|
connection.onRequest(vscode_languageserver_1.InlayHintRequest.type, (params, cancellationToken) => pluginHost.getInlayHints(params.textDocument, params.range, cancellationToken));
|
|
226
226
|
connection.onRequest(TagCloseRequest, (evt) => pluginHost.doTagComplete(evt.textDocument, evt.position));
|
|
227
227
|
connection.onSignatureHelp((evt, cancellationToken) => pluginHost.getSignatureHelp(evt.textDocument, evt.position, evt.context, cancellationToken));
|
|
228
|
+
connection.onPrepareRename((evt) => pluginHost.prepareRename(evt.textDocument, evt.position));
|
|
228
229
|
connection.onRenameRequest((evt) => pluginHost.rename(evt.textDocument, evt.position, evt.newName));
|
|
229
230
|
connection.onDidSaveTextDocument(updateAllDiagnostics);
|
|
230
231
|
connection.onNotification('$/onDidChangeNonAstroFile', async (e) => {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/language-server",
|
|
3
|
-
"version": "0.29.
|
|
3
|
+
"version": "0.29.5",
|
|
4
4
|
"author": "withastro",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"type": "commonjs",
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"prettier": "^2.7.1",
|
|
22
22
|
"prettier-plugin-astro": "^0.7.0",
|
|
23
23
|
"synckit": "^0.8.4",
|
|
24
|
-
"vscode-css-languageservice": "^6.
|
|
24
|
+
"vscode-css-languageservice": "^6.2.1",
|
|
25
25
|
"vscode-html-languageservice": "^5.0.0",
|
|
26
26
|
"vscode-languageserver": "^8.0.1",
|
|
27
27
|
"vscode-languageserver-protocol": "^3.17.1",
|