@astrojs/language-server 2.0.0-next.8 → 2.0.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/README.md +10 -0
- package/dist/core/astro2tsx.d.ts +1 -1
- package/dist/core/index.d.ts +1 -0
- package/dist/core/index.js +4 -2
- package/dist/core/parseAstro.d.ts +1 -2
- package/dist/core/parseCSS.d.ts +2 -1
- package/dist/core/parseCSS.js +27 -5
- package/dist/core/parseHTML.d.ts +4 -0
- package/dist/core/parseHTML.js +4 -3
- package/dist/core/parseJS.d.ts +1 -1
- package/dist/core/parseJS.js +3 -3
- package/dist/importPackage.d.ts +2 -2
- package/dist/importPackage.js +8 -2
- package/dist/languageServerPlugin.d.ts +1 -1
- package/dist/languageServerPlugin.js +46 -26
- package/dist/plugins/astro.js +5 -3
- package/dist/plugins/html.d.ts +1 -1
- package/dist/plugins/html.js +13 -2
- package/dist/plugins/typescript/codeActions.d.ts +1 -1
- package/dist/plugins/typescript/codeActions.js +6 -1
- package/dist/plugins/typescript/completions.js +8 -1
- package/dist/plugins/typescript/index.js +6 -2
- package/dist/utils.d.ts +12 -5
- package/dist/utils.js +30 -6
- package/package.json +14 -4
- package/dist/core/compilerUtils.d.ts +0 -27
- package/dist/core/compilerUtils.js +0 -52
package/README.md
CHANGED
|
@@ -13,3 +13,13 @@ The Astro language server, implement the [language server protocol](https://micr
|
|
|
13
13
|
├── test # Tests
|
|
14
14
|
└── types # Types injected into Astro files by the language server under certain conditions
|
|
15
15
|
```
|
|
16
|
+
|
|
17
|
+
## Troubleshooting
|
|
18
|
+
|
|
19
|
+
### Formatting does not work
|
|
20
|
+
|
|
21
|
+
> Using VS Code? This section does not apply to you, the VS Code extension includes both Prettier and the Astro plugin by default.
|
|
22
|
+
|
|
23
|
+
The Astro language server uses Prettier to format Astro files, but does not include `prettier` or `prettier-plugin-astro` by itself as dependencies in order to keep the dependency count low and allow users to better control the version of Prettier they want to use.
|
|
24
|
+
|
|
25
|
+
As such, if you want to use formatting, you'll need to install `prettier` and `prettier-plugin-astro` as dependencies in your project.
|
package/dist/core/astro2tsx.d.ts
CHANGED
|
@@ -2,5 +2,5 @@ import { VirtualFile } from '@volar/language-core';
|
|
|
2
2
|
import { HTMLDocument } from 'vscode-html-languageservice';
|
|
3
3
|
export declare function astro2tsx(input: string, fileName: string, ts: typeof import('typescript/lib/tsserverlibrary.js'), htmlDocument: HTMLDocument): {
|
|
4
4
|
virtualFile: VirtualFile;
|
|
5
|
-
diagnostics: import("@astrojs/compiler
|
|
5
|
+
diagnostics: import("@astrojs/compiler").DiagnosticMessage[];
|
|
6
6
|
};
|
package/dist/core/index.d.ts
CHANGED
|
@@ -19,6 +19,7 @@ export declare class AstroFile implements VirtualFile {
|
|
|
19
19
|
};
|
|
20
20
|
compilerDiagnostics: DiagnosticMessage[];
|
|
21
21
|
htmlDocument: HTMLDocument;
|
|
22
|
+
scriptFiles: string[];
|
|
22
23
|
codegenStacks: never[];
|
|
23
24
|
constructor(sourceFileName: string, snapshot: ts.IScriptSnapshot, ts: typeof import('typescript/lib/tsserverlibrary.js'));
|
|
24
25
|
get hasCompilationErrors(): boolean;
|
package/dist/core/index.js
CHANGED
|
@@ -47,10 +47,10 @@ function getLanguageModule(astroInstall, ts) {
|
|
|
47
47
|
getScriptFileNames() {
|
|
48
48
|
const fileNames = host.getScriptFileNames();
|
|
49
49
|
return [
|
|
50
|
+
...fileNames,
|
|
50
51
|
...(astroInstall
|
|
51
52
|
? ['./env.d.ts', './astro-jsx.d.ts'].map((filePath) => ts.sys.resolvePath(path.resolve(astroInstall.path, filePath)))
|
|
52
53
|
: []),
|
|
53
|
-
...fileNames,
|
|
54
54
|
];
|
|
55
55
|
},
|
|
56
56
|
getCompilationSettings() {
|
|
@@ -107,7 +107,9 @@ class AstroFile {
|
|
|
107
107
|
? this.astroMeta.frontmatter.position.end.offset
|
|
108
108
|
: 0);
|
|
109
109
|
this.htmlDocument = htmlDocument;
|
|
110
|
-
|
|
110
|
+
const scriptTags = (0, parseJS_js_1.extractScriptTags)(this.fileName, this.snapshot, htmlDocument, this.astroMeta.ast);
|
|
111
|
+
this.scriptFiles = scriptTags.map((scriptTag) => scriptTag.fileName);
|
|
112
|
+
htmlVirtualFile.embeddedFiles.push(...(0, parseCSS_1.extractStylesheets)(this.fileName, this.snapshot, htmlDocument, this.astroMeta.ast), ...scriptTags);
|
|
111
113
|
this.embeddedFiles = [];
|
|
112
114
|
this.embeddedFiles.push(htmlVirtualFile);
|
|
113
115
|
const tsx = (0, astro2tsx_1.astro2tsx)(this.snapshot.getText(0, this.snapshot.getLength()), this.fileName, this.ts, htmlDocument);
|
package/dist/core/parseCSS.d.ts
CHANGED
|
@@ -2,6 +2,7 @@ import type { ParseResult } from '@astrojs/compiler/types';
|
|
|
2
2
|
import { VirtualFile } from '@volar/language-core';
|
|
3
3
|
import type ts from 'typescript/lib/tsserverlibrary';
|
|
4
4
|
import type { HTMLDocument } from 'vscode-html-languageservice';
|
|
5
|
-
import { AttributeNodeWithPosition } from '
|
|
5
|
+
import type { AttributeNodeWithPosition } from '../utils.js';
|
|
6
6
|
export declare function extractStylesheets(fileName: string, snapshot: ts.IScriptSnapshot, htmlDocument: HTMLDocument, ast: ParseResult['ast']): VirtualFile[];
|
|
7
|
+
export declare function collectClassesAndIdsFromDocument(ast: ParseResult['ast']): string[];
|
|
7
8
|
export declare function findInlineStyles(ast: ParseResult['ast']): AttributeNodeWithPosition[];
|
package/dist/core/parseCSS.js
CHANGED
|
@@ -23,11 +23,11 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.findInlineStyles = exports.extractStylesheets = void 0;
|
|
26
|
+
exports.findInlineStyles = exports.collectClassesAndIdsFromDocument = exports.extractStylesheets = void 0;
|
|
27
|
+
const utils_1 = require("@astrojs/compiler/utils");
|
|
27
28
|
const language_core_1 = require("@volar/language-core");
|
|
28
29
|
const SourceMap = __importStar(require("@volar/source-map"));
|
|
29
30
|
const muggle = __importStar(require("muggle-string"));
|
|
30
|
-
const compilerUtils_js_1 = require("./compilerUtils.js");
|
|
31
31
|
function extractStylesheets(fileName, snapshot, htmlDocument, ast) {
|
|
32
32
|
const embeddedCSSFiles = [];
|
|
33
33
|
for (const [index, root] of htmlDocument.roots.entries()) {
|
|
@@ -82,7 +82,7 @@ function extractStylesheets(fileName, snapshot, htmlDocument, ast) {
|
|
|
82
82
|
getLength: () => text.length,
|
|
83
83
|
getChangeRange: () => undefined,
|
|
84
84
|
},
|
|
85
|
-
capabilities: {},
|
|
85
|
+
capabilities: { documentSymbol: true },
|
|
86
86
|
embeddedFiles: [],
|
|
87
87
|
kind: language_core_1.FileKind.TextFile,
|
|
88
88
|
mappings,
|
|
@@ -91,6 +91,28 @@ function extractStylesheets(fileName, snapshot, htmlDocument, ast) {
|
|
|
91
91
|
return embeddedCSSFiles;
|
|
92
92
|
}
|
|
93
93
|
exports.extractStylesheets = extractStylesheets;
|
|
94
|
+
// TODO: Provide completion for classes and IDs
|
|
95
|
+
function collectClassesAndIdsFromDocument(ast) {
|
|
96
|
+
const classesAndIds = [];
|
|
97
|
+
function walkDown(parent) {
|
|
98
|
+
if (!parent.children)
|
|
99
|
+
return;
|
|
100
|
+
parent.children.forEach((child) => {
|
|
101
|
+
if (utils_1.is.element(child)) {
|
|
102
|
+
const classOrIDAttributes = child.attributes
|
|
103
|
+
.filter((attr) => attr.kind === 'quoted' && (attr.name === 'class' || attr.name === 'id'))
|
|
104
|
+
.flatMap((attr) => attr.value.split(' '));
|
|
105
|
+
classesAndIds.push(...classOrIDAttributes);
|
|
106
|
+
}
|
|
107
|
+
if (utils_1.is.parent(child)) {
|
|
108
|
+
walkDown(child);
|
|
109
|
+
}
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
walkDown(ast);
|
|
113
|
+
return classesAndIds;
|
|
114
|
+
}
|
|
115
|
+
exports.collectClassesAndIdsFromDocument = collectClassesAndIdsFromDocument;
|
|
94
116
|
function findInlineStyles(ast) {
|
|
95
117
|
const styleAttrs = [];
|
|
96
118
|
// `@astrojs/compiler`'s `walk` method is async, so we can't use it here. Arf
|
|
@@ -98,13 +120,13 @@ function findInlineStyles(ast) {
|
|
|
98
120
|
if (!parent.children)
|
|
99
121
|
return;
|
|
100
122
|
parent.children.forEach((child) => {
|
|
101
|
-
if (
|
|
123
|
+
if (utils_1.is.element(child)) {
|
|
102
124
|
const styleAttribute = child.attributes.find((attr) => attr.name === 'style' && attr.kind === 'quoted');
|
|
103
125
|
if (styleAttribute && styleAttribute.position) {
|
|
104
126
|
styleAttrs.push(styleAttribute);
|
|
105
127
|
}
|
|
106
128
|
}
|
|
107
|
-
if (
|
|
129
|
+
if (utils_1.is.parent(child)) {
|
|
108
130
|
walkDown(child);
|
|
109
131
|
}
|
|
110
132
|
});
|
package/dist/core/parseHTML.d.ts
CHANGED
|
@@ -5,3 +5,7 @@ export declare function parseHTML(fileName: string, snapshot: ts.IScriptSnapshot
|
|
|
5
5
|
virtualFile: VirtualFile;
|
|
6
6
|
htmlDocument: html.HTMLDocument;
|
|
7
7
|
};
|
|
8
|
+
/**
|
|
9
|
+
* scan the text and remove any `>` or `<` that cause the tag to end short
|
|
10
|
+
*/
|
|
11
|
+
export declare function preprocessHTML(text: string, frontmatterEnd?: number): string;
|
package/dist/core/parseHTML.js
CHANGED
|
@@ -23,13 +23,13 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
23
23
|
return result;
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
|
-
exports.parseHTML = void 0;
|
|
26
|
+
exports.preprocessHTML = exports.parseHTML = void 0;
|
|
27
27
|
const language_core_1 = require("@volar/language-core");
|
|
28
28
|
const html = __importStar(require("vscode-html-languageservice"));
|
|
29
29
|
const utils_1 = require("../utils");
|
|
30
30
|
const htmlLs = html.getLanguageService();
|
|
31
31
|
function parseHTML(fileName, snapshot, frontmatterEnd) {
|
|
32
|
-
const htmlContent =
|
|
32
|
+
const htmlContent = preprocessHTML(snapshot.getText(0, snapshot.getLength()), frontmatterEnd);
|
|
33
33
|
return {
|
|
34
34
|
virtualFile: getHTMLVirtualFile(fileName, htmlContent),
|
|
35
35
|
htmlDocument: getHTMLDocument(htmlContent),
|
|
@@ -40,7 +40,7 @@ const createScanner = htmlLs.createScanner;
|
|
|
40
40
|
/**
|
|
41
41
|
* scan the text and remove any `>` or `<` that cause the tag to end short
|
|
42
42
|
*/
|
|
43
|
-
function
|
|
43
|
+
function preprocessHTML(text, frontmatterEnd) {
|
|
44
44
|
let content = text.split('').fill(' ', 0, frontmatterEnd).join('');
|
|
45
45
|
let scanner = createScanner(content);
|
|
46
46
|
let token = scanner.scan();
|
|
@@ -82,6 +82,7 @@ function preprocess(text, frontmatterEnd) {
|
|
|
82
82
|
scanner = createScanner(content, offset, state ?? html.ScannerState.WithinTag);
|
|
83
83
|
}
|
|
84
84
|
}
|
|
85
|
+
exports.preprocessHTML = preprocessHTML;
|
|
85
86
|
function getHTMLVirtualFile(fileName, preprocessedHTML) {
|
|
86
87
|
return {
|
|
87
88
|
fileName: fileName + `.html`,
|
package/dist/core/parseJS.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ParseResult } from '@astrojs/compiler/types
|
|
1
|
+
import type { ParseResult } from '@astrojs/compiler/types';
|
|
2
2
|
import { VirtualFile } from '@volar/language-core';
|
|
3
3
|
import type ts from 'typescript/lib/tsserverlibrary';
|
|
4
4
|
import type { HTMLDocument, Node } from 'vscode-html-languageservice';
|
package/dist/core/parseJS.js
CHANGED
|
@@ -24,10 +24,10 @@ var __importStar = (this && this.__importStar) || function (mod) {
|
|
|
24
24
|
};
|
|
25
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
26
26
|
exports.htmlEventAttributes = exports.getScriptTagLanguage = exports.extractScriptTags = void 0;
|
|
27
|
+
const utils_1 = require("@astrojs/compiler/utils");
|
|
27
28
|
const language_core_1 = require("@volar/language-core");
|
|
28
29
|
const SourceMap = __importStar(require("@volar/source-map"));
|
|
29
30
|
const muggle = __importStar(require("muggle-string"));
|
|
30
|
-
const compilerUtils_js_1 = require("./compilerUtils.js");
|
|
31
31
|
function extractScriptTags(fileName, snapshot, htmlDocument, ast) {
|
|
32
32
|
const embeddedJSFiles = [];
|
|
33
33
|
for (const [index, root] of htmlDocument.roots.entries()) {
|
|
@@ -120,7 +120,7 @@ function findEventAttributes(ast) {
|
|
|
120
120
|
if (!parent.children)
|
|
121
121
|
return;
|
|
122
122
|
parent.children.forEach((child) => {
|
|
123
|
-
if (
|
|
123
|
+
if (utils_1.is.element(child)) {
|
|
124
124
|
const eventAttribute = child.attributes.find((attr) => exports.htmlEventAttributes.includes(attr.name) && attr.kind === 'quoted');
|
|
125
125
|
if (eventAttribute && eventAttribute.position) {
|
|
126
126
|
eventAttrs.push({
|
|
@@ -129,7 +129,7 @@ function findEventAttributes(ast) {
|
|
|
129
129
|
});
|
|
130
130
|
}
|
|
131
131
|
}
|
|
132
|
-
if (
|
|
132
|
+
if (utils_1.is.parent(child)) {
|
|
133
133
|
walkDown(child);
|
|
134
134
|
}
|
|
135
135
|
});
|
package/dist/importPackage.d.ts
CHANGED
|
@@ -5,5 +5,5 @@ export declare function setIsTrusted(_isTrusted: boolean): void;
|
|
|
5
5
|
export declare function getPackagePath(packageName: string, fromPath: string[]): string | undefined;
|
|
6
6
|
export declare function importSvelteIntegration(fromPath: string): typeof svelte | undefined;
|
|
7
7
|
export declare function importVueIntegration(fromPath: string): typeof vue | undefined;
|
|
8
|
-
export declare function importPrettier(fromPath: string): typeof prettier;
|
|
9
|
-
export declare function getPrettierPluginPath(fromPath: string): string;
|
|
8
|
+
export declare function importPrettier(fromPath: string): typeof prettier | undefined;
|
|
9
|
+
export declare function getPrettierPluginPath(fromPath: string): string | undefined;
|
package/dist/importPackage.js
CHANGED
|
@@ -43,13 +43,19 @@ function importVueIntegration(fromPath) {
|
|
|
43
43
|
}
|
|
44
44
|
exports.importVueIntegration = importVueIntegration;
|
|
45
45
|
function importPrettier(fromPath) {
|
|
46
|
-
// This shouldn't ever fail, because we bundle Prettier in the extension itself
|
|
47
46
|
const prettierPkg = getPackagePath('prettier', [fromPath, __dirname]);
|
|
47
|
+
if (!prettierPkg) {
|
|
48
|
+
return undefined;
|
|
49
|
+
}
|
|
48
50
|
return require(prettierPkg);
|
|
49
51
|
}
|
|
50
52
|
exports.importPrettier = importPrettier;
|
|
51
53
|
function getPrettierPluginPath(fromPath) {
|
|
52
|
-
|
|
54
|
+
const prettierPluginPath = getPackagePath('prettier-plugin-astro', [fromPath, __dirname]);
|
|
55
|
+
if (!prettierPluginPath) {
|
|
56
|
+
return undefined;
|
|
57
|
+
}
|
|
58
|
+
return prettierPluginPath;
|
|
53
59
|
}
|
|
54
60
|
exports.getPrettierPluginPath = getPrettierPluginPath;
|
|
55
61
|
//# sourceMappingURL=importPackage.js.map
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import
|
|
1
|
+
import { LanguageServerPlugin } from '@volar/language-server/node';
|
|
2
2
|
export declare const plugin: LanguageServerPlugin;
|
|
@@ -4,6 +4,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
6
|
exports.plugin = void 0;
|
|
7
|
+
const node_1 = require("@volar/language-server/node");
|
|
7
8
|
const volar_service_css_1 = __importDefault(require("volar-service-css"));
|
|
8
9
|
const volar_service_emmet_1 = __importDefault(require("volar-service-emmet"));
|
|
9
10
|
const volar_service_prettier_1 = __importDefault(require("volar-service-prettier"));
|
|
@@ -39,7 +40,14 @@ const plugin = (initOptions, modules) => ({
|
|
|
39
40
|
resolveConfig(config, ctx) {
|
|
40
41
|
config.languages ??= {};
|
|
41
42
|
if (ctx) {
|
|
42
|
-
|
|
43
|
+
const astroInstall = (0, utils_1.getAstroInstall)([ctx.project.rootUri.fsPath]);
|
|
44
|
+
if (!astroInstall) {
|
|
45
|
+
ctx.server.connection.sendNotification(node_1.ShowMessageNotification.type, {
|
|
46
|
+
message: `Couldn't find Astro in workspace "${ctx.project.rootUri.fsPath}". Experience might be degraded. For the best experience, please make sure Astro is installed into your project and restart the language server.`,
|
|
47
|
+
type: node_1.MessageType.Warning,
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
config.languages.astro = (0, core_1.getLanguageModule)(astroInstall, modules.typescript);
|
|
43
51
|
config.languages.vue = (0, vue_js_1.getVueLanguageModule)();
|
|
44
52
|
config.languages.svelte = (0, svelte_js_1.getSvelteLanguageModule)();
|
|
45
53
|
}
|
|
@@ -50,31 +58,43 @@ const plugin = (initOptions, modules) => ({
|
|
|
50
58
|
config.services.typescript ??= (0, index_js_1.default)();
|
|
51
59
|
config.services.typescripttwoslash ??= (0, volar_service_typescript_twoslash_queries_1.default)();
|
|
52
60
|
config.services.astro ??= (0, astro_js_1.default)();
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
61
|
+
if (ctx) {
|
|
62
|
+
const rootDir = ctx.env.uriToFileName(ctx.project.rootUri.toString());
|
|
63
|
+
const prettier = (0, importPackage_js_1.importPrettier)(rootDir);
|
|
64
|
+
const prettierPluginPath = (0, importPackage_js_1.getPrettierPluginPath)(rootDir);
|
|
65
|
+
if (prettier && prettierPluginPath) {
|
|
66
|
+
config.services.prettier ??= (0, volar_service_prettier_1.default)({
|
|
67
|
+
languages: ['astro'],
|
|
68
|
+
resolveConfigOptions: {
|
|
69
|
+
// Prettier's cache is a bit cumbersome, because you need to reload the config yourself on change
|
|
70
|
+
// TODO: Upstream a fix for this
|
|
71
|
+
useCache: false,
|
|
72
|
+
},
|
|
73
|
+
additionalOptions: (resolvedConfig) => {
|
|
74
|
+
function getAstroPrettierPlugin() {
|
|
75
|
+
if (!prettier || !prettierPluginPath) {
|
|
76
|
+
return [];
|
|
77
|
+
}
|
|
78
|
+
const hasPluginLoadedAlready = prettier
|
|
79
|
+
.getSupportInfo()
|
|
80
|
+
.languages.some((l) => l.name === 'astro');
|
|
81
|
+
return hasPluginLoadedAlready ? [] : [prettierPluginPath];
|
|
82
|
+
}
|
|
83
|
+
return {
|
|
84
|
+
plugins: [...getAstroPrettierPlugin(), ...(resolvedConfig.plugins ?? [])],
|
|
85
|
+
parser: 'astro',
|
|
86
|
+
...resolvedConfig,
|
|
87
|
+
};
|
|
88
|
+
},
|
|
89
|
+
});
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
ctx.server.connection.sendNotification(node_1.ShowMessageNotification.type, {
|
|
93
|
+
message: "Couldn't load `prettier` or `prettier-plugin-astro`. Formatting will not work. Please make sure those two packages are installed into your project.",
|
|
94
|
+
type: node_1.MessageType.Warning,
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
78
98
|
return config;
|
|
79
99
|
},
|
|
80
100
|
});
|
package/dist/plugins/astro.js
CHANGED
|
@@ -48,7 +48,7 @@ exports.default = () => (context, modules) => {
|
|
|
48
48
|
provideCodeLenses(document, token) {
|
|
49
49
|
if (token.isCancellationRequested)
|
|
50
50
|
return;
|
|
51
|
-
if (!modules?.typescript || !context?.typescript || !(0, utils_js_1.
|
|
51
|
+
if (!modules?.typescript || !context?.typescript || !(0, utils_js_1.isJSDocument)(document.languageId))
|
|
52
52
|
return;
|
|
53
53
|
const ts = modules?.typescript;
|
|
54
54
|
const tsProgram = context.typescript.languageService.getProgram();
|
|
@@ -59,8 +59,10 @@ exports.default = () => (context, modules) => {
|
|
|
59
59
|
function walk() {
|
|
60
60
|
return ts.forEachChild(sourceFile, function cb(node) {
|
|
61
61
|
if (ts.isCallExpression(node) && node.expression.getText() === 'Astro.glob') {
|
|
62
|
-
const
|
|
63
|
-
|
|
62
|
+
const globArgument = node.arguments.at(0);
|
|
63
|
+
if (globArgument) {
|
|
64
|
+
globcodeLens.push(getGlobResultAsCodeLens(globArgument.getText().slice(1, -1), (0, node_path_1.dirname)(context.env.uriToFileName(document.uri)), document.positionAt(node.arguments.pos)));
|
|
65
|
+
}
|
|
64
66
|
}
|
|
65
67
|
return ts.forEachChild(node, cb);
|
|
66
68
|
});
|
package/dist/plugins/html.d.ts
CHANGED
package/dist/plugins/html.js
CHANGED
|
@@ -3,6 +3,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
const language_server_1 = require("@volar/language-server");
|
|
6
7
|
const volar_service_html_1 = __importDefault(require("volar-service-html"));
|
|
7
8
|
const index_js_1 = require("../core/index.js");
|
|
8
9
|
const utils_js_1 = require("../utils.js");
|
|
@@ -19,7 +20,7 @@ exports.default = () => (context, modules) => {
|
|
|
19
20
|
]);
|
|
20
21
|
return {
|
|
21
22
|
...htmlPlugin,
|
|
22
|
-
provideCompletionItems(document, position, completionContext, token) {
|
|
23
|
+
async provideCompletionItems(document, position, completionContext, token) {
|
|
23
24
|
if (document.languageId !== 'html')
|
|
24
25
|
return;
|
|
25
26
|
const [_, source] = context.documents.getVirtualFileByUri(document.uri);
|
|
@@ -30,7 +31,17 @@ exports.default = () => (context, modules) => {
|
|
|
30
31
|
if ((0, utils_js_1.isInComponentStartTag)(rootVirtualFile.htmlDocument, document.offsetAt(position))) {
|
|
31
32
|
return null;
|
|
32
33
|
}
|
|
33
|
-
|
|
34
|
+
const completions = await htmlPlugin.provideCompletionItems(document, position, completionContext, token);
|
|
35
|
+
if (!completions) {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
// We don't want completions for file references, as they're mostly invalid for Astro
|
|
39
|
+
completions.items = completions.items.filter((completion) => completion.kind !== language_server_1.CompletionItemKind.File);
|
|
40
|
+
return completions;
|
|
41
|
+
},
|
|
42
|
+
// Document links provided by `vscode-html-languageservice` are invalid for Astro
|
|
43
|
+
provideDocumentLinks() {
|
|
44
|
+
return [];
|
|
34
45
|
},
|
|
35
46
|
};
|
|
36
47
|
};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { CodeAction } from '@volar/language-server';
|
|
2
2
|
import type { TextDocument } from 'vscode-html-languageservice';
|
|
3
3
|
import type { AstroFile } from '../../core/index.js';
|
|
4
|
-
export declare function enhancedProvideCodeActions(codeActions: CodeAction[], file: AstroFile, document: TextDocument, newLine: string): CodeAction[];
|
|
4
|
+
export declare function enhancedProvideCodeActions(codeActions: CodeAction[], file: AstroFile, document: TextDocument, originalDocument: TextDocument, newLine: string): CodeAction[];
|
|
@@ -2,11 +2,16 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enhancedProvideCodeActions = void 0;
|
|
4
4
|
const language_server_1 = require("@volar/language-server");
|
|
5
|
+
const vscode_uri_1 = require("vscode-uri");
|
|
5
6
|
const utils_js_1 = require("../../utils.js");
|
|
6
|
-
|
|
7
|
+
// Q: Why provideCodeActions instead of resolveCodeAction?
|
|
8
|
+
// A: TypeScript actions are already fully resolved in provideCodeActions, so editors won't call resolveCodeAction at all.
|
|
9
|
+
function enhancedProvideCodeActions(codeActions, file, document, originalDocument, newLine) {
|
|
7
10
|
codeActions = codeActions.map((codeAction) => {
|
|
8
11
|
if (!codeAction.edit)
|
|
9
12
|
return codeAction;
|
|
13
|
+
if (file.scriptFiles.includes(vscode_uri_1.URI.parse(originalDocument.uri).path))
|
|
14
|
+
return codeAction;
|
|
10
15
|
codeAction.edit.documentChanges = codeAction.edit.documentChanges?.map((change) => {
|
|
11
16
|
if (language_server_1.TextDocumentEdit.is(change)) {
|
|
12
17
|
change.edits = change.edits.map((edit) => {
|
|
@@ -31,6 +31,8 @@ function enhancedResolveCompletionItem(resolvedCompletion, originalItem, context
|
|
|
31
31
|
const file = source?.root;
|
|
32
32
|
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
33
33
|
return resolvedCompletion;
|
|
34
|
+
if (file.scriptFiles.includes(originalItem.data.fileName))
|
|
35
|
+
return resolvedCompletion;
|
|
34
36
|
const newLine = context.host.getNewLine ? context.host.getNewLine() : '\n';
|
|
35
37
|
resolvedCompletion.additionalTextEdits = resolvedCompletion.additionalTextEdits?.map((edit) => {
|
|
36
38
|
// HACK: There's a weird situation sometimes where some components (especially Svelte) will get imported as type imports
|
|
@@ -38,6 +40,7 @@ function enhancedResolveCompletionItem(resolvedCompletion, originalItem, context
|
|
|
38
40
|
if (resolvedCompletion.data.isComponent && edit.newText.includes('import type')) {
|
|
39
41
|
edit.newText.replace('import type', 'import');
|
|
40
42
|
}
|
|
43
|
+
// Return a different edit depending on the state of the formatter
|
|
41
44
|
if (file.astroMeta.frontmatter.status === 'doesnt-exist') {
|
|
42
45
|
return (0, utils_js_1.getNewFrontmatterEdit)(edit, newLine);
|
|
43
46
|
}
|
|
@@ -73,7 +76,11 @@ const svelte2tsxTypes = new Set([
|
|
|
73
76
|
]);
|
|
74
77
|
function isValidCompletion(completion) {
|
|
75
78
|
const isSvelte2tsxCompletion = completion.label.startsWith('__sveltets_') || svelte2tsxTypes.has(completion.label);
|
|
76
|
-
|
|
79
|
+
// Filter out completions for the children prop, as it doesn't work in Astro
|
|
80
|
+
const isChildrenCompletion = completion.label === 'children?' &&
|
|
81
|
+
completion.kind === language_server_1.CompletionItemKind.Field &&
|
|
82
|
+
completion.filterText === 'children={$1}';
|
|
83
|
+
if (isSvelte2tsxCompletion || isChildrenCompletion)
|
|
77
84
|
return false;
|
|
78
85
|
return true;
|
|
79
86
|
}
|
|
@@ -11,7 +11,11 @@ const diagnostics_js_1 = require("./diagnostics.js");
|
|
|
11
11
|
exports.default = () => (context, modules) => {
|
|
12
12
|
const typeScriptPlugin = (0, volar_service_typescript_1.default)()(context, modules);
|
|
13
13
|
if (!context) {
|
|
14
|
-
return {
|
|
14
|
+
return {
|
|
15
|
+
triggerCharacters: typeScriptPlugin.triggerCharacters,
|
|
16
|
+
signatureHelpTriggerCharacters: typeScriptPlugin.signatureHelpTriggerCharacters,
|
|
17
|
+
signatureHelpRetriggerCharacters: typeScriptPlugin.signatureHelpRetriggerCharacters,
|
|
18
|
+
};
|
|
15
19
|
}
|
|
16
20
|
return {
|
|
17
21
|
...typeScriptPlugin,
|
|
@@ -36,7 +40,7 @@ exports.default = () => (context, modules) => {
|
|
|
36
40
|
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
37
41
|
return codeActions;
|
|
38
42
|
const newLine = context.host.getNewLine ? context.host.getNewLine() : '\n';
|
|
39
|
-
return (0, codeActions_js_1.enhancedProvideCodeActions)(codeActions, file, context.documents.getDocumentByFileName(file.snapshot, file.sourceFileName), newLine);
|
|
43
|
+
return (0, codeActions_js_1.enhancedProvideCodeActions)(codeActions, file, context.documents.getDocumentByFileName(file.snapshot, file.sourceFileName), document, newLine);
|
|
40
44
|
},
|
|
41
45
|
async provideSemanticDiagnostics(document, token) {
|
|
42
46
|
const [_, source] = context.documents.getVirtualFileByUri(document.uri);
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type { Point } from '@astrojs/compiler/types';
|
|
2
|
-
import { HTMLDocument,
|
|
1
|
+
import type { AttributeNode, Position as CompilerPosition, Point } from '@astrojs/compiler/types';
|
|
2
|
+
import { HTMLDocument, Position as LSPPosition, Node, Range, TextEdit } from 'vscode-html-languageservice';
|
|
3
3
|
import type { FrontmatterStatus } from './core/parseAstro.js';
|
|
4
|
-
export declare function
|
|
4
|
+
export declare function isJSDocument(languageId: string): boolean;
|
|
5
5
|
/**
|
|
6
6
|
* Return true if a specific node could be a component.
|
|
7
7
|
* This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
|
|
@@ -22,11 +22,18 @@ export declare function isInsideFrontmatter(offset: number, frontmatter: Frontma
|
|
|
22
22
|
/**
|
|
23
23
|
* Transform a Point from the Astro compiler to an LSP Position
|
|
24
24
|
*/
|
|
25
|
-
export declare function PointToPosition(point: Point):
|
|
25
|
+
export declare function PointToPosition(point: Point): LSPPosition;
|
|
26
|
+
export declare function createCompilerPosition(start: Point, end: Point): CompilerPosition;
|
|
27
|
+
export declare function createCompilerPoint(line: number, column: number, offset: number): Point;
|
|
28
|
+
type WithRequired<T, K extends keyof T> = T & {
|
|
29
|
+
[P in K]-?: T[P];
|
|
30
|
+
};
|
|
31
|
+
export type AttributeNodeWithPosition = WithRequired<AttributeNode, 'position'>;
|
|
26
32
|
/**
|
|
27
|
-
* Force a range to be at the start of the frontmatter
|
|
33
|
+
* Force a range to be at the start of the frontmatter if it is outside
|
|
28
34
|
*/
|
|
29
35
|
export declare function ensureRangeIsInFrontmatter(range: Range, frontmatter: FrontmatterStatus): Range;
|
|
30
36
|
export declare function getNewFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
31
37
|
export declare function getOpenFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
32
38
|
export declare function getWorkspacePnpPath(workspacePath: string): string | null;
|
|
39
|
+
export {};
|
package/dist/utils.js
CHANGED
|
@@ -3,16 +3,16 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
3
3
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
4
|
};
|
|
5
5
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.getWorkspacePnpPath = exports.getOpenFrontmatterEdit = exports.getNewFrontmatterEdit = exports.ensureRangeIsInFrontmatter = exports.PointToPosition = exports.isInsideFrontmatter = exports.isInsideExpression = exports.isInComponentStartTag = exports.isPossibleComponent = exports.
|
|
6
|
+
exports.getWorkspacePnpPath = exports.getOpenFrontmatterEdit = exports.getNewFrontmatterEdit = exports.ensureRangeIsInFrontmatter = exports.createCompilerPoint = exports.createCompilerPosition = exports.PointToPosition = exports.isInsideFrontmatter = exports.isInsideExpression = exports.isInComponentStartTag = exports.isPossibleComponent = exports.isJSDocument = void 0;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
8
|
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
|
|
9
|
-
function
|
|
9
|
+
function isJSDocument(languageId) {
|
|
10
10
|
return (languageId === 'javascript' ||
|
|
11
11
|
languageId === 'typescript' ||
|
|
12
12
|
languageId === 'javascriptreact' ||
|
|
13
13
|
languageId === 'typescriptreact');
|
|
14
14
|
}
|
|
15
|
-
exports.
|
|
15
|
+
exports.isJSDocument = isJSDocument;
|
|
16
16
|
/**
|
|
17
17
|
* Return true if a specific node could be a component.
|
|
18
18
|
* This is not a 100% sure test as it'll return false for any component that does not match the standard format for a component
|
|
@@ -55,16 +55,40 @@ exports.isInsideFrontmatter = isInsideFrontmatter;
|
|
|
55
55
|
* Transform a Point from the Astro compiler to an LSP Position
|
|
56
56
|
*/
|
|
57
57
|
function PointToPosition(point) {
|
|
58
|
+
// Columns are 0-based in LSP, but the compiler's Point are 1 based.
|
|
58
59
|
return vscode_html_languageservice_1.Position.create(point.line, point.column - 1);
|
|
59
60
|
}
|
|
60
61
|
exports.PointToPosition = PointToPosition;
|
|
62
|
+
function createCompilerPosition(start, end) {
|
|
63
|
+
return {
|
|
64
|
+
start,
|
|
65
|
+
end,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
exports.createCompilerPosition = createCompilerPosition;
|
|
69
|
+
function createCompilerPoint(line, column, offset) {
|
|
70
|
+
return {
|
|
71
|
+
line,
|
|
72
|
+
column,
|
|
73
|
+
offset,
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
exports.createCompilerPoint = createCompilerPoint;
|
|
61
77
|
/**
|
|
62
|
-
* Force a range to be at the start of the frontmatter
|
|
78
|
+
* Force a range to be at the start of the frontmatter if it is outside
|
|
63
79
|
*/
|
|
64
80
|
function ensureRangeIsInFrontmatter(range, frontmatter) {
|
|
65
81
|
if (frontmatter.status === 'open' || frontmatter.status === 'closed') {
|
|
66
|
-
const
|
|
67
|
-
|
|
82
|
+
const frontmatterStartPosition = PointToPosition(frontmatter.position.start);
|
|
83
|
+
const frontmatterEndPosition = frontmatter.position.end
|
|
84
|
+
? PointToPosition(frontmatter.position.end)
|
|
85
|
+
: undefined;
|
|
86
|
+
// If the range start is outside the frontmatter, return a range at the start of the frontmatter
|
|
87
|
+
if (range.start.line < frontmatterStartPosition.line ||
|
|
88
|
+
(frontmatterEndPosition && range.start.line > frontmatterEndPosition.line)) {
|
|
89
|
+
return vscode_html_languageservice_1.Range.create(frontmatterStartPosition, frontmatterStartPosition);
|
|
90
|
+
}
|
|
91
|
+
return range;
|
|
68
92
|
}
|
|
69
93
|
return range;
|
|
70
94
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/language-server",
|
|
3
|
-
"version": "2.0.0
|
|
3
|
+
"version": "2.0.0",
|
|
4
4
|
"author": "withastro",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"astro-ls": "./bin/nodeServer.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@astrojs/compiler": "^1.
|
|
23
|
+
"@astrojs/compiler": "^1.5.0",
|
|
24
24
|
"@jridgewell/sourcemap-codec": "^1.4.15",
|
|
25
25
|
"@volar/kit": "^1.6.9",
|
|
26
26
|
"@volar/language-core": "^1.6.9",
|
|
@@ -29,8 +29,6 @@
|
|
|
29
29
|
"@volar/source-map": "^1.6.9",
|
|
30
30
|
"fast-glob": "^3.2.12",
|
|
31
31
|
"muggle-string": "^0.3.1",
|
|
32
|
-
"prettier": "^2.8.8",
|
|
33
|
-
"prettier-plugin-astro": "^0.9.0",
|
|
34
32
|
"volar-service-css": "^0.0.4",
|
|
35
33
|
"volar-service-emmet": "^0.0.4",
|
|
36
34
|
"volar-service-html": "^0.0.4",
|
|
@@ -55,6 +53,18 @@
|
|
|
55
53
|
"vscode-languageserver-protocol": "^3.17.3",
|
|
56
54
|
"vscode-languageserver-textdocument": "^1.0.8"
|
|
57
55
|
},
|
|
56
|
+
"peerDependencies": {
|
|
57
|
+
"prettier": "^2.8.8",
|
|
58
|
+
"prettier-plugin-astro": "^0.10.0"
|
|
59
|
+
},
|
|
60
|
+
"peerDependenciesMeta": {
|
|
61
|
+
"prettier": {
|
|
62
|
+
"optional": true
|
|
63
|
+
},
|
|
64
|
+
"prettier-plugin-astro": {
|
|
65
|
+
"optional": true
|
|
66
|
+
}
|
|
67
|
+
},
|
|
58
68
|
"scripts": {
|
|
59
69
|
"build": "tsc",
|
|
60
70
|
"dev": "tsc --watch",
|
|
@@ -1,27 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* TODO: Upstream this
|
|
3
|
-
*/
|
|
4
|
-
import type { AttributeNode, CommentNode, ComponentNode, CustomElementNode, DoctypeNode, ElementNode, ExpressionNode, FragmentNode, FrontmatterNode, LiteralNode, Node, ParentNode, Point, Position, RootNode, TagLikeNode, TextNode } from '@astrojs/compiler/types';
|
|
5
|
-
export declare const is: {
|
|
6
|
-
parent(node: Node): node is ParentNode;
|
|
7
|
-
literal(node: Node): node is LiteralNode;
|
|
8
|
-
tag(node: Node): node is TagLikeNode;
|
|
9
|
-
whitespace(node: Node): node is TextNode;
|
|
10
|
-
root: (node: Node) => node is RootNode;
|
|
11
|
-
element: (node: Node) => node is ElementNode;
|
|
12
|
-
customElement: (node: Node) => node is CustomElementNode;
|
|
13
|
-
component: (node: Node) => node is ComponentNode;
|
|
14
|
-
fragment: (node: Node) => node is FragmentNode;
|
|
15
|
-
expression: (node: Node) => node is ExpressionNode;
|
|
16
|
-
text: (node: Node) => node is TextNode;
|
|
17
|
-
doctype: (node: Node) => node is DoctypeNode;
|
|
18
|
-
comment: (node: Node) => node is CommentNode;
|
|
19
|
-
frontmatter: (node: Node) => node is FrontmatterNode;
|
|
20
|
-
};
|
|
21
|
-
export declare function createCompilerPosition(start: Point, end: Point): Position;
|
|
22
|
-
export declare function createCompilerPoint(line: number, column: number, offset: number): Point;
|
|
23
|
-
type WithRequired<T, K extends keyof T> = T & {
|
|
24
|
-
[P in K]-?: T[P];
|
|
25
|
-
};
|
|
26
|
-
export type AttributeNodeWithPosition = WithRequired<AttributeNode, 'position'>;
|
|
27
|
-
export {};
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
/**
|
|
3
|
-
* TODO: Upstream this
|
|
4
|
-
*/
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.createCompilerPoint = exports.createCompilerPosition = exports.is = void 0;
|
|
7
|
-
function guard(type) {
|
|
8
|
-
return (node) => node.type === type;
|
|
9
|
-
}
|
|
10
|
-
exports.is = {
|
|
11
|
-
parent(node) {
|
|
12
|
-
return Array.isArray(node.children);
|
|
13
|
-
},
|
|
14
|
-
literal(node) {
|
|
15
|
-
return typeof node.value === 'string';
|
|
16
|
-
},
|
|
17
|
-
tag(node) {
|
|
18
|
-
return (node.type === 'element' ||
|
|
19
|
-
node.type === 'custom-element' ||
|
|
20
|
-
node.type === 'component' ||
|
|
21
|
-
node.type === 'fragment');
|
|
22
|
-
},
|
|
23
|
-
whitespace(node) {
|
|
24
|
-
return node.type === 'text' && node.value.trim().length === 0;
|
|
25
|
-
},
|
|
26
|
-
root: guard('root'),
|
|
27
|
-
element: guard('element'),
|
|
28
|
-
customElement: guard('custom-element'),
|
|
29
|
-
component: guard('component'),
|
|
30
|
-
fragment: guard('fragment'),
|
|
31
|
-
expression: guard('expression'),
|
|
32
|
-
text: guard('text'),
|
|
33
|
-
doctype: guard('doctype'),
|
|
34
|
-
comment: guard('comment'),
|
|
35
|
-
frontmatter: guard('frontmatter'),
|
|
36
|
-
};
|
|
37
|
-
function createCompilerPosition(start, end) {
|
|
38
|
-
return {
|
|
39
|
-
start,
|
|
40
|
-
end,
|
|
41
|
-
};
|
|
42
|
-
}
|
|
43
|
-
exports.createCompilerPosition = createCompilerPosition;
|
|
44
|
-
function createCompilerPoint(line, column, offset) {
|
|
45
|
-
return {
|
|
46
|
-
line,
|
|
47
|
-
column,
|
|
48
|
-
offset,
|
|
49
|
-
};
|
|
50
|
-
}
|
|
51
|
-
exports.createCompilerPoint = createCompilerPoint;
|
|
52
|
-
//# sourceMappingURL=compilerUtils.js.map
|