@astrojs/language-server 0.16.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +30 -0
- package/dist/core/config/ConfigManager.d.ts +25 -16
- package/dist/core/config/ConfigManager.js +160 -46
- package/dist/core/config/interfaces.d.ts +4 -51
- package/dist/core/documents/AstroDocument.d.ts +1 -0
- package/dist/core/documents/AstroDocument.js +1 -0
- package/dist/core/documents/DocumentMapper.d.ts +2 -0
- package/dist/core/documents/DocumentMapper.js +7 -5
- package/dist/core/documents/utils.d.ts +1 -0
- package/dist/core/documents/utils.js +16 -1
- package/dist/plugins/PluginHost.d.ts +3 -1
- package/dist/plugins/PluginHost.js +8 -0
- package/dist/plugins/astro/AstroPlugin.d.ts +1 -6
- package/dist/plugins/astro/AstroPlugin.js +10 -85
- package/dist/plugins/astro/features/CompletionsProvider.d.ts +4 -5
- package/dist/plugins/astro/features/CompletionsProvider.js +53 -58
- package/dist/plugins/css/CSSPlugin.d.ts +5 -5
- package/dist/plugins/css/CSSPlugin.js +36 -31
- package/dist/plugins/html/HTMLPlugin.d.ts +6 -5
- package/dist/plugins/html/HTMLPlugin.js +38 -16
- package/dist/plugins/html/features/astro-attributes.js +1 -0
- package/dist/plugins/interfaces.d.ts +5 -2
- package/dist/plugins/typescript/TypeScriptPlugin.d.ts +7 -4
- package/dist/plugins/typescript/TypeScriptPlugin.js +34 -110
- package/dist/plugins/typescript/features/CodeActionsProvider.d.ts +3 -1
- package/dist/plugins/typescript/features/CodeActionsProvider.js +82 -17
- package/dist/plugins/typescript/features/CompletionsProvider.d.ts +5 -3
- package/dist/plugins/typescript/features/CompletionsProvider.js +112 -56
- package/dist/plugins/typescript/features/DefinitionsProvider.d.ts +9 -0
- package/dist/plugins/typescript/features/DefinitionsProvider.js +57 -0
- package/dist/plugins/typescript/features/DiagnosticsProvider.js +58 -15
- package/dist/plugins/typescript/features/FoldingRangesProvider.js +13 -6
- package/dist/plugins/typescript/features/FormattingProvider.d.ts +11 -0
- package/dist/plugins/typescript/features/FormattingProvider.js +132 -0
- package/dist/plugins/typescript/features/HoverProvider.js +14 -1
- package/dist/plugins/typescript/features/InlayHintsProvider.d.ts +12 -0
- package/dist/plugins/typescript/features/InlayHintsProvider.js +36 -0
- package/dist/plugins/typescript/features/SignatureHelpProvider.js +9 -1
- package/dist/plugins/typescript/language-service.js +18 -0
- package/dist/plugins/typescript/snapshots/DocumentSnapshot.d.ts +22 -2
- package/dist/plugins/typescript/snapshots/DocumentSnapshot.js +48 -1
- package/dist/plugins/typescript/snapshots/SnapshotManager.js +1 -0
- package/dist/plugins/typescript/snapshots/utils.js +3 -2
- package/dist/plugins/typescript/utils.d.ts +11 -1
- package/dist/plugins/typescript/utils.js +17 -1
- package/dist/server.js +27 -15
- package/package.json +7 -6
|
@@ -1,22 +1,15 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
3
|
exports.AstroPlugin = void 0;
|
|
7
|
-
const typescript_1 = __importDefault(require("typescript"));
|
|
8
4
|
const vscode_languageserver_1 = require("vscode-languageserver");
|
|
9
|
-
const documents_1 = require("../../core/documents");
|
|
10
|
-
const utils_1 = require("../../utils");
|
|
11
5
|
const LanguageServiceManager_1 = require("../typescript/LanguageServiceManager");
|
|
12
|
-
const utils_2 = require("../typescript/utils");
|
|
13
6
|
const CompletionsProvider_1 = require("./features/CompletionsProvider");
|
|
14
7
|
class AstroPlugin {
|
|
15
8
|
constructor(docManager, configManager, workspaceUris) {
|
|
16
9
|
this.__name = 'astro';
|
|
17
10
|
this.configManager = configManager;
|
|
18
11
|
this.languageServiceManager = new LanguageServiceManager_1.LanguageServiceManager(docManager, workspaceUris, configManager);
|
|
19
|
-
this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(
|
|
12
|
+
this.completionProvider = new CompletionsProvider_1.CompletionsProviderImpl(this.languageServiceManager);
|
|
20
13
|
}
|
|
21
14
|
async getCompletions(document, position, completionContext) {
|
|
22
15
|
const completions = this.completionProvider.getCompletions(document, position, completionContext);
|
|
@@ -28,8 +21,15 @@ class AstroPlugin {
|
|
|
28
21
|
// Currently editing frontmatter, don't fold
|
|
29
22
|
if (frontmatter.state !== 'closed')
|
|
30
23
|
return foldingRanges;
|
|
31
|
-
|
|
32
|
-
|
|
24
|
+
// The way folding ranges work is by folding anything between the starting position and the ending one, as such
|
|
25
|
+
// the start in this case should be after the frontmatter start (after the starting ---) until the last character
|
|
26
|
+
// of the last line of the frontmatter before its ending (before the closing ---)
|
|
27
|
+
// ---
|
|
28
|
+
// ^ -- start
|
|
29
|
+
// console.log("Astro")
|
|
30
|
+
// --- ^ -- end
|
|
31
|
+
const start = document.positionAt(frontmatter.startOffset + 3);
|
|
32
|
+
const end = document.positionAt(frontmatter.endOffset - 1);
|
|
33
33
|
return [
|
|
34
34
|
{
|
|
35
35
|
startLine: start.line,
|
|
@@ -40,80 +40,5 @@ class AstroPlugin {
|
|
|
40
40
|
},
|
|
41
41
|
];
|
|
42
42
|
}
|
|
43
|
-
async getDefinitions(document, position) {
|
|
44
|
-
if (this.isInsideFrontmatter(document, position)) {
|
|
45
|
-
return [];
|
|
46
|
-
}
|
|
47
|
-
const offset = document.offsetAt(position);
|
|
48
|
-
const html = document.html;
|
|
49
|
-
const node = html.findNodeAt(offset);
|
|
50
|
-
if (!this.isComponentTag(node)) {
|
|
51
|
-
return [];
|
|
52
|
-
}
|
|
53
|
-
const [componentName] = node.tag.split(':');
|
|
54
|
-
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
55
|
-
const defs = this.getDefinitionsForComponentName(document, lang, componentName);
|
|
56
|
-
if (!defs || !defs.length) {
|
|
57
|
-
return [];
|
|
58
|
-
}
|
|
59
|
-
const startRange = vscode_languageserver_1.Range.create(vscode_languageserver_1.Position.create(0, 0), vscode_languageserver_1.Position.create(0, 0));
|
|
60
|
-
const links = defs.map((def) => {
|
|
61
|
-
const defFilePath = (0, utils_2.ensureRealFilePath)(def.fileName);
|
|
62
|
-
return vscode_languageserver_1.LocationLink.create((0, utils_1.pathToUrl)(defFilePath), startRange, startRange);
|
|
63
|
-
});
|
|
64
|
-
return links;
|
|
65
|
-
}
|
|
66
|
-
isInsideFrontmatter(document, position) {
|
|
67
|
-
return (0, documents_1.isInsideFrontmatter)(document.getText(), document.offsetAt(position));
|
|
68
|
-
}
|
|
69
|
-
isComponentTag(node) {
|
|
70
|
-
if (!node.tag) {
|
|
71
|
-
return false;
|
|
72
|
-
}
|
|
73
|
-
const firstChar = node.tag[0];
|
|
74
|
-
return /[A-Z]/.test(firstChar);
|
|
75
|
-
}
|
|
76
|
-
getDefinitionsForComponentName(document, lang, componentName) {
|
|
77
|
-
const filePath = (0, utils_1.urlToPath)(document.uri);
|
|
78
|
-
const tsFilePath = (0, utils_2.toVirtualAstroFilePath)(filePath);
|
|
79
|
-
const program = lang.getProgram();
|
|
80
|
-
const sourceFile = program?.getSourceFile(tsFilePath);
|
|
81
|
-
if (!sourceFile) {
|
|
82
|
-
return undefined;
|
|
83
|
-
}
|
|
84
|
-
const specifier = this.getImportSpecifierForIdentifier(sourceFile, componentName);
|
|
85
|
-
if (!specifier) {
|
|
86
|
-
return [];
|
|
87
|
-
}
|
|
88
|
-
const defs = lang.getDefinitionAtPosition(tsFilePath, specifier.getStart());
|
|
89
|
-
if (!defs) {
|
|
90
|
-
return undefined;
|
|
91
|
-
}
|
|
92
|
-
return defs;
|
|
93
|
-
}
|
|
94
|
-
getImportSpecifierForIdentifier(sourceFile, identifier) {
|
|
95
|
-
let importSpecifier = undefined;
|
|
96
|
-
typescript_1.default.forEachChild(sourceFile, (tsNode) => {
|
|
97
|
-
if (typescript_1.default.isImportDeclaration(tsNode)) {
|
|
98
|
-
if (tsNode.importClause) {
|
|
99
|
-
const { name, namedBindings } = tsNode.importClause;
|
|
100
|
-
if (name && name.getText() === identifier) {
|
|
101
|
-
importSpecifier = tsNode.moduleSpecifier;
|
|
102
|
-
return true;
|
|
103
|
-
}
|
|
104
|
-
else if (namedBindings && namedBindings.kind === typescript_1.default.SyntaxKind.NamedImports) {
|
|
105
|
-
const elements = namedBindings.elements;
|
|
106
|
-
for (let elem of elements) {
|
|
107
|
-
if (elem.name.getText() === identifier) {
|
|
108
|
-
importSpecifier = tsNode.moduleSpecifier;
|
|
109
|
-
return true;
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
}
|
|
115
|
-
});
|
|
116
|
-
return importSpecifier;
|
|
117
|
-
}
|
|
118
43
|
}
|
|
119
44
|
exports.AstroPlugin = AstroPlugin;
|
|
@@ -1,17 +1,16 @@
|
|
|
1
1
|
import type { AppCompletionList, CompletionsProvider } from '../../interfaces';
|
|
2
|
-
import type { AstroDocument
|
|
2
|
+
import type { AstroDocument } from '../../../core/documents';
|
|
3
3
|
import { CompletionContext, Position } from 'vscode-languageserver';
|
|
4
4
|
import { LanguageServiceManager as TypeScriptLanguageServiceManager } from '../../typescript/LanguageServiceManager';
|
|
5
5
|
export declare class CompletionsProviderImpl implements CompletionsProvider {
|
|
6
|
-
private readonly docManager;
|
|
7
6
|
private readonly languageServiceManager;
|
|
7
|
+
private lastCompletion;
|
|
8
8
|
directivesHTMLLang: import("vscode-html-languageservice").LanguageService;
|
|
9
|
-
constructor(
|
|
9
|
+
constructor(languageServiceManager: TypeScriptLanguageServiceManager);
|
|
10
10
|
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<AppCompletionList | null>;
|
|
11
11
|
private getComponentScriptCompletion;
|
|
12
|
-
private
|
|
12
|
+
private getPropCompletionsAndFilePath;
|
|
13
13
|
private getImportedSymbol;
|
|
14
14
|
private getPropType;
|
|
15
15
|
private getCompletionItemForProperty;
|
|
16
|
-
private isAstroComponent;
|
|
17
16
|
}
|
|
@@ -13,21 +13,18 @@ const vscode_html_languageservice_1 = require("vscode-html-languageservice");
|
|
|
13
13
|
const astro_attributes_1 = require("../../html/features/astro-attributes");
|
|
14
14
|
const utils_4 = require("../../html/utils");
|
|
15
15
|
class CompletionsProviderImpl {
|
|
16
|
-
constructor(
|
|
16
|
+
constructor(languageServiceManager) {
|
|
17
|
+
this.lastCompletion = null;
|
|
17
18
|
this.directivesHTMLLang = (0, vscode_html_languageservice_1.getLanguageService)({
|
|
18
19
|
customDataProviders: [astro_attributes_1.astroDirectives],
|
|
19
20
|
useDefaultDataProvider: false,
|
|
20
21
|
});
|
|
21
|
-
this.docManager = docManager;
|
|
22
22
|
this.languageServiceManager = languageServiceManager;
|
|
23
23
|
}
|
|
24
24
|
async getCompletions(document, position, completionContext) {
|
|
25
|
-
const doc = this.docManager.get(document.uri);
|
|
26
|
-
if (!doc)
|
|
27
|
-
return null;
|
|
28
25
|
let items = [];
|
|
29
26
|
if (completionContext?.triggerCharacter === '-') {
|
|
30
|
-
const frontmatter = this.getComponentScriptCompletion(
|
|
27
|
+
const frontmatter = this.getComponentScriptCompletion(document, position);
|
|
31
28
|
if (frontmatter)
|
|
32
29
|
items.push(frontmatter);
|
|
33
30
|
}
|
|
@@ -35,11 +32,11 @@ class CompletionsProviderImpl {
|
|
|
35
32
|
const offset = document.offsetAt(position);
|
|
36
33
|
const node = html.findNodeAt(offset);
|
|
37
34
|
if ((0, utils_1.isInComponentStartTag)(html, offset) && !(0, utils_1.isInsideExpression)(document.getText(), node.start, offset)) {
|
|
38
|
-
const props = await this.
|
|
35
|
+
const { completions: props, componentFilePath } = await this.getPropCompletionsAndFilePath(document, position, completionContext);
|
|
39
36
|
if (props.length) {
|
|
40
37
|
items.push(...props);
|
|
41
38
|
}
|
|
42
|
-
const isAstro =
|
|
39
|
+
const isAstro = componentFilePath?.endsWith('.astro');
|
|
43
40
|
if (!isAstro) {
|
|
44
41
|
const directives = (0, utils_4.removeDataAttrCompletion)(this.directivesHTMLLang.doComplete(document, position, html).items);
|
|
45
42
|
items.push(...directives);
|
|
@@ -47,7 +44,7 @@ class CompletionsProviderImpl {
|
|
|
47
44
|
}
|
|
48
45
|
return vscode_languageserver_1.CompletionList.create(items, true);
|
|
49
46
|
}
|
|
50
|
-
getComponentScriptCompletion(document, position
|
|
47
|
+
getComponentScriptCompletion(document, position) {
|
|
51
48
|
const base = {
|
|
52
49
|
kind: vscode_languageserver_1.CompletionItemKind.Snippet,
|
|
53
50
|
label: '---',
|
|
@@ -55,7 +52,7 @@ class CompletionsProviderImpl {
|
|
|
55
52
|
preselect: true,
|
|
56
53
|
detail: 'Component script',
|
|
57
54
|
insertTextFormat: vscode_languageserver_1.InsertTextFormat.Snippet,
|
|
58
|
-
commitCharacters: [
|
|
55
|
+
commitCharacters: [],
|
|
59
56
|
};
|
|
60
57
|
const prefix = document.getLineUntilOffset(document.offsetAt(position));
|
|
61
58
|
if (document.astroMeta.frontmatter.state === null) {
|
|
@@ -78,25 +75,25 @@ class CompletionsProviderImpl {
|
|
|
78
75
|
}
|
|
79
76
|
return null;
|
|
80
77
|
}
|
|
81
|
-
async
|
|
78
|
+
async getPropCompletionsAndFilePath(document, position, completionContext) {
|
|
82
79
|
const offset = document.offsetAt(position);
|
|
83
80
|
const html = document.html;
|
|
84
81
|
const node = html.findNodeAt(offset);
|
|
85
82
|
if (!(0, utils_2.isPossibleComponent)(node)) {
|
|
86
|
-
return [];
|
|
83
|
+
return { completions: [], componentFilePath: null };
|
|
87
84
|
}
|
|
88
85
|
const inAttribute = node.start + node.tag.length < offset;
|
|
89
86
|
if (!inAttribute) {
|
|
90
|
-
return [];
|
|
87
|
+
return { completions: [], componentFilePath: null };
|
|
91
88
|
}
|
|
92
89
|
if (completionContext?.triggerCharacter === '/' || completionContext?.triggerCharacter === '>') {
|
|
93
|
-
return [];
|
|
90
|
+
return { completions: [], componentFilePath: null };
|
|
94
91
|
}
|
|
95
92
|
// If inside of attribute value, skip.
|
|
96
93
|
if (completionContext &&
|
|
97
94
|
completionContext.triggerKind === vscode_languageserver_1.CompletionTriggerKind.TriggerCharacter &&
|
|
98
95
|
completionContext.triggerCharacter === '"') {
|
|
99
|
-
return [];
|
|
96
|
+
return { completions: [], componentFilePath: null };
|
|
100
97
|
}
|
|
101
98
|
const componentName = node.tag;
|
|
102
99
|
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
@@ -106,18 +103,34 @@ class CompletionsProviderImpl {
|
|
|
106
103
|
const sourceFile = program?.getSourceFile(tsFilePath);
|
|
107
104
|
const typeChecker = program?.getTypeChecker();
|
|
108
105
|
if (!sourceFile || !typeChecker) {
|
|
109
|
-
return [];
|
|
106
|
+
return { completions: [], componentFilePath: null };
|
|
110
107
|
}
|
|
111
108
|
// Get the import statement
|
|
112
109
|
const imp = this.getImportedSymbol(sourceFile, componentName);
|
|
113
110
|
const importType = imp && typeChecker.getTypeAtLocation(imp);
|
|
114
111
|
if (!importType) {
|
|
115
|
-
return [];
|
|
112
|
+
return { completions: [], componentFilePath: null };
|
|
113
|
+
}
|
|
114
|
+
const symbol = importType.getSymbol();
|
|
115
|
+
if (!symbol) {
|
|
116
|
+
return { completions: [], componentFilePath: null };
|
|
117
|
+
}
|
|
118
|
+
const symbolDeclaration = symbol.declarations;
|
|
119
|
+
if (!symbolDeclaration) {
|
|
120
|
+
return { completions: [], componentFilePath: null };
|
|
121
|
+
}
|
|
122
|
+
const filePath = symbolDeclaration[0].getSourceFile().fileName;
|
|
123
|
+
const componentSnapshot = await this.languageServiceManager.getSnapshot(filePath);
|
|
124
|
+
if (this.lastCompletion) {
|
|
125
|
+
if (this.lastCompletion.tag === componentName &&
|
|
126
|
+
this.lastCompletion.documentVersion == componentSnapshot.version) {
|
|
127
|
+
return { completions: this.lastCompletion.completions, componentFilePath: filePath };
|
|
128
|
+
}
|
|
116
129
|
}
|
|
117
130
|
// Get the component's props type
|
|
118
|
-
const componentType = this.getPropType(
|
|
131
|
+
const componentType = this.getPropType(symbolDeclaration, typeChecker);
|
|
119
132
|
if (!componentType) {
|
|
120
|
-
return [];
|
|
133
|
+
return { completions: [], componentFilePath: null };
|
|
121
134
|
}
|
|
122
135
|
let completionItems = [];
|
|
123
136
|
// Add completions for this component's props type properties
|
|
@@ -127,11 +140,12 @@ class CompletionsProviderImpl {
|
|
|
127
140
|
let completionItem = this.getCompletionItemForProperty(property, typeChecker, type);
|
|
128
141
|
completionItems.push(completionItem);
|
|
129
142
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
143
|
+
this.lastCompletion = {
|
|
144
|
+
tag: componentName,
|
|
145
|
+
documentVersion: componentSnapshot.version,
|
|
146
|
+
completions: completionItems,
|
|
147
|
+
};
|
|
148
|
+
return { completions: completionItems, componentFilePath: filePath };
|
|
135
149
|
}
|
|
136
150
|
getImportedSymbol(sourceFile, identifier) {
|
|
137
151
|
for (let list of sourceFile.getChildren()) {
|
|
@@ -159,24 +173,20 @@ class CompletionsProviderImpl {
|
|
|
159
173
|
}
|
|
160
174
|
return null;
|
|
161
175
|
}
|
|
162
|
-
getPropType(
|
|
163
|
-
const
|
|
164
|
-
if (!sym) {
|
|
165
|
-
return null;
|
|
166
|
-
}
|
|
167
|
-
for (const decl of sym?.getDeclarations() || []) {
|
|
176
|
+
getPropType(declarations, typeChecker) {
|
|
177
|
+
for (const decl of declarations) {
|
|
168
178
|
const fileName = (0, utils_3.toVirtualFilePath)(decl.getSourceFile().fileName);
|
|
169
|
-
if (fileName.endsWith('.tsx') || fileName.endsWith('.jsx')) {
|
|
170
|
-
if (!typescript_1.default.isFunctionDeclaration(decl)) {
|
|
171
|
-
console.error(`We only support
|
|
179
|
+
if (fileName.endsWith('.tsx') || fileName.endsWith('.jsx') || fileName.endsWith('.d.ts')) {
|
|
180
|
+
if (!typescript_1.default.isFunctionDeclaration(decl) && !typescript_1.default.isFunctionTypeNode(decl)) {
|
|
181
|
+
console.error(`We only support functions declarations at the moment`);
|
|
172
182
|
continue;
|
|
173
183
|
}
|
|
174
184
|
const fn = decl;
|
|
175
185
|
if (!fn.parameters.length)
|
|
176
186
|
continue;
|
|
177
187
|
const param1 = fn.parameters[0];
|
|
178
|
-
const
|
|
179
|
-
return
|
|
188
|
+
const propType = typeChecker.getTypeAtLocation(param1);
|
|
189
|
+
return propType;
|
|
180
190
|
}
|
|
181
191
|
}
|
|
182
192
|
return null;
|
|
@@ -201,7 +211,15 @@ class CompletionsProviderImpl {
|
|
|
201
211
|
insertText: insertText,
|
|
202
212
|
insertTextFormat: vscode_languageserver_1.InsertTextFormat.Snippet,
|
|
203
213
|
commitCharacters: [],
|
|
214
|
+
// Ensure that props shows up first as a completion, despite this plugin being ran after the HTML one
|
|
215
|
+
sortText: '\0',
|
|
204
216
|
};
|
|
217
|
+
if (mem.flags & typescript_1.default.SymbolFlags.Optional) {
|
|
218
|
+
item.filterText = item.label;
|
|
219
|
+
item.label += '?';
|
|
220
|
+
// Put optional props at a lower priority
|
|
221
|
+
item.sortText = '_';
|
|
222
|
+
}
|
|
205
223
|
mem.getDocumentationComment(typeChecker);
|
|
206
224
|
let description = mem
|
|
207
225
|
.getDocumentationComment(typeChecker)
|
|
@@ -216,28 +234,5 @@ class CompletionsProviderImpl {
|
|
|
216
234
|
}
|
|
217
235
|
return item;
|
|
218
236
|
}
|
|
219
|
-
async isAstroComponent(document, node) {
|
|
220
|
-
const { lang, tsDoc } = await this.languageServiceManager.getLSAndTSDoc(document);
|
|
221
|
-
// Get the source file
|
|
222
|
-
const tsFilePath = (0, utils_3.toVirtualAstroFilePath)(tsDoc.filePath);
|
|
223
|
-
const program = lang.getProgram();
|
|
224
|
-
const sourceFile = program?.getSourceFile(tsFilePath);
|
|
225
|
-
const typeChecker = program?.getTypeChecker();
|
|
226
|
-
if (!sourceFile || !typeChecker) {
|
|
227
|
-
return false;
|
|
228
|
-
}
|
|
229
|
-
const componentName = node.tag;
|
|
230
|
-
const imp = this.getImportedSymbol(sourceFile, componentName);
|
|
231
|
-
const importType = imp && typeChecker.getTypeAtLocation(imp);
|
|
232
|
-
if (!importType) {
|
|
233
|
-
return false;
|
|
234
|
-
}
|
|
235
|
-
const symbolDeclaration = importType.getSymbol()?.declarations;
|
|
236
|
-
if (symbolDeclaration) {
|
|
237
|
-
const fileName = symbolDeclaration[0].getSourceFile().fileName;
|
|
238
|
-
return fileName.endsWith('.astro');
|
|
239
|
-
}
|
|
240
|
-
return false;
|
|
241
|
-
}
|
|
242
237
|
}
|
|
243
238
|
exports.CompletionsProviderImpl = CompletionsProviderImpl;
|
|
@@ -8,14 +8,14 @@ export declare class CSSPlugin implements Plugin {
|
|
|
8
8
|
private cssDocuments;
|
|
9
9
|
private triggerCharacters;
|
|
10
10
|
constructor(configManager: ConfigManager);
|
|
11
|
-
doHover(document: AstroDocument, position: Position): Hover | null
|
|
11
|
+
doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
|
|
12
12
|
private doHoverInternal;
|
|
13
|
-
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): CompletionList | null
|
|
13
|
+
getCompletions(document: AstroDocument, position: Position, completionContext?: CompletionContext): Promise<CompletionList | null>;
|
|
14
14
|
private getCompletionsInternal;
|
|
15
|
-
getDocumentColors(document: AstroDocument): ColorInformation[]
|
|
16
|
-
getColorPresentations(document: AstroDocument, range: Range, color: Color): ColorPresentation[]
|
|
15
|
+
getDocumentColors(document: AstroDocument): Promise<ColorInformation[]>;
|
|
16
|
+
getColorPresentations(document: AstroDocument, range: Range, color: Color): Promise<ColorPresentation[]>;
|
|
17
17
|
getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
|
|
18
|
-
getDocumentSymbols(document: AstroDocument): SymbolInformation[]
|
|
18
|
+
getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
|
|
19
19
|
private inStyleAttributeWithoutInterpolation;
|
|
20
20
|
/**
|
|
21
21
|
* Get the associated CSS Document for a style tag
|
|
@@ -17,8 +17,8 @@ class CSSPlugin {
|
|
|
17
17
|
this.triggerCharacters = new Set(['.', ':', '-', '/']);
|
|
18
18
|
this.configManager = configManager;
|
|
19
19
|
}
|
|
20
|
-
doHover(document, position) {
|
|
21
|
-
if (!this.featureEnabled('hover')) {
|
|
20
|
+
async doHover(document, position) {
|
|
21
|
+
if (!(await this.featureEnabled(document, 'hover'))) {
|
|
22
22
|
return null;
|
|
23
23
|
}
|
|
24
24
|
if ((0, documents_1.isInsideFrontmatter)(document.getText(), document.offsetAt(position))) {
|
|
@@ -53,8 +53,8 @@ class CSSPlugin {
|
|
|
53
53
|
const hoverInfo = (0, language_service_1.getLanguageService)(extractLanguage(cssDocument)).doHover(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
|
|
54
54
|
return hoverInfo ? (0, documents_1.mapHoverToParent)(cssDocument, hoverInfo) : hoverInfo;
|
|
55
55
|
}
|
|
56
|
-
getCompletions(document, position, completionContext) {
|
|
57
|
-
if (!this.featureEnabled('completions')) {
|
|
56
|
+
async getCompletions(document, position, completionContext) {
|
|
57
|
+
if (!(await this.featureEnabled(document, 'completions'))) {
|
|
58
58
|
return null;
|
|
59
59
|
}
|
|
60
60
|
if ((0, documents_1.isInsideFrontmatter)(document.getText(), document.offsetAt(position))) {
|
|
@@ -77,7 +77,7 @@ class CSSPlugin {
|
|
|
77
77
|
}
|
|
78
78
|
if (this.inStyleAttributeWithoutInterpolation(attributeContext, document.getText())) {
|
|
79
79
|
const [start, end] = attributeContext.valueRange;
|
|
80
|
-
return this.getCompletionsInternal(document, position, new StyleAttributeDocument_1.StyleAttributeDocument(document, start, end));
|
|
80
|
+
return await this.getCompletionsInternal(document, position, new StyleAttributeDocument_1.StyleAttributeDocument(document, start, end));
|
|
81
81
|
}
|
|
82
82
|
// If we're not in a style attribute, instead give completions for ids and classes used in the current document
|
|
83
83
|
else if ((attributeContext.name == 'id' || attributeContext.name == 'class') && attributeContext.inValue) {
|
|
@@ -87,13 +87,14 @@ class CSSPlugin {
|
|
|
87
87
|
return null;
|
|
88
88
|
}
|
|
89
89
|
const cssDocument = this.getCSSDocumentForStyleTag(styleTag, document);
|
|
90
|
-
return this.getCompletionsInternal(document, position, cssDocument);
|
|
90
|
+
return await this.getCompletionsInternal(document, position, cssDocument);
|
|
91
91
|
}
|
|
92
|
-
getCompletionsInternal(document, position, cssDocument) {
|
|
92
|
+
async getCompletionsInternal(document, position, cssDocument) {
|
|
93
|
+
const emmetConfig = await this.configManager.getEmmetConfig(document);
|
|
93
94
|
if (isSASS(cssDocument)) {
|
|
94
95
|
// The CSS language service does not support SASS (not to be confused with SCSS)
|
|
95
96
|
// however we can at least still at least provide Emmet completions in SASS blocks
|
|
96
|
-
return (0, emmet_helper_1.doComplete)(document, position, 'sass',
|
|
97
|
+
return (0, emmet_helper_1.doComplete)(document, position, 'sass', emmetConfig) || null;
|
|
97
98
|
}
|
|
98
99
|
const cssLang = extractLanguage(cssDocument);
|
|
99
100
|
const langService = (0, language_service_1.getLanguageService)(cssLang);
|
|
@@ -101,29 +102,32 @@ class CSSPlugin {
|
|
|
101
102
|
isIncomplete: false,
|
|
102
103
|
items: [],
|
|
103
104
|
};
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
105
|
+
const extensionConfig = await this.configManager.getConfig('astro', document.uri);
|
|
106
|
+
if (extensionConfig.css.completions.emmet) {
|
|
107
|
+
langService.setCompletionParticipants([
|
|
108
|
+
{
|
|
109
|
+
onCssProperty: (context) => {
|
|
110
|
+
if (context?.propertyName) {
|
|
111
|
+
emmetResults =
|
|
112
|
+
(0, emmet_helper_1.doComplete)(cssDocument, cssDocument.getGeneratedPosition(position), (0, language_service_1.getLanguage)(cssLang), emmetConfig) || emmetResults;
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
onCssPropertyValue: (context) => {
|
|
116
|
+
if (context?.propertyValue) {
|
|
117
|
+
emmetResults =
|
|
118
|
+
(0, emmet_helper_1.doComplete)(cssDocument, cssDocument.getGeneratedPosition(position), (0, language_service_1.getLanguage)(cssLang), emmetConfig) || emmetResults;
|
|
119
|
+
}
|
|
120
|
+
},
|
|
111
121
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
emmetResults =
|
|
115
|
-
(0, emmet_helper_1.doComplete)(cssDocument, cssDocument.getGeneratedPosition(position), (0, language_service_1.getLanguage)(cssLang), this.configManager.getEmmetConfig()) || emmetResults;
|
|
116
|
-
}
|
|
117
|
-
},
|
|
118
|
-
},
|
|
119
|
-
]);
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
120
124
|
const results = langService.doComplete(cssDocument, cssDocument.getGeneratedPosition(position), cssDocument.stylesheet);
|
|
121
125
|
return vscode_languageserver_1.CompletionList.create([...(results ? results.items : []), ...emmetResults.items].map((completionItem) => (0, documents_1.mapCompletionItemToOriginal)(cssDocument, completionItem)),
|
|
122
126
|
// Emmet completions change on every keystroke, so they are never complete
|
|
123
127
|
emmetResults.items.length > 0);
|
|
124
128
|
}
|
|
125
|
-
getDocumentColors(document) {
|
|
126
|
-
if (!this.featureEnabled('documentColors')) {
|
|
129
|
+
async getDocumentColors(document) {
|
|
130
|
+
if (!(await this.featureEnabled(document, 'documentColors'))) {
|
|
127
131
|
return [];
|
|
128
132
|
}
|
|
129
133
|
const allColorInfo = this.getCSSDocumentsForDocument(document).map((cssDoc) => {
|
|
@@ -138,8 +142,8 @@ class CSSPlugin {
|
|
|
138
142
|
});
|
|
139
143
|
return (0, lodash_1.flatten)(allColorInfo);
|
|
140
144
|
}
|
|
141
|
-
getColorPresentations(document, range, color) {
|
|
142
|
-
if (!this.featureEnabled('
|
|
145
|
+
async getColorPresentations(document, range, color) {
|
|
146
|
+
if (!(await this.featureEnabled(document, 'documentColors'))) {
|
|
143
147
|
return [];
|
|
144
148
|
}
|
|
145
149
|
const allColorPres = this.getCSSDocumentsForDocument(document).map((cssDoc) => {
|
|
@@ -163,8 +167,8 @@ class CSSPlugin {
|
|
|
163
167
|
});
|
|
164
168
|
return (0, lodash_1.flatten)(allFoldingRanges);
|
|
165
169
|
}
|
|
166
|
-
getDocumentSymbols(document) {
|
|
167
|
-
if (!this.featureEnabled('documentSymbols')) {
|
|
170
|
+
async getDocumentSymbols(document) {
|
|
171
|
+
if (!(await this.featureEnabled(document, 'documentSymbols'))) {
|
|
168
172
|
return [];
|
|
169
173
|
}
|
|
170
174
|
const allDocumentSymbols = this.getCSSDocumentsForDocument(document).map((cssDoc) => {
|
|
@@ -210,8 +214,9 @@ class CSSPlugin {
|
|
|
210
214
|
return (0, documents_1.isInTag)(position, styleTag);
|
|
211
215
|
});
|
|
212
216
|
}
|
|
213
|
-
featureEnabled(feature) {
|
|
214
|
-
return this.configManager.
|
|
217
|
+
async featureEnabled(document, feature) {
|
|
218
|
+
return ((await this.configManager.isEnabled(document, 'css')) &&
|
|
219
|
+
(await this.configManager.isEnabled(document, 'css', feature)));
|
|
215
220
|
}
|
|
216
221
|
}
|
|
217
222
|
exports.CSSPlugin = CSSPlugin;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { CompletionList, Position, FoldingRange, Hover, SymbolInformation } from 'vscode-languageserver';
|
|
1
|
+
import { CompletionList, Position, TextEdit, FoldingRange, Hover, SymbolInformation, FormattingOptions } 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';
|
|
@@ -10,14 +10,15 @@ export declare class HTMLPlugin implements Plugin {
|
|
|
10
10
|
private styleScriptTemplate;
|
|
11
11
|
private configManager;
|
|
12
12
|
constructor(configManager: ConfigManager);
|
|
13
|
-
doHover(document: AstroDocument, position: Position): Hover | null
|
|
13
|
+
doHover(document: AstroDocument, position: Position): Promise<Hover | null>;
|
|
14
14
|
/**
|
|
15
15
|
* Get HTML completions
|
|
16
16
|
*/
|
|
17
|
-
getCompletions(document: AstroDocument, position: Position): CompletionList | null
|
|
17
|
+
getCompletions(document: AstroDocument, position: Position): Promise<CompletionList | null>;
|
|
18
|
+
formatDocument(document: AstroDocument, options: FormattingOptions): Promise<TextEdit[]>;
|
|
18
19
|
getFoldingRanges(document: AstroDocument): FoldingRange[] | null;
|
|
19
|
-
doTagComplete(document: AstroDocument, position: Position): string | null
|
|
20
|
-
getDocumentSymbols(document: AstroDocument): SymbolInformation[]
|
|
20
|
+
doTagComplete(document: AstroDocument, position: Position): Promise<string | null>;
|
|
21
|
+
getDocumentSymbols(document: AstroDocument): Promise<SymbolInformation[]>;
|
|
21
22
|
/**
|
|
22
23
|
* Get lang completions for style tags (ex: `<style lang="scss">`)
|
|
23
24
|
*/
|
|
@@ -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))
|
|
@@ -77,6 +80,24 @@ class HTMLPlugin {
|
|
|
77
80
|
// Emmet completions change on every keystroke, so they are never complete
|
|
78
81
|
emmetResults.items.length > 0);
|
|
79
82
|
}
|
|
83
|
+
async formatDocument(document, options) {
|
|
84
|
+
const start = document.positionAt(document.astroMeta.frontmatter.state === 'closed' ? document.astroMeta.frontmatter.endOffset + 3 : 0);
|
|
85
|
+
if (document.astroMeta.frontmatter.state === 'closed') {
|
|
86
|
+
start.line += 1;
|
|
87
|
+
start.character = 0;
|
|
88
|
+
}
|
|
89
|
+
const end = document.positionAt(document.getTextLength());
|
|
90
|
+
const htmlFormatConfig = (await this.configManager.getConfig('html.format', document.uri)) ?? {};
|
|
91
|
+
// The HTML plugin can't format script tags properly, we'll handle those inside the TypeScript plugin
|
|
92
|
+
if (htmlFormatConfig.contentUnformatted) {
|
|
93
|
+
htmlFormatConfig.contentUnformatted = htmlFormatConfig.contentUnformatted + ',script';
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
htmlFormatConfig.contentUnformatted = 'script';
|
|
97
|
+
}
|
|
98
|
+
const edits = this.lang.format(document, vscode_languageserver_1.Range.create(start, end), { ...htmlFormatConfig, ...options });
|
|
99
|
+
return edits;
|
|
100
|
+
}
|
|
80
101
|
getFoldingRanges(document) {
|
|
81
102
|
const html = document.html;
|
|
82
103
|
if (!html) {
|
|
@@ -84,8 +105,8 @@ class HTMLPlugin {
|
|
|
84
105
|
}
|
|
85
106
|
return this.lang.getFoldingRanges(document);
|
|
86
107
|
}
|
|
87
|
-
doTagComplete(document, position) {
|
|
88
|
-
if (!this.featureEnabled('tagComplete')) {
|
|
108
|
+
async doTagComplete(document, position) {
|
|
109
|
+
if (!(await this.featureEnabled(document, 'tagComplete'))) {
|
|
89
110
|
return null;
|
|
90
111
|
}
|
|
91
112
|
const html = document.html;
|
|
@@ -97,8 +118,8 @@ class HTMLPlugin {
|
|
|
97
118
|
}
|
|
98
119
|
return this.lang.doTagComplete(document, position, html);
|
|
99
120
|
}
|
|
100
|
-
getDocumentSymbols(document) {
|
|
101
|
-
if (!this.featureEnabled('documentSymbols')) {
|
|
121
|
+
async getDocumentSymbols(document) {
|
|
122
|
+
if (!(await this.featureEnabled(document, 'documentSymbols'))) {
|
|
102
123
|
return [];
|
|
103
124
|
}
|
|
104
125
|
const html = document.html;
|
|
@@ -134,8 +155,9 @@ class HTMLPlugin {
|
|
|
134
155
|
}));
|
|
135
156
|
}
|
|
136
157
|
}
|
|
137
|
-
featureEnabled(feature) {
|
|
138
|
-
return this.configManager.
|
|
158
|
+
async featureEnabled(document, feature) {
|
|
159
|
+
return ((await this.configManager.isEnabled(document, 'html')) &&
|
|
160
|
+
(await this.configManager.isEnabled(document, 'html', feature)));
|
|
139
161
|
}
|
|
140
162
|
}
|
|
141
163
|
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',
|