@astrojs/language-server 0.16.0 → 0.16.1
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 +7 -0
- package/dist/core/config/ConfigManager.d.ts +20 -16
- package/dist/core/config/ConfigManager.js +112 -46
- package/dist/core/config/interfaces.d.ts +0 -52
- package/dist/plugins/astro/AstroPlugin.d.ts +1 -6
- package/dist/plugins/astro/AstroPlugin.js +0 -82
- package/dist/plugins/css/CSSPlugin.d.ts +5 -5
- package/dist/plugins/css/CSSPlugin.js +36 -31
- package/dist/plugins/html/HTMLPlugin.d.ts +4 -4
- package/dist/plugins/html/HTMLPlugin.js +20 -16
- package/dist/plugins/html/features/astro-attributes.js +1 -0
- package/dist/plugins/typescript/TypeScriptPlugin.d.ts +2 -3
- package/dist/plugins/typescript/TypeScriptPlugin.js +24 -110
- package/dist/plugins/typescript/features/CodeActionsProvider.d.ts +3 -1
- package/dist/plugins/typescript/features/CodeActionsProvider.js +11 -5
- package/dist/plugins/typescript/features/CompletionsProvider.d.ts +3 -2
- package/dist/plugins/typescript/features/CompletionsProvider.js +9 -15
- package/dist/plugins/typescript/features/DefinitionsProvider.d.ts +9 -0
- package/dist/plugins/typescript/features/DefinitionsProvider.js +36 -0
- package/dist/server.js +23 -15
- package/package.json +1 -1
|
@@ -25,8 +25,8 @@ class HTMLPlugin {
|
|
|
25
25
|
this.styleScriptTemplate = new Set(['style']);
|
|
26
26
|
this.configManager = configManager;
|
|
27
27
|
}
|
|
28
|
-
doHover(document, position) {
|
|
29
|
-
if (!this.featureEnabled('hover')) {
|
|
28
|
+
async doHover(document, position) {
|
|
29
|
+
if (!(await this.featureEnabled(document, 'hover'))) {
|
|
30
30
|
return null;
|
|
31
31
|
}
|
|
32
32
|
const html = document.html;
|
|
@@ -46,8 +46,8 @@ class HTMLPlugin {
|
|
|
46
46
|
/**
|
|
47
47
|
* Get HTML completions
|
|
48
48
|
*/
|
|
49
|
-
getCompletions(document, position) {
|
|
50
|
-
if (!this.featureEnabled('completions')) {
|
|
49
|
+
async getCompletions(document, position) {
|
|
50
|
+
if (!(await this.featureEnabled(document, 'completions'))) {
|
|
51
51
|
return null;
|
|
52
52
|
}
|
|
53
53
|
const html = document.html;
|
|
@@ -62,12 +62,15 @@ class HTMLPlugin {
|
|
|
62
62
|
isIncomplete: true,
|
|
63
63
|
items: [],
|
|
64
64
|
};
|
|
65
|
-
this.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
65
|
+
const emmetConfig = await this.configManager.getEmmetConfig(document);
|
|
66
|
+
const extensionConfig = await this.configManager.getConfig('astro', document.uri);
|
|
67
|
+
if (extensionConfig.html.completions.emmet) {
|
|
68
|
+
this.lang.setCompletionParticipants([
|
|
69
|
+
{
|
|
70
|
+
onHtmlContent: () => (emmetResults = (0, emmet_helper_1.doComplete)(document, position, 'html', emmetConfig) || emmetResults),
|
|
71
|
+
},
|
|
72
|
+
]);
|
|
73
|
+
}
|
|
71
74
|
// If we're in a component starting tag, we do not want HTML language completions
|
|
72
75
|
// as HTML attributes are not valid for components
|
|
73
76
|
const results = (0, utils_1.isInComponentStartTag)(html, document.offsetAt(position))
|
|
@@ -84,8 +87,8 @@ class HTMLPlugin {
|
|
|
84
87
|
}
|
|
85
88
|
return this.lang.getFoldingRanges(document);
|
|
86
89
|
}
|
|
87
|
-
doTagComplete(document, position) {
|
|
88
|
-
if (!this.featureEnabled('tagComplete')) {
|
|
90
|
+
async doTagComplete(document, position) {
|
|
91
|
+
if (!(await this.featureEnabled(document, 'tagComplete'))) {
|
|
89
92
|
return null;
|
|
90
93
|
}
|
|
91
94
|
const html = document.html;
|
|
@@ -97,8 +100,8 @@ class HTMLPlugin {
|
|
|
97
100
|
}
|
|
98
101
|
return this.lang.doTagComplete(document, position, html);
|
|
99
102
|
}
|
|
100
|
-
getDocumentSymbols(document) {
|
|
101
|
-
if (!this.featureEnabled('documentSymbols')) {
|
|
103
|
+
async getDocumentSymbols(document) {
|
|
104
|
+
if (!(await this.featureEnabled(document, 'documentSymbols'))) {
|
|
102
105
|
return [];
|
|
103
106
|
}
|
|
104
107
|
const html = document.html;
|
|
@@ -134,8 +137,9 @@ class HTMLPlugin {
|
|
|
134
137
|
}));
|
|
135
138
|
}
|
|
136
139
|
}
|
|
137
|
-
featureEnabled(feature) {
|
|
138
|
-
return this.configManager.
|
|
140
|
+
async featureEnabled(document, feature) {
|
|
141
|
+
return ((await this.configManager.isEnabled(document, 'html')) &&
|
|
142
|
+
(await this.configManager.isEnabled(document, 'html', feature)));
|
|
139
143
|
}
|
|
140
144
|
}
|
|
141
145
|
exports.HTMLPlugin = HTMLPlugin;
|
|
@@ -43,6 +43,7 @@ exports.astroAttributes = (0, vscode_html_languageservice_1.newHTMLDataProvider)
|
|
|
43
43
|
{
|
|
44
44
|
name: 'is:raw',
|
|
45
45
|
description: 'Instructs the Astro compiler to treat any children of this element as text',
|
|
46
|
+
valueSet: 'v',
|
|
46
47
|
references: [
|
|
47
48
|
{
|
|
48
49
|
name: 'Astro reference',
|
|
@@ -10,6 +10,7 @@ export declare class TypeScriptPlugin implements Plugin {
|
|
|
10
10
|
private readonly codeActionsProvider;
|
|
11
11
|
private readonly completionProvider;
|
|
12
12
|
private readonly hoverProvider;
|
|
13
|
+
private readonly definitionsProvider;
|
|
13
14
|
private readonly signatureHelpProvider;
|
|
14
15
|
private readonly diagnosticsProvider;
|
|
15
16
|
private readonly documentSymbolsProvider;
|
|
@@ -19,7 +20,7 @@ export declare class TypeScriptPlugin implements Plugin {
|
|
|
19
20
|
doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
|
|
20
21
|
rename(document: AstroDocument, position: Position, newName: string): Promise<WorkspaceEdit | null>;
|
|
21
22
|
getFoldingRanges(document: AstroDocument): Promise<FoldingRange[] | null>;
|
|
22
|
-
getSemanticTokens(
|
|
23
|
+
getSemanticTokens(document: AstroDocument, range?: Range, cancellationToken?: CancellationToken): Promise<SemanticTokens | null>;
|
|
23
24
|
getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
|
|
24
25
|
getCodeActions(document: AstroDocument, range: Range, context: CodeActionContext, cancellationToken?: CancellationToken): Promise<CodeAction[]>;
|
|
25
26
|
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext, cancellationToken?: CancellationToken): Promise<AppCompletionList<CompletionItemData> | null>;
|
|
@@ -29,7 +30,5 @@ export declare class TypeScriptPlugin implements Plugin {
|
|
|
29
30
|
onWatchFileChanges(onWatchFileChangesParas: OnWatchFileChangesParam[]): Promise<void>;
|
|
30
31
|
updateNonAstroFile(fileName: string, changes: TextDocumentContentChangeEvent[]): Promise<void>;
|
|
31
32
|
getSignatureHelp(document: AstroDocument, position: Position, context: SignatureHelpContext | undefined, cancellationToken?: CancellationToken): Promise<SignatureHelp | null>;
|
|
32
|
-
private goToDefinitionFoundOnlyAlias;
|
|
33
|
-
private getGoToDefinitionRefsForImportSpecifier;
|
|
34
33
|
private featureEnabled;
|
|
35
34
|
}
|
|
@@ -1,52 +1,31 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
-
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
-
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
-
}
|
|
8
|
-
Object.defineProperty(o, k2, desc);
|
|
9
|
-
}) : (function(o, m, k, k2) {
|
|
10
|
-
if (k2 === undefined) k2 = k;
|
|
11
|
-
o[k2] = m[k];
|
|
12
|
-
}));
|
|
13
|
-
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
-
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
-
}) : function(o, v) {
|
|
16
|
-
o["default"] = v;
|
|
17
|
-
});
|
|
18
|
-
var __importStar = (this && this.__importStar) || function (mod) {
|
|
19
|
-
if (mod && mod.__esModule) return mod;
|
|
20
|
-
var result = {};
|
|
21
|
-
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
|
|
22
|
-
__setModuleDefault(result, mod);
|
|
23
|
-
return result;
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
24
4
|
};
|
|
25
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
6
|
exports.TypeScriptPlugin = void 0;
|
|
27
|
-
const typescript_1 =
|
|
7
|
+
const typescript_1 = __importDefault(require("typescript"));
|
|
28
8
|
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
29
|
-
const path_1 = require("path");
|
|
30
|
-
const utils_1 = require("../../utils");
|
|
31
9
|
const CompletionsProvider_1 = require("./features/CompletionsProvider");
|
|
32
10
|
const DiagnosticsProvider_1 = require("./features/DiagnosticsProvider");
|
|
33
11
|
const HoverProvider_1 = require("./features/HoverProvider");
|
|
34
12
|
const SignatureHelpProvider_1 = require("./features/SignatureHelpProvider");
|
|
35
|
-
const utils_2 = require("./features/utils");
|
|
36
13
|
const LanguageServiceManager_1 = require("./LanguageServiceManager");
|
|
37
|
-
const
|
|
14
|
+
const utils_1 = require("./utils");
|
|
38
15
|
const DocumentSymbolsProvider_1 = require("./features/DocumentSymbolsProvider");
|
|
39
16
|
const SemanticTokenProvider_1 = require("./features/SemanticTokenProvider");
|
|
40
17
|
const FoldingRangesProvider_1 = require("./features/FoldingRangesProvider");
|
|
41
18
|
const CodeActionsProvider_1 = require("./features/CodeActionsProvider");
|
|
19
|
+
const DefinitionsProvider_1 = require("./features/DefinitionsProvider");
|
|
42
20
|
class TypeScriptPlugin {
|
|
43
21
|
constructor(docManager, configManager, workspaceUris) {
|
|
44
22
|
this.__name = 'typescript';
|
|
45
23
|
this.configManager = configManager;
|
|
46
24
|
this.languageServiceManager = new LanguageServiceManager_1.LanguageServiceManager(docManager, workspaceUris, configManager);
|
|
47
|
-
this.codeActionsProvider = new CodeActionsProvider_1.CodeActionsProviderImpl(this.languageServiceManager);
|
|
48
|
-
this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(this.languageServiceManager);
|
|
25
|
+
this.codeActionsProvider = new CodeActionsProvider_1.CodeActionsProviderImpl(this.languageServiceManager, this.configManager);
|
|
26
|
+
this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(this.languageServiceManager, this.configManager);
|
|
49
27
|
this.hoverProvider = new HoverProvider_1.HoverProviderImpl(this.languageServiceManager);
|
|
28
|
+
this.definitionsProvider = new DefinitionsProvider_1.DefinitionsProviderImpl(this.languageServiceManager);
|
|
50
29
|
this.signatureHelpProvider = new SignatureHelpProvider_1.SignatureHelpProviderImpl(this.languageServiceManager);
|
|
51
30
|
this.diagnosticsProvider = new DiagnosticsProvider_1.DiagnosticsProviderImpl(this.languageServiceManager);
|
|
52
31
|
this.documentSymbolsProvider = new DocumentSymbolsProvider_1.DocumentSymbolsProviderImpl(this.languageServiceManager);
|
|
@@ -54,7 +33,7 @@ class TypeScriptPlugin {
|
|
|
54
33
|
this.foldingRangesProvider = new FoldingRangesProvider_1.FoldingRangesProviderImpl(this.languageServiceManager);
|
|
55
34
|
}
|
|
56
35
|
async doHover(document, position) {
|
|
57
|
-
if (!this.featureEnabled('hover')) {
|
|
36
|
+
if (!(await this.featureEnabled(document, 'hover'))) {
|
|
58
37
|
return null;
|
|
59
38
|
}
|
|
60
39
|
return this.hoverProvider.doHover(document, position);
|
|
@@ -63,7 +42,7 @@ class TypeScriptPlugin {
|
|
|
63
42
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
64
43
|
const fragment = await tsDoc.createFragment();
|
|
65
44
|
const offset = fragment.offsetAt(fragment.getGeneratedPosition(position));
|
|
66
|
-
let renames = lang.findRenameLocations((0,
|
|
45
|
+
let renames = lang.findRenameLocations((0, utils_1.toVirtualAstroFilePath)(tsDoc.filePath), offset, false, false, true);
|
|
67
46
|
if (!renames) {
|
|
68
47
|
return null;
|
|
69
48
|
}
|
|
@@ -71,13 +50,13 @@ class TypeScriptPlugin {
|
|
|
71
50
|
changes: {},
|
|
72
51
|
};
|
|
73
52
|
renames.forEach((rename) => {
|
|
74
|
-
const filePath = (0,
|
|
53
|
+
const filePath = (0, utils_1.ensureRealFilePath)(rename.fileName);
|
|
75
54
|
if (!(filePath in edit.changes)) {
|
|
76
55
|
edit.changes[filePath] = [];
|
|
77
56
|
}
|
|
78
57
|
edit.changes[filePath].push({
|
|
79
58
|
newText: newName,
|
|
80
|
-
range: (0,
|
|
59
|
+
range: (0, utils_1.convertToLocationRange)(fragment, rename.textSpan),
|
|
81
60
|
});
|
|
82
61
|
});
|
|
83
62
|
return edit;
|
|
@@ -85,27 +64,27 @@ class TypeScriptPlugin {
|
|
|
85
64
|
async getFoldingRanges(document) {
|
|
86
65
|
return this.foldingRangesProvider.getFoldingRanges(document);
|
|
87
66
|
}
|
|
88
|
-
async getSemanticTokens(
|
|
89
|
-
if (!this.featureEnabled('semanticTokens')) {
|
|
67
|
+
async getSemanticTokens(document, range, cancellationToken) {
|
|
68
|
+
if (!(await this.featureEnabled(document, 'semanticTokens'))) {
|
|
90
69
|
return null;
|
|
91
70
|
}
|
|
92
|
-
return this.semanticTokensProvider.getSemanticTokens(
|
|
71
|
+
return this.semanticTokensProvider.getSemanticTokens(document, range, cancellationToken);
|
|
93
72
|
}
|
|
94
73
|
async getDocumentSymbols(document) {
|
|
95
|
-
if (!this.featureEnabled('documentSymbols')) {
|
|
74
|
+
if (!(await this.featureEnabled(document, 'documentSymbols'))) {
|
|
96
75
|
return [];
|
|
97
76
|
}
|
|
98
77
|
const symbols = await this.documentSymbolsProvider.getDocumentSymbols(document);
|
|
99
78
|
return symbols;
|
|
100
79
|
}
|
|
101
80
|
async getCodeActions(document, range, context, cancellationToken) {
|
|
102
|
-
if (!this.featureEnabled('codeActions')) {
|
|
81
|
+
if (!(await this.featureEnabled(document, 'codeActions'))) {
|
|
103
82
|
return [];
|
|
104
83
|
}
|
|
105
84
|
return this.codeActionsProvider.getCodeActions(document, range, context, cancellationToken);
|
|
106
85
|
}
|
|
107
86
|
async getCompletions(document, position, completionContext, cancellationToken) {
|
|
108
|
-
if (!this.featureEnabled('completions')) {
|
|
87
|
+
if (!(await this.featureEnabled(document, 'completions'))) {
|
|
109
88
|
return null;
|
|
110
89
|
}
|
|
111
90
|
const completions = await this.completionProvider.getCompletions(document, position, completionContext, cancellationToken);
|
|
@@ -115,36 +94,10 @@ class TypeScriptPlugin {
|
|
|
115
94
|
return this.completionProvider.resolveCompletion(document, completionItem, cancellationToken);
|
|
116
95
|
}
|
|
117
96
|
async getDefinitions(document, position) {
|
|
118
|
-
|
|
119
|
-
const mainFragment = await tsDoc.createFragment();
|
|
120
|
-
const filePath = tsDoc.filePath;
|
|
121
|
-
const tsFilePath = (0, utils_3.toVirtualAstroFilePath)(filePath);
|
|
122
|
-
const fragmentPosition = mainFragment.getGeneratedPosition(position);
|
|
123
|
-
const fragmentOffset = mainFragment.offsetAt(fragmentPosition);
|
|
124
|
-
let defs = lang.getDefinitionAndBoundSpan(tsFilePath, fragmentOffset);
|
|
125
|
-
if (!defs || !defs.definitions) {
|
|
126
|
-
return [];
|
|
127
|
-
}
|
|
128
|
-
// Resolve all imports if we can
|
|
129
|
-
if (this.goToDefinitionFoundOnlyAlias(tsFilePath, defs.definitions)) {
|
|
130
|
-
let importDef = this.getGoToDefinitionRefsForImportSpecifier(tsFilePath, fragmentOffset, lang);
|
|
131
|
-
if (importDef) {
|
|
132
|
-
defs = importDef;
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
const docs = new utils_2.SnapshotFragmentMap(this.languageServiceManager);
|
|
136
|
-
docs.set(tsDoc.filePath, { fragment: mainFragment, snapshot: tsDoc });
|
|
137
|
-
const result = await Promise.all(defs.definitions.map(async (def) => {
|
|
138
|
-
const { fragment, snapshot } = await docs.retrieve(def.fileName);
|
|
139
|
-
const fileName = (0, utils_3.ensureRealFilePath)(def.fileName);
|
|
140
|
-
// Since we converted our files to TSX and we don't have sourcemaps, we don't know where the function is, unfortunate
|
|
141
|
-
const textSpan = (0, utils_3.isVirtualFilePath)(tsFilePath) ? { start: 0, length: 0 } : def.textSpan;
|
|
142
|
-
return vscode_languageserver_1.LocationLink.create((0, utils_1.pathToUrl)(fileName), (0, utils_3.convertToLocationRange)(fragment, textSpan), (0, utils_3.convertToLocationRange)(fragment, textSpan), (0, utils_3.convertToLocationRange)(mainFragment, defs.textSpan));
|
|
143
|
-
}));
|
|
144
|
-
return result.filter(utils_1.isNotNullOrUndefined);
|
|
97
|
+
return this.definitionsProvider.getDefinitions(document, position);
|
|
145
98
|
}
|
|
146
99
|
async getDiagnostics(document, cancellationToken) {
|
|
147
|
-
if (!this.featureEnabled('diagnostics')) {
|
|
100
|
+
if (!(await this.featureEnabled(document, 'diagnostics'))) {
|
|
148
101
|
return [];
|
|
149
102
|
}
|
|
150
103
|
return this.diagnosticsProvider.getDiagnostics(document, cancellationToken);
|
|
@@ -152,7 +105,7 @@ class TypeScriptPlugin {
|
|
|
152
105
|
async onWatchFileChanges(onWatchFileChangesParas) {
|
|
153
106
|
let doneUpdateProjectFiles = false;
|
|
154
107
|
for (const { fileName, changeType } of onWatchFileChangesParas) {
|
|
155
|
-
const scriptKind = (0,
|
|
108
|
+
const scriptKind = (0, utils_1.getScriptKindFromFileName)(fileName);
|
|
156
109
|
if (scriptKind === typescript_1.default.ScriptKind.Unknown) {
|
|
157
110
|
continue;
|
|
158
111
|
}
|
|
@@ -174,48 +127,9 @@ class TypeScriptPlugin {
|
|
|
174
127
|
async getSignatureHelp(document, position, context, cancellationToken) {
|
|
175
128
|
return this.signatureHelpProvider.getSignatureHelp(document, position, context, cancellationToken);
|
|
176
129
|
}
|
|
177
|
-
|
|
178
|
-
return
|
|
179
|
-
|
|
180
|
-
getGoToDefinitionRefsForImportSpecifier(tsFilePath, offset, lang) {
|
|
181
|
-
const program = lang.getProgram();
|
|
182
|
-
const sourceFile = program?.getSourceFile(tsFilePath);
|
|
183
|
-
if (sourceFile) {
|
|
184
|
-
let node = typescript_1.default.getTouchingPropertyName(sourceFile, offset);
|
|
185
|
-
if (node && node.kind === typescript_1.SyntaxKind.Identifier) {
|
|
186
|
-
if (node.parent.kind === typescript_1.SyntaxKind.ImportClause) {
|
|
187
|
-
let decl = node.parent.parent;
|
|
188
|
-
let spec = typescript_1.default.isStringLiteral(decl.moduleSpecifier) && decl.moduleSpecifier.text;
|
|
189
|
-
if (spec) {
|
|
190
|
-
let fileName = (0, path_1.join)((0, path_1.dirname)(tsFilePath), spec);
|
|
191
|
-
let start = node.pos + 1;
|
|
192
|
-
let def = {
|
|
193
|
-
definitions: [
|
|
194
|
-
{
|
|
195
|
-
kind: 'alias',
|
|
196
|
-
fileName,
|
|
197
|
-
name: '',
|
|
198
|
-
containerKind: '',
|
|
199
|
-
containerName: '',
|
|
200
|
-
textSpan: {
|
|
201
|
-
start: 0,
|
|
202
|
-
length: 0,
|
|
203
|
-
},
|
|
204
|
-
},
|
|
205
|
-
],
|
|
206
|
-
textSpan: {
|
|
207
|
-
start,
|
|
208
|
-
length: node.end - start,
|
|
209
|
-
},
|
|
210
|
-
};
|
|
211
|
-
return def;
|
|
212
|
-
}
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
featureEnabled(feature) {
|
|
218
|
-
return (this.configManager.enabled('typescript.enabled') && this.configManager.enabled(`typescript.${feature}.enabled`));
|
|
130
|
+
async featureEnabled(document, feature) {
|
|
131
|
+
return ((await this.configManager.isEnabled(document, 'typescript')) &&
|
|
132
|
+
(await this.configManager.isEnabled(document, 'typescript', feature)));
|
|
219
133
|
}
|
|
220
134
|
}
|
|
221
135
|
exports.TypeScriptPlugin = TypeScriptPlugin;
|
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
import { CancellationToken } from 'vscode-languageserver';
|
|
2
2
|
import { CodeAction, CodeActionContext, Range } from 'vscode-languageserver-types';
|
|
3
|
+
import { ConfigManager } from '../../../core/config';
|
|
3
4
|
import { AstroDocument } from '../../../core/documents';
|
|
4
5
|
import { CodeActionsProvider } from '../../interfaces';
|
|
5
6
|
import { LanguageServiceManager } from '../LanguageServiceManager';
|
|
6
7
|
export declare const sortImportKind: string;
|
|
7
8
|
export declare class CodeActionsProviderImpl implements CodeActionsProvider {
|
|
8
9
|
private languageServiceManager;
|
|
9
|
-
|
|
10
|
+
private configManager;
|
|
11
|
+
constructor(languageServiceManager: LanguageServiceManager, configManager: ConfigManager);
|
|
10
12
|
getCodeActions(document: AstroDocument, range: Range, context: CodeActionContext, cancellationToken?: CancellationToken): Promise<CodeAction[]>;
|
|
11
13
|
private getComponentQuickFix;
|
|
12
14
|
private organizeSortImports;
|
|
@@ -15,8 +15,9 @@ const utils_3 = require("./utils");
|
|
|
15
15
|
// These are VS Code specific CodeActionKind so they're not in the language server protocol
|
|
16
16
|
exports.sortImportKind = `${vscode_languageserver_types_1.CodeActionKind.Source}.sortImports`;
|
|
17
17
|
class CodeActionsProviderImpl {
|
|
18
|
-
constructor(languageServiceManager) {
|
|
18
|
+
constructor(languageServiceManager, configManager) {
|
|
19
19
|
this.languageServiceManager = languageServiceManager;
|
|
20
|
+
this.configManager = configManager;
|
|
20
21
|
}
|
|
21
22
|
async getCodeActions(document, range, context, cancellationToken) {
|
|
22
23
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
@@ -24,6 +25,8 @@ class CodeActionsProviderImpl {
|
|
|
24
25
|
const fragment = await tsDoc.createFragment();
|
|
25
26
|
const start = fragment.offsetAt(fragment.getGeneratedPosition(range.start));
|
|
26
27
|
const end = fragment.offsetAt(fragment.getGeneratedPosition(range.end));
|
|
28
|
+
const tsPreferences = await this.configManager.getTSPreferences(document);
|
|
29
|
+
const formatOptions = await this.configManager.getTSFormatConfig(document);
|
|
27
30
|
let result = [];
|
|
28
31
|
if (cancellationToken?.isCancellationRequested) {
|
|
29
32
|
return [];
|
|
@@ -47,8 +50,11 @@ class CodeActionsProviderImpl {
|
|
|
47
50
|
.map((diag) => Number(diag.code))
|
|
48
51
|
// We currently cannot support quick fix for unreachable code properly due to the way our TSX output is structured
|
|
49
52
|
.filter((code) => code !== 7027);
|
|
50
|
-
let codeFixes = errorCodes.includes(2304)
|
|
51
|
-
|
|
53
|
+
let codeFixes = errorCodes.includes(2304)
|
|
54
|
+
? this.getComponentQuickFix(start, end, lang, filePath, formatOptions, tsPreferences)
|
|
55
|
+
: undefined;
|
|
56
|
+
codeFixes =
|
|
57
|
+
codeFixes ?? lang.getCodeFixesAtPosition(filePath, start, end, errorCodes, formatOptions, tsPreferences);
|
|
52
58
|
const codeActions = codeFixes.map((fix) => codeFixToCodeAction(fix, context.diagnostics, context.only ? vscode_languageserver_types_1.CodeActionKind.QuickFix : vscode_languageserver_types_1.CodeActionKind.Empty));
|
|
53
59
|
result.push(...codeActions);
|
|
54
60
|
}
|
|
@@ -73,7 +79,7 @@ class CodeActionsProviderImpl {
|
|
|
73
79
|
return codeAction;
|
|
74
80
|
}
|
|
75
81
|
}
|
|
76
|
-
getComponentQuickFix(start, end, lang, filePath) {
|
|
82
|
+
getComponentQuickFix(start, end, lang, filePath, formatOptions, tsPreferences) {
|
|
77
83
|
const sourceFile = lang.getProgram()?.getSourceFile(filePath);
|
|
78
84
|
if (!sourceFile) {
|
|
79
85
|
return;
|
|
@@ -87,7 +93,7 @@ class CodeActionsProviderImpl {
|
|
|
87
93
|
}
|
|
88
94
|
const tagName = node.tagName;
|
|
89
95
|
// Unlike quick fixes, completions will be able to find the component, so let's use those to get it
|
|
90
|
-
const completion = lang.getCompletionsAtPosition(filePath, tagName.getEnd(),
|
|
96
|
+
const completion = lang.getCompletionsAtPosition(filePath, tagName.getEnd(), tsPreferences, formatOptions);
|
|
91
97
|
if (!completion) {
|
|
92
98
|
return;
|
|
93
99
|
}
|
|
@@ -4,7 +4,7 @@ import { AstroDocument } from '../../../core/documents';
|
|
|
4
4
|
import ts from 'typescript';
|
|
5
5
|
import { AppCompletionItem, AppCompletionList, CompletionsProvider } from '../../interfaces';
|
|
6
6
|
import { AstroSnapshotFragment } from '../snapshots/DocumentSnapshot';
|
|
7
|
-
|
|
7
|
+
import { ConfigManager } from '../../../core/config';
|
|
8
8
|
export interface CompletionItemData extends TextDocumentIdentifier {
|
|
9
9
|
filePath: string;
|
|
10
10
|
offset: number;
|
|
@@ -12,7 +12,8 @@ export interface CompletionItemData extends TextDocumentIdentifier {
|
|
|
12
12
|
}
|
|
13
13
|
export declare class CompletionsProviderImpl implements CompletionsProvider<CompletionItemData> {
|
|
14
14
|
private languageServiceManager;
|
|
15
|
-
|
|
15
|
+
private configManager;
|
|
16
|
+
constructor(languageServiceManager: LanguageServiceManager, configManager: ConfigManager);
|
|
16
17
|
private readonly validTriggerCharacters;
|
|
17
18
|
private isValidTriggerCharacter;
|
|
18
19
|
private lastCompletion?;
|
|
@@ -23,7 +23,7 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.codeActionChangeToTextEdit = exports.CompletionsProviderImpl =
|
|
26
|
+
exports.codeActionChangeToTextEdit = exports.CompletionsProviderImpl = void 0;
|
|
27
27
|
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
28
28
|
const vscode_languageserver_protocol_1 = require("vscode-languageserver-protocol");
|
|
29
29
|
const utils_1 = require("../../../core/documents/utils");
|
|
@@ -35,22 +35,13 @@ const utils_3 = require("../../../utils");
|
|
|
35
35
|
const lodash_1 = require("lodash");
|
|
36
36
|
const previewer_1 = require("../previewer");
|
|
37
37
|
const utils_4 = require("./utils");
|
|
38
|
-
exports.completionOptions = {
|
|
39
|
-
importModuleSpecifierPreference: 'relative',
|
|
40
|
-
importModuleSpecifierEnding: 'auto',
|
|
41
|
-
quotePreference: 'single',
|
|
42
|
-
includeCompletionsForModuleExports: true,
|
|
43
|
-
includeCompletionsForImportStatements: true,
|
|
44
|
-
includeCompletionsWithInsertText: true,
|
|
45
|
-
allowIncompleteCompletions: true,
|
|
46
|
-
includeCompletionsWithSnippetText: true,
|
|
47
|
-
};
|
|
48
38
|
// `import {...} from '..'` or `import ... from '..'`
|
|
49
39
|
// Note: Does not take into account if import is within a comment.
|
|
50
40
|
const scriptImportRegex = /\bimport\s+{([^}]*?)}\s+?from\s+['"`].+?['"`]|\bimport\s+(\w+?)\s+from\s+['"`].+?['"`]/g;
|
|
51
41
|
class CompletionsProviderImpl {
|
|
52
|
-
constructor(languageServiceManager) {
|
|
42
|
+
constructor(languageServiceManager, configManager) {
|
|
53
43
|
this.languageServiceManager = languageServiceManager;
|
|
44
|
+
this.configManager = configManager;
|
|
54
45
|
this.validTriggerCharacters = ['.', '"', "'", '`', '/', '@', '<', '#'];
|
|
55
46
|
}
|
|
56
47
|
isValidTriggerCharacter(character) {
|
|
@@ -97,12 +88,14 @@ class CompletionsProviderImpl {
|
|
|
97
88
|
if (!isCompletionInsideFrontmatter && !(0, utils_1.isComponentTag)(node) && !isCompletionInsideExpression) {
|
|
98
89
|
return null;
|
|
99
90
|
}
|
|
91
|
+
const tsPreferences = await this.configManager.getTSPreferences(document);
|
|
92
|
+
const formatOptions = await this.configManager.getTSFormatConfig(document);
|
|
100
93
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
101
94
|
const filePath = (0, utils_2.toVirtualAstroFilePath)(tsDoc.filePath);
|
|
102
95
|
const completions = lang.getCompletionsAtPosition(filePath, offset, {
|
|
103
|
-
...
|
|
96
|
+
...tsPreferences,
|
|
104
97
|
triggerCharacter: validTriggerCharacter,
|
|
105
|
-
});
|
|
98
|
+
}, formatOptions);
|
|
106
99
|
if (completions === undefined || completions.entries.length === 0) {
|
|
107
100
|
return null;
|
|
108
101
|
}
|
|
@@ -123,6 +116,7 @@ class CompletionsProviderImpl {
|
|
|
123
116
|
}
|
|
124
117
|
async resolveCompletion(document, item, cancellationToken) {
|
|
125
118
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
119
|
+
const tsPreferences = await this.configManager.getTSPreferences(document);
|
|
126
120
|
const data = item.data;
|
|
127
121
|
if (!data || !data.filePath || cancellationToken?.isCancellationRequested) {
|
|
128
122
|
return item;
|
|
@@ -133,7 +127,7 @@ class CompletionsProviderImpl {
|
|
|
133
127
|
data.originalItem.name, // entryName
|
|
134
128
|
{}, // formatOptions
|
|
135
129
|
data.originalItem.source, // source
|
|
136
|
-
|
|
130
|
+
tsPreferences, // preferences
|
|
137
131
|
data.originalItem.data // data
|
|
138
132
|
);
|
|
139
133
|
if (detail) {
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { Position, LocationLink } from 'vscode-languageserver-types';
|
|
2
|
+
import { AstroDocument } from '../../../core/documents';
|
|
3
|
+
import { DefinitionsProvider } from '../../interfaces';
|
|
4
|
+
import { LanguageServiceManager } from '../LanguageServiceManager';
|
|
5
|
+
export declare class DefinitionsProviderImpl implements DefinitionsProvider {
|
|
6
|
+
private languageServiceManager;
|
|
7
|
+
constructor(languageServiceManager: LanguageServiceManager);
|
|
8
|
+
getDefinitions(document: AstroDocument, position: Position): Promise<LocationLink[]>;
|
|
9
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.DefinitionsProviderImpl = void 0;
|
|
4
|
+
const vscode_languageserver_types_1 = require("vscode-languageserver-types");
|
|
5
|
+
const utils_1 = require("../../../utils");
|
|
6
|
+
const utils_2 = require("../utils");
|
|
7
|
+
const utils_3 = require("./utils");
|
|
8
|
+
class DefinitionsProviderImpl {
|
|
9
|
+
constructor(languageServiceManager) {
|
|
10
|
+
this.languageServiceManager = languageServiceManager;
|
|
11
|
+
}
|
|
12
|
+
async getDefinitions(document, position) {
|
|
13
|
+
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
14
|
+
const mainFragment = await tsDoc.createFragment();
|
|
15
|
+
const tsFilePath = (0, utils_2.toVirtualAstroFilePath)(tsDoc.filePath);
|
|
16
|
+
const fragmentPosition = mainFragment.getGeneratedPosition(position);
|
|
17
|
+
const fragmentOffset = mainFragment.offsetAt(fragmentPosition);
|
|
18
|
+
const defs = lang.getDefinitionAndBoundSpan(tsFilePath, fragmentOffset);
|
|
19
|
+
if (!defs || !defs.definitions) {
|
|
20
|
+
return [];
|
|
21
|
+
}
|
|
22
|
+
const docs = new utils_3.SnapshotFragmentMap(this.languageServiceManager);
|
|
23
|
+
docs.set(tsFilePath, { fragment: mainFragment, snapshot: tsDoc });
|
|
24
|
+
const result = await Promise.all(defs.definitions.map(async (def) => {
|
|
25
|
+
const { fragment, snapshot } = await docs.retrieve(def.fileName);
|
|
26
|
+
const fileName = (0, utils_2.ensureRealFilePath)(def.fileName);
|
|
27
|
+
// For Astro, Svelte and Vue, the position is wrongly mapped to the end of the file due to the TSX output
|
|
28
|
+
// So we'll instead redirect to the beginning of the file
|
|
29
|
+
const isFramework = (0, utils_2.isFrameworkFilePath)(def.fileName) || (0, utils_2.isAstroFilePath)(def.fileName);
|
|
30
|
+
const textSpan = isFramework && tsDoc.filePath !== def.fileName ? { start: 0, length: 0 } : def.textSpan;
|
|
31
|
+
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));
|
|
32
|
+
}));
|
|
33
|
+
return result.filter(utils_1.isNotNullOrUndefined);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
exports.DefinitionsProviderImpl = DefinitionsProviderImpl;
|
package/dist/server.js
CHANGED
|
@@ -41,9 +41,10 @@ const TagCloseRequest = new vscode.RequestType('html/tag');
|
|
|
41
41
|
// Start the language server
|
|
42
42
|
function startLanguageServer(connection) {
|
|
43
43
|
// Create our managers
|
|
44
|
-
const configManager = new ConfigManager_1.ConfigManager();
|
|
45
44
|
const documentManager = new DocumentManager_1.DocumentManager();
|
|
46
45
|
const pluginHost = new PluginHost_1.PluginHost(documentManager);
|
|
46
|
+
const configManager = new ConfigManager_1.ConfigManager(connection);
|
|
47
|
+
let hasConfigurationCapability = false;
|
|
47
48
|
connection.onInitialize((params) => {
|
|
48
49
|
const workspaceUris = params.workspaceFolders?.map((folder) => folder.uri.toString()) ?? [params.rootUri ?? ''];
|
|
49
50
|
workspaceUris.forEach((uri) => {
|
|
@@ -62,6 +63,7 @@ function startLanguageServer(connection) {
|
|
|
62
63
|
});
|
|
63
64
|
}
|
|
64
65
|
});
|
|
66
|
+
hasConfigurationCapability = !!(params.capabilities.workspace && !!params.capabilities.workspace.configuration);
|
|
65
67
|
pluginHost.initialize({
|
|
66
68
|
filterIncompleteCompletions: !params.initializationOptions?.dontFilterIncompleteCompletions,
|
|
67
69
|
definitionLinkSupport: !!params.capabilities.textDocument?.definition?.linkSupport,
|
|
@@ -74,15 +76,6 @@ function startLanguageServer(connection) {
|
|
|
74
76
|
pluginHost.registerPlugin(new AstroPlugin_1.AstroPlugin(documentManager, configManager, workspaceUris));
|
|
75
77
|
pluginHost.registerPlugin(new plugins_1.TypeScriptPlugin(documentManager, configManager, workspaceUris));
|
|
76
78
|
}
|
|
77
|
-
// Update language-server config with what the user supplied to us at launch
|
|
78
|
-
let astroConfiguration = params.initializationOptions?.configuration?.astro;
|
|
79
|
-
if (astroConfiguration) {
|
|
80
|
-
configManager.updateConfig(astroConfiguration);
|
|
81
|
-
}
|
|
82
|
-
let emmetConfiguration = params.initializationOptions?.configuration?.emmet;
|
|
83
|
-
if (emmetConfiguration) {
|
|
84
|
-
configManager.updateEmmetConfig(emmetConfiguration);
|
|
85
|
-
}
|
|
86
79
|
return {
|
|
87
80
|
capabilities: {
|
|
88
81
|
textDocumentSync: {
|
|
@@ -147,10 +140,18 @@ function startLanguageServer(connection) {
|
|
|
147
140
|
},
|
|
148
141
|
};
|
|
149
142
|
});
|
|
150
|
-
//
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
143
|
+
// The params don't matter here because in "pull mode" it's always null, it's intended that when the config is updated
|
|
144
|
+
// you should just reset "your internal cache" and get the config again for relevant documents, weird API design
|
|
145
|
+
connection.onDidChangeConfiguration(async (change) => {
|
|
146
|
+
if (hasConfigurationCapability) {
|
|
147
|
+
configManager.updateConfig();
|
|
148
|
+
documentManager.getAllOpenedByClient().forEach(async (document) => {
|
|
149
|
+
await configManager.getConfig('astro', document[1].uri);
|
|
150
|
+
});
|
|
151
|
+
}
|
|
152
|
+
else {
|
|
153
|
+
configManager.updateGlobalConfig(change.settings.astro || ConfigManager_1.defaultLSConfig);
|
|
154
|
+
}
|
|
154
155
|
});
|
|
155
156
|
// Documents
|
|
156
157
|
connection.onDidOpenTextDocument((params) => {
|
|
@@ -206,10 +207,17 @@ function startLanguageServer(connection) {
|
|
|
206
207
|
updateAllDiagnostics();
|
|
207
208
|
});
|
|
208
209
|
documentManager.on('documentChange', (0, utils_1.debounceThrottle)(async (document) => diagnosticsManager.update(document), 1000));
|
|
209
|
-
documentManager.on('documentClose', (document) =>
|
|
210
|
+
documentManager.on('documentClose', (document) => {
|
|
211
|
+
diagnosticsManager.removeDiagnostics(document);
|
|
212
|
+
configManager.removeDocument(document.uri);
|
|
213
|
+
});
|
|
210
214
|
// Taking off 🚀
|
|
211
215
|
connection.onInitialized(() => {
|
|
212
216
|
connection.console.log('Successfully initialized! 🚀');
|
|
217
|
+
// Register for all configuration changes.
|
|
218
|
+
if (hasConfigurationCapability) {
|
|
219
|
+
connection.client.register(vscode_languageserver_1.DidChangeConfigurationNotification.type);
|
|
220
|
+
}
|
|
213
221
|
});
|
|
214
222
|
connection.listen();
|
|
215
223
|
}
|