@astrojs/language-server 2.0.15 → 2.0.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/check.js +4 -6
- package/dist/core/astro2tsx.d.ts +11 -1
- package/dist/core/astro2tsx.js +36 -6
- package/dist/core/compilerUtils.d.ts +11 -0
- package/dist/core/compilerUtils.js +13 -0
- package/dist/core/index.d.ts +1 -1
- package/dist/core/parseCSS.d.ts +1 -1
- package/dist/core/parseHTML.js +1 -1
- package/dist/core/utils.d.ts +0 -10
- package/dist/core/utils.js +1 -42
- package/dist/importPackage.d.ts +1 -0
- package/dist/importPackage.js +12 -1
- package/dist/languageServerPlugin.js +2 -2
- package/dist/plugins/astro.js +7 -4
- package/dist/plugins/html.js +1 -1
- package/dist/plugins/typescript/completions.d.ts +2 -2
- package/dist/plugins/typescript/completions.js +1 -27
- package/dist/plugins/typescript/diagnostics.js +1 -1
- package/dist/plugins/typescript/index.d.ts +1 -1
- package/dist/plugins/typescript/index.js +79 -13
- package/dist/plugins/utils.d.ts +37 -0
- package/dist/plugins/utils.js +115 -0
- package/dist/utils.d.ts +10 -39
- package/dist/utils.js +61 -111
- package/package.json +20 -19
- package/dist/plugins/typescript/codeActions.d.ts +0 -4
- package/dist/plugins/typescript/codeActions.js +0 -54
package/dist/check.js
CHANGED
|
@@ -32,10 +32,10 @@ const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
|
32
32
|
const node_url_1 = require("node:url");
|
|
33
33
|
const index_js_1 = require("./core/index.js");
|
|
34
34
|
const svelte_js_1 = require("./core/svelte.js");
|
|
35
|
-
const utils_js_1 = require("./core/utils.js");
|
|
36
35
|
const vue_js_1 = require("./core/vue.js");
|
|
37
36
|
const astro_js_1 = __importDefault(require("./plugins/astro.js"));
|
|
38
37
|
const index_js_2 = __importDefault(require("./plugins/typescript/index.js"));
|
|
38
|
+
const utils_js_1 = require("./utils.js");
|
|
39
39
|
// Export those for downstream consumers
|
|
40
40
|
var language_server_1 = require("@volar/language-server");
|
|
41
41
|
Object.defineProperty(exports, "DiagnosticSeverity", { enumerable: true, get: function () { return language_server_1.DiagnosticSeverity; } });
|
|
@@ -54,9 +54,7 @@ class AstroCheck {
|
|
|
54
54
|
async lint(fileNames = undefined, logErrors = false) {
|
|
55
55
|
const files = fileNames !== undefined
|
|
56
56
|
? fileNames
|
|
57
|
-
: this.project.
|
|
58
|
-
.getScriptFileNames()
|
|
59
|
-
.filter((file) => file.endsWith('.astro'));
|
|
57
|
+
: this.project.languageHost.getScriptFileNames().filter((file) => file.endsWith('.astro'));
|
|
60
58
|
const errors = [];
|
|
61
59
|
for (const file of files) {
|
|
62
60
|
const fileErrors = await this.linter.check(file);
|
|
@@ -64,7 +62,7 @@ class AstroCheck {
|
|
|
64
62
|
this.linter.logErrors(file, fileErrors);
|
|
65
63
|
}
|
|
66
64
|
if (fileErrors.length > 0) {
|
|
67
|
-
const fileSnapshot = this.project.
|
|
65
|
+
const fileSnapshot = this.project.languageHost.getScriptSnapshot(file);
|
|
68
66
|
const fileContent = fileSnapshot?.getText(0, fileSnapshot.getLength());
|
|
69
67
|
errors.push({
|
|
70
68
|
errors: fileErrors,
|
|
@@ -105,7 +103,7 @@ class AstroCheck {
|
|
|
105
103
|
});
|
|
106
104
|
});
|
|
107
105
|
}
|
|
108
|
-
this.linter = kit.createLinter(config, this.project.
|
|
106
|
+
this.linter = kit.createLinter(config, this.project.languageHost);
|
|
109
107
|
}
|
|
110
108
|
getTsconfig() {
|
|
111
109
|
const tsconfig = this.ts.findConfigFile(this.workspacePath, this.ts.sys.fileExists) ||
|
package/dist/core/astro2tsx.d.ts
CHANGED
|
@@ -2,5 +2,15 @@ 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").DiagnosticMessage[]
|
|
5
|
+
diagnostics: import("@astrojs/compiler").DiagnosticMessage[] | {
|
|
6
|
+
code: 1000;
|
|
7
|
+
location: {
|
|
8
|
+
file: string;
|
|
9
|
+
line: number;
|
|
10
|
+
column: number;
|
|
11
|
+
length: number;
|
|
12
|
+
};
|
|
13
|
+
severity: 1;
|
|
14
|
+
text: string;
|
|
15
|
+
}[];
|
|
6
16
|
};
|
package/dist/core/astro2tsx.js
CHANGED
|
@@ -6,8 +6,36 @@ const sourcemap_codec_1 = require("@jridgewell/sourcemap-codec");
|
|
|
6
6
|
const language_core_1 = require("@volar/language-core");
|
|
7
7
|
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
|
|
8
8
|
const utils_js_1 = require("./utils.js");
|
|
9
|
+
function safeConvertToTSX(content, options) {
|
|
10
|
+
try {
|
|
11
|
+
const tsx = (0, sync_1.convertToTSX)(content, { filename: options.filename });
|
|
12
|
+
return tsx;
|
|
13
|
+
}
|
|
14
|
+
catch (e) {
|
|
15
|
+
console.error(`There was an error transforming ${options.filename} to TSX. An empty file will be returned instead. Please create an issue: https://github.com/withastro/language-tools/issues\nError: ${e}.`);
|
|
16
|
+
return {
|
|
17
|
+
code: '',
|
|
18
|
+
map: {
|
|
19
|
+
file: options.filename ?? '',
|
|
20
|
+
sources: [],
|
|
21
|
+
sourcesContent: [],
|
|
22
|
+
names: [],
|
|
23
|
+
mappings: '',
|
|
24
|
+
version: 0,
|
|
25
|
+
},
|
|
26
|
+
diagnostics: [
|
|
27
|
+
{
|
|
28
|
+
code: 1000,
|
|
29
|
+
location: { file: options.filename, line: 1, column: 1, length: content.length },
|
|
30
|
+
severity: 1,
|
|
31
|
+
text: `The Astro compiler encountered an unknown error while parsing this file. Please create an issue with your code and the error shown in the server's logs: https://github.com/withastro/language-tools/issues`,
|
|
32
|
+
},
|
|
33
|
+
],
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
9
37
|
function astro2tsx(input, fileName, ts, htmlDocument) {
|
|
10
|
-
const tsx = (
|
|
38
|
+
const tsx = safeConvertToTSX(input, { filename: fileName });
|
|
11
39
|
return {
|
|
12
40
|
virtualFile: getVirtualFileTSX(input, tsx, fileName, ts, htmlDocument),
|
|
13
41
|
diagnostics: tsx.diagnostics,
|
|
@@ -90,11 +118,13 @@ function getVirtualFileTSX(input, tsx, fileName, ts, htmlDocument) {
|
|
|
90
118
|
data: {},
|
|
91
119
|
});
|
|
92
120
|
const ast = ts.createSourceFile('/a.tsx', tsx.code, ts.ScriptTarget.ESNext);
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
121
|
+
if (ast.statements[0]) {
|
|
122
|
+
mappings.push({
|
|
123
|
+
sourceRange: [0, input.length],
|
|
124
|
+
generatedRange: [ast.statements[0].getStart(ast), tsx.code.length],
|
|
125
|
+
data: {},
|
|
126
|
+
});
|
|
127
|
+
}
|
|
98
128
|
return {
|
|
99
129
|
fileName: fileName + '.tsx',
|
|
100
130
|
kind: language_core_1.FileKind.TypeScriptHostFile,
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AttributeNode, Point } from '@astrojs/compiler';
|
|
2
|
+
import { Position as LSPPosition } from '@volar/language-server';
|
|
3
|
+
/**
|
|
4
|
+
* Transform a Point from the Astro compiler to an LSP Position
|
|
5
|
+
*/
|
|
6
|
+
export declare function PointToPosition(point: Point): LSPPosition;
|
|
7
|
+
type WithRequired<T, K extends keyof T> = T & {
|
|
8
|
+
[P in K]-?: T[P];
|
|
9
|
+
};
|
|
10
|
+
export type AttributeNodeWithPosition = WithRequired<AttributeNode, 'position'>;
|
|
11
|
+
export {};
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.PointToPosition = void 0;
|
|
4
|
+
const language_server_1 = require("@volar/language-server");
|
|
5
|
+
/**
|
|
6
|
+
* Transform a Point from the Astro compiler to an LSP Position
|
|
7
|
+
*/
|
|
8
|
+
function PointToPosition(point) {
|
|
9
|
+
// Columns and lines are 0-based in LSP, but the compiler's Point are 1 based.
|
|
10
|
+
return language_server_1.Position.create(point.line - 1, point.column - 1);
|
|
11
|
+
}
|
|
12
|
+
exports.PointToPosition = PointToPosition;
|
|
13
|
+
//# sourceMappingURL=compilerUtils.js.map
|
package/dist/core/index.d.ts
CHANGED
|
@@ -2,8 +2,8 @@ import type { DiagnosticMessage, ParseResult } from '@astrojs/compiler/types';
|
|
|
2
2
|
import { FileCapabilities, FileKind, type Language, type 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 type { AstroInstall } from '../utils.js';
|
|
5
6
|
import { FrontmatterStatus } from './parseAstro';
|
|
6
|
-
import type { AstroInstall } from './utils';
|
|
7
7
|
export declare function getLanguageModule(astroInstall: AstroInstall | undefined, ts: typeof import('typescript/lib/tsserverlibrary.js')): Language<AstroFile>;
|
|
8
8
|
export declare class AstroFile implements VirtualFile {
|
|
9
9
|
sourceFileName: string;
|
package/dist/core/parseCSS.d.ts
CHANGED
|
@@ -2,7 +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 type { AttributeNodeWithPosition } from '
|
|
5
|
+
import type { AttributeNodeWithPosition } from './compilerUtils.js';
|
|
6
6
|
export declare function extractStylesheets(fileName: string, snapshot: ts.IScriptSnapshot, htmlDocument: HTMLDocument, ast: ParseResult['ast']): VirtualFile[];
|
|
7
7
|
export declare function collectClassesAndIdsFromDocument(ast: ParseResult['ast']): string[];
|
|
8
8
|
export declare function findInlineStyles(ast: ParseResult['ast']): AttributeNodeWithPosition[];
|
package/dist/core/parseHTML.js
CHANGED
|
@@ -26,7 +26,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
26
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
|
-
const utils_1 = require("../utils");
|
|
29
|
+
const utils_1 = require("../plugins/utils");
|
|
30
30
|
const htmlLs = html.getLanguageService();
|
|
31
31
|
function parseHTML(fileName, snapshot, frontmatterEnd) {
|
|
32
32
|
const htmlContent = preprocessHTML(snapshot.getText(0, snapshot.getLength()), frontmatterEnd);
|
package/dist/core/utils.d.ts
CHANGED
|
@@ -1,14 +1,4 @@
|
|
|
1
1
|
import { type VirtualFile } from '@volar/language-core';
|
|
2
|
-
export interface AstroInstall {
|
|
3
|
-
path: string;
|
|
4
|
-
version: {
|
|
5
|
-
full: string;
|
|
6
|
-
major: number;
|
|
7
|
-
minor: number;
|
|
8
|
-
patch: number;
|
|
9
|
-
};
|
|
10
|
-
}
|
|
11
|
-
export declare function getAstroInstall(basePaths: string[]): AstroInstall | undefined;
|
|
12
2
|
export declare function framework2tsx(fileName: string, filePath: string, sourceCode: string, framework: 'vue' | 'svelte'): VirtualFile;
|
|
13
3
|
export declare function classNameFromFilename(filename: string): string;
|
|
14
4
|
export declare function patchTSX(code: string, fileName: string): string;
|
package/dist/core/utils.js
CHANGED
|
@@ -23,52 +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.patchTSX = exports.classNameFromFilename = exports.framework2tsx =
|
|
26
|
+
exports.patchTSX = exports.classNameFromFilename = exports.framework2tsx = void 0;
|
|
27
27
|
const language_core_1 = require("@volar/language-core");
|
|
28
28
|
const path = __importStar(require("node:path"));
|
|
29
29
|
const vscode_uri_1 = require("vscode-uri");
|
|
30
30
|
const importPackage_1 = require("../importPackage");
|
|
31
|
-
function getAstroInstall(basePaths) {
|
|
32
|
-
let astroPath;
|
|
33
|
-
let version;
|
|
34
|
-
try {
|
|
35
|
-
astroPath = (0, importPackage_1.getPackagePath)('astro', basePaths);
|
|
36
|
-
if (!astroPath) {
|
|
37
|
-
throw Error;
|
|
38
|
-
}
|
|
39
|
-
version = require(path.resolve(astroPath, 'package.json')).version;
|
|
40
|
-
}
|
|
41
|
-
catch {
|
|
42
|
-
// If we couldn't find it inside the workspace's node_modules, it might means we're in the monorepo
|
|
43
|
-
try {
|
|
44
|
-
astroPath = (0, importPackage_1.getPackagePath)('./packages/astro', basePaths);
|
|
45
|
-
if (!astroPath) {
|
|
46
|
-
throw Error;
|
|
47
|
-
}
|
|
48
|
-
version = require(path.resolve(astroPath, 'package.json')).version;
|
|
49
|
-
}
|
|
50
|
-
catch (e) {
|
|
51
|
-
// If we still couldn't find it, it probably just doesn't exist
|
|
52
|
-
console.error(`${basePaths[0]} seems to be an Astro project, but we couldn't find Astro or Astro is not installed`);
|
|
53
|
-
return undefined;
|
|
54
|
-
}
|
|
55
|
-
}
|
|
56
|
-
let [major, minor, patch] = version.split('.');
|
|
57
|
-
if (patch.includes('-')) {
|
|
58
|
-
const patchParts = patch.split('-');
|
|
59
|
-
patch = patchParts[0];
|
|
60
|
-
}
|
|
61
|
-
return {
|
|
62
|
-
path: astroPath,
|
|
63
|
-
version: {
|
|
64
|
-
full: version,
|
|
65
|
-
major: Number(major),
|
|
66
|
-
minor: Number(minor),
|
|
67
|
-
patch: Number(patch),
|
|
68
|
-
},
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
exports.getAstroInstall = getAstroInstall;
|
|
72
31
|
function framework2tsx(fileName, filePath, sourceCode, framework) {
|
|
73
32
|
const integrationEditorEntrypoint = framework === 'vue' ? (0, importPackage_1.importVueIntegration)(filePath) : (0, importPackage_1.importSvelteIntegration)(filePath);
|
|
74
33
|
if (!integrationEditorEntrypoint) {
|
package/dist/importPackage.d.ts
CHANGED
|
@@ -7,3 +7,4 @@ export declare function importSvelteIntegration(fromPath: string): typeof svelte
|
|
|
7
7
|
export declare function importVueIntegration(fromPath: string): typeof vue | undefined;
|
|
8
8
|
export declare function importPrettier(fromPath: string): typeof prettier | undefined;
|
|
9
9
|
export declare function getPrettierPluginPath(fromPath: string): string | undefined;
|
|
10
|
+
export declare function getWorkspacePnpPath(workspacePath: string): string | null;
|
package/dist/importPackage.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.getPrettierPluginPath = exports.importPrettier = exports.importVueIntegration = exports.importSvelteIntegration = exports.getPackagePath = exports.setIsTrusted = void 0;
|
|
3
|
+
exports.getWorkspacePnpPath = exports.getPrettierPluginPath = exports.importPrettier = exports.importVueIntegration = exports.importSvelteIntegration = exports.getPackagePath = exports.setIsTrusted = void 0;
|
|
4
4
|
const node_path_1 = require("node:path");
|
|
5
5
|
let isTrusted = true;
|
|
6
6
|
function setIsTrusted(_isTrusted) {
|
|
@@ -58,4 +58,15 @@ function getPrettierPluginPath(fromPath) {
|
|
|
58
58
|
return prettierPluginPath;
|
|
59
59
|
}
|
|
60
60
|
exports.getPrettierPluginPath = getPrettierPluginPath;
|
|
61
|
+
function getWorkspacePnpPath(workspacePath) {
|
|
62
|
+
try {
|
|
63
|
+
const possiblePath = (0, node_path_1.resolve)(workspacePath, '.pnp.cjs');
|
|
64
|
+
require.resolve(possiblePath);
|
|
65
|
+
return possiblePath;
|
|
66
|
+
}
|
|
67
|
+
catch {
|
|
68
|
+
return null;
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
exports.getWorkspacePnpPath = getWorkspacePnpPath;
|
|
61
72
|
//# sourceMappingURL=importPackage.js.map
|
|
@@ -11,12 +11,12 @@ const volar_service_prettier_1 = __importDefault(require("volar-service-prettier
|
|
|
11
11
|
const volar_service_typescript_twoslash_queries_1 = __importDefault(require("volar-service-typescript-twoslash-queries"));
|
|
12
12
|
const core_1 = require("./core");
|
|
13
13
|
const svelte_js_1 = require("./core/svelte.js");
|
|
14
|
-
const utils_1 = require("./core/utils");
|
|
15
14
|
const vue_js_1 = require("./core/vue.js");
|
|
16
15
|
const importPackage_js_1 = require("./importPackage.js");
|
|
17
16
|
const astro_js_1 = __importDefault(require("./plugins/astro.js"));
|
|
18
17
|
const html_js_1 = __importDefault(require("./plugins/html.js"));
|
|
19
18
|
const index_js_1 = __importDefault(require("./plugins/typescript/index.js"));
|
|
19
|
+
const utils_js_1 = require("./utils.js");
|
|
20
20
|
const plugin = (initOptions, modules) => ({
|
|
21
21
|
extraFileExtensions: [
|
|
22
22
|
{ extension: 'astro', isMixedContent: true, scriptKind: 7 },
|
|
@@ -40,7 +40,7 @@ const plugin = (initOptions, modules) => ({
|
|
|
40
40
|
resolveConfig(config, ctx) {
|
|
41
41
|
config.languages ??= {};
|
|
42
42
|
if (ctx) {
|
|
43
|
-
const astroInstall = (0,
|
|
43
|
+
const astroInstall = (0, utils_js_1.getAstroInstall)([ctx.project.rootUri.fsPath]);
|
|
44
44
|
if (!astroInstall) {
|
|
45
45
|
ctx.server.connection.sendNotification(node_1.ShowMessageNotification.type, {
|
|
46
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.`,
|
package/dist/plugins/astro.js
CHANGED
|
@@ -7,7 +7,7 @@ const language_server_1 = require("@volar/language-server");
|
|
|
7
7
|
const fast_glob_1 = __importDefault(require("fast-glob"));
|
|
8
8
|
const node_path_1 = require("node:path");
|
|
9
9
|
const index_js_1 = require("../core/index.js");
|
|
10
|
-
const utils_js_1 = require("
|
|
10
|
+
const utils_js_1 = require("./utils.js");
|
|
11
11
|
exports.default = () => (context, modules) => {
|
|
12
12
|
return {
|
|
13
13
|
triggerCharacters: ['-'],
|
|
@@ -37,7 +37,7 @@ exports.default = () => (context, modules) => {
|
|
|
37
37
|
return file.compilerDiagnostics.map(compilerMessageToDiagnostic);
|
|
38
38
|
function compilerMessageToDiagnostic(message) {
|
|
39
39
|
return {
|
|
40
|
-
message: message.text + '\n\n' + message.hint,
|
|
40
|
+
message: message.text + (message.hint ? '\n\n' + message.hint : ''),
|
|
41
41
|
range: language_server_1.Range.create(message.location.line - 1, message.location.column - 1, message.location.line, message.location.length),
|
|
42
42
|
code: message.code,
|
|
43
43
|
severity: message.severity,
|
|
@@ -48,10 +48,13 @@ exports.default = () => (context, modules) => {
|
|
|
48
48
|
provideCodeLenses(document, token) {
|
|
49
49
|
if (token.isCancellationRequested)
|
|
50
50
|
return;
|
|
51
|
-
if (!
|
|
51
|
+
if (!context || !modules?.typescript || !(0, utils_js_1.isJSDocument)(document.languageId))
|
|
52
|
+
return;
|
|
53
|
+
const languageService = context.inject('typescript/languageService');
|
|
54
|
+
if (!languageService)
|
|
52
55
|
return;
|
|
53
56
|
const ts = modules?.typescript;
|
|
54
|
-
const tsProgram =
|
|
57
|
+
const tsProgram = languageService.getProgram();
|
|
55
58
|
if (!tsProgram)
|
|
56
59
|
return;
|
|
57
60
|
const globcodeLens = [];
|
package/dist/plugins/html.js
CHANGED
|
@@ -6,8 +6,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
const language_server_1 = require("@volar/language-server");
|
|
7
7
|
const volar_service_html_1 = __importDefault(require("volar-service-html"));
|
|
8
8
|
const index_js_1 = require("../core/index.js");
|
|
9
|
-
const utils_js_1 = require("../utils.js");
|
|
10
9
|
const html_data_js_1 = require("./html-data.js");
|
|
10
|
+
const utils_js_1 = require("./utils.js");
|
|
11
11
|
exports.default = () => (context, modules) => {
|
|
12
12
|
const htmlPlugin = (0, volar_service_html_1.default)()(context, modules);
|
|
13
13
|
if (!context) {
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import { CompletionItem, CompletionList
|
|
1
|
+
import { CompletionItem, CompletionList } from '@volar/language-server';
|
|
2
2
|
export declare function enhancedProvideCompletionItems(completions: CompletionList): CompletionList;
|
|
3
|
-
export declare function enhancedResolveCompletionItem(resolvedCompletion: CompletionItem
|
|
3
|
+
export declare function enhancedResolveCompletionItem(resolvedCompletion: CompletionItem): CompletionItem;
|
|
@@ -2,8 +2,6 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.enhancedResolveCompletionItem = exports.enhancedProvideCompletionItems = void 0;
|
|
4
4
|
const language_server_1 = require("@volar/language-server");
|
|
5
|
-
const index_js_1 = require("../../core/index.js");
|
|
6
|
-
const utils_js_1 = require("../../utils.js");
|
|
7
5
|
function enhancedProvideCompletionItems(completions) {
|
|
8
6
|
completions.items = completions.items.filter(isValidCompletion).map((completion) => {
|
|
9
7
|
const source = completion?.data?.originalItem?.source;
|
|
@@ -21,35 +19,11 @@ function enhancedProvideCompletionItems(completions) {
|
|
|
21
19
|
return completions;
|
|
22
20
|
}
|
|
23
21
|
exports.enhancedProvideCompletionItems = enhancedProvideCompletionItems;
|
|
24
|
-
function enhancedResolveCompletionItem(resolvedCompletion
|
|
22
|
+
function enhancedResolveCompletionItem(resolvedCompletion) {
|
|
25
23
|
// Make sure we keep our icons even when the completion is resolved
|
|
26
24
|
if (resolvedCompletion.data.isComponent) {
|
|
27
25
|
resolvedCompletion.detail = getDetailForFileCompletion(resolvedCompletion.detail ?? '', resolvedCompletion.data.originalItem.source);
|
|
28
26
|
}
|
|
29
|
-
// Properly handle completions with actions to make sure their edits end up in the frontmatter when needed
|
|
30
|
-
const [_, source] = context.documents.getVirtualFileByUri(originalItem.data.uri);
|
|
31
|
-
const file = source?.root;
|
|
32
|
-
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
33
|
-
return resolvedCompletion;
|
|
34
|
-
if (file.scriptFiles.includes(originalItem.data.fileName))
|
|
35
|
-
return resolvedCompletion;
|
|
36
|
-
const newLine = context.host.getNewLine ? context.host.getNewLine() : '\n';
|
|
37
|
-
resolvedCompletion.additionalTextEdits = resolvedCompletion.additionalTextEdits?.map((edit) => {
|
|
38
|
-
// HACK: There's a weird situation sometimes where some components (especially Svelte) will get imported as type imports
|
|
39
|
-
// for some unknown reason. This work around the problem by always ensuring a normal import for components
|
|
40
|
-
if (resolvedCompletion.data.isComponent && edit.newText.includes('import type')) {
|
|
41
|
-
edit.newText.replace('import type', 'import');
|
|
42
|
-
}
|
|
43
|
-
// Return a different edit depending on the state of the formatter
|
|
44
|
-
if (file.astroMeta.frontmatter.status === 'doesnt-exist') {
|
|
45
|
-
return (0, utils_js_1.getNewFrontmatterEdit)(edit, newLine);
|
|
46
|
-
}
|
|
47
|
-
if (file.astroMeta.frontmatter.status === 'open') {
|
|
48
|
-
return (0, utils_js_1.getOpenFrontmatterEdit)(edit, newLine);
|
|
49
|
-
}
|
|
50
|
-
edit.range = (0, utils_js_1.ensureRangeIsInFrontmatter)(edit.range, file.astroMeta.frontmatter);
|
|
51
|
-
return edit;
|
|
52
|
-
});
|
|
53
27
|
return resolvedCompletion;
|
|
54
28
|
}
|
|
55
29
|
exports.enhancedResolveCompletionItem = enhancedResolveCompletionItem;
|
|
@@ -13,7 +13,7 @@ var DiagnosticCodes;
|
|
|
13
13
|
DiagnosticCodes[DiagnosticCodes["TYPE_NOT_ASSIGNABLE"] = 2322] = "TYPE_NOT_ASSIGNABLE";
|
|
14
14
|
DiagnosticCodes[DiagnosticCodes["JSX_NO_CLOSING_TAG"] = 17008] = "JSX_NO_CLOSING_TAG";
|
|
15
15
|
DiagnosticCodes[DiagnosticCodes["JSX_ELEMENT_NO_CALL"] = 2604] = "JSX_ELEMENT_NO_CALL";
|
|
16
|
-
})(DiagnosticCodes
|
|
16
|
+
})(DiagnosticCodes || (exports.DiagnosticCodes = DiagnosticCodes = {}));
|
|
17
17
|
function enhancedProvideSemanticDiagnostics(originalDiagnostics, documentLineCount) {
|
|
18
18
|
const diagnostics = originalDiagnostics
|
|
19
19
|
.filter((diagnostic) => diagnostic.range.start.line <= documentLineCount &&
|
|
@@ -3,9 +3,10 @@ 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_typescript_1 = __importDefault(require("volar-service-typescript"));
|
|
7
8
|
const index_js_1 = require("../../core/index.js");
|
|
8
|
-
const
|
|
9
|
+
const utils_js_1 = require("../utils.js");
|
|
9
10
|
const completions_js_1 = require("./completions.js");
|
|
10
11
|
const diagnostics_js_1 = require("./diagnostics.js");
|
|
11
12
|
exports.default = () => (context, modules) => {
|
|
@@ -19,6 +20,82 @@ exports.default = () => (context, modules) => {
|
|
|
19
20
|
}
|
|
20
21
|
return {
|
|
21
22
|
...typeScriptPlugin,
|
|
23
|
+
transformCompletionItem(item) {
|
|
24
|
+
const [_, source] = context.documents.getVirtualFileByUri(item.data.uri);
|
|
25
|
+
const file = source?.root;
|
|
26
|
+
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
27
|
+
return undefined;
|
|
28
|
+
if (file.scriptFiles.includes(item.data.fileName))
|
|
29
|
+
return undefined;
|
|
30
|
+
const newLine = context.host.getCompilationSettings().newLine?.toString() ?? '\n';
|
|
31
|
+
if (item.additionalTextEdits) {
|
|
32
|
+
item.additionalTextEdits = item.additionalTextEdits.map((edit) => {
|
|
33
|
+
// HACK: There's a weird situation sometimes where some components (especially Svelte) will get imported as type imports
|
|
34
|
+
// for some unknown reason. This work around the problem by always ensuring a normal import for components
|
|
35
|
+
if (item.data.isComponent && edit.newText.includes('import type')) {
|
|
36
|
+
edit.newText.replace('import type', 'import');
|
|
37
|
+
}
|
|
38
|
+
if ((0, utils_js_1.editShouldBeInFrontmatter)(edit.range)) {
|
|
39
|
+
return (0, utils_js_1.ensureProperEditForFrontmatter)(edit, file.astroMeta.frontmatter, newLine);
|
|
40
|
+
}
|
|
41
|
+
return edit;
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
return item;
|
|
45
|
+
},
|
|
46
|
+
transformCodeAction(item) {
|
|
47
|
+
if (item.kind !== 'quickfix')
|
|
48
|
+
return undefined;
|
|
49
|
+
const originalFileName = item.data.uri.replace('.tsx', '');
|
|
50
|
+
const [_, source] = context.documents.getVirtualFileByUri(originalFileName);
|
|
51
|
+
const file = source?.root;
|
|
52
|
+
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
53
|
+
return undefined;
|
|
54
|
+
if (file.scriptFiles.includes(item.diagnostics?.[0].data.documentUri.replace('file://', '')))
|
|
55
|
+
return undefined;
|
|
56
|
+
const document = context.getTextDocument(originalFileName);
|
|
57
|
+
if (!document)
|
|
58
|
+
return undefined;
|
|
59
|
+
const newLine = context.host.getCompilationSettings().newLine?.toString() ?? '\n';
|
|
60
|
+
if (!item.edit?.documentChanges)
|
|
61
|
+
return undefined;
|
|
62
|
+
item.edit.documentChanges = item.edit.documentChanges.map((change) => {
|
|
63
|
+
if (language_server_1.TextDocumentEdit.is(change)) {
|
|
64
|
+
change.textDocument.uri = originalFileName;
|
|
65
|
+
if (change.edits.length === 1) {
|
|
66
|
+
change.edits = change.edits.map((edit) => {
|
|
67
|
+
const editInFrontmatter = (0, utils_js_1.editShouldBeInFrontmatter)(edit.range, document);
|
|
68
|
+
if (editInFrontmatter.itShould) {
|
|
69
|
+
return (0, utils_js_1.ensureProperEditForFrontmatter)(edit, file.astroMeta.frontmatter, newLine, editInFrontmatter.position);
|
|
70
|
+
}
|
|
71
|
+
return edit;
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
else {
|
|
75
|
+
if (file.astroMeta.frontmatter.status === 'closed') {
|
|
76
|
+
change.edits = change.edits.map((edit) => {
|
|
77
|
+
const editInFrontmatter = (0, utils_js_1.editShouldBeInFrontmatter)(edit.range, document);
|
|
78
|
+
if (editInFrontmatter.itShould) {
|
|
79
|
+
edit.range = (0, utils_js_1.ensureRangeIsInFrontmatter)(edit.range, file.astroMeta.frontmatter, editInFrontmatter.position);
|
|
80
|
+
}
|
|
81
|
+
return edit;
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
else {
|
|
85
|
+
// TODO: Handle when there's multiple edits and a new frontmatter is potentially needed
|
|
86
|
+
if (change.edits.some((edit) => {
|
|
87
|
+
return (0, utils_js_1.editShouldBeInFrontmatter)(edit.range, document).itShould;
|
|
88
|
+
})) {
|
|
89
|
+
console.error('Code actions with multiple edits that require potentially creating a frontmatter are currently not implemented. In the meantime, please manually insert a frontmatter in your file before using this code action.');
|
|
90
|
+
change.edits = [];
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return change;
|
|
96
|
+
});
|
|
97
|
+
return item;
|
|
98
|
+
},
|
|
22
99
|
async provideCompletionItems(document, position, completionContext, token) {
|
|
23
100
|
const originalCompletions = await typeScriptPlugin.provideCompletionItems(document, position, completionContext, token);
|
|
24
101
|
if (!originalCompletions)
|
|
@@ -29,18 +106,7 @@ exports.default = () => (context, modules) => {
|
|
|
29
106
|
const resolvedCompletionItem = await typeScriptPlugin.resolveCompletionItem(item, token);
|
|
30
107
|
if (!resolvedCompletionItem)
|
|
31
108
|
return item;
|
|
32
|
-
return (0, completions_js_1.enhancedResolveCompletionItem)(resolvedCompletionItem
|
|
33
|
-
},
|
|
34
|
-
async provideCodeActions(document, range, codeActionContext, token) {
|
|
35
|
-
const codeActions = await typeScriptPlugin.provideCodeActions(document, range, codeActionContext, token);
|
|
36
|
-
if (!codeActions)
|
|
37
|
-
return null;
|
|
38
|
-
const [_, source] = context.documents.getVirtualFileByUri(document.uri);
|
|
39
|
-
const file = source?.root;
|
|
40
|
-
if (!(file instanceof index_js_1.AstroFile) || !context.host)
|
|
41
|
-
return codeActions;
|
|
42
|
-
const newLine = context.host.getNewLine ? context.host.getNewLine() : '\n';
|
|
43
|
-
return (0, codeActions_js_1.enhancedProvideCodeActions)(codeActions, file, context.documents.getDocumentByFileName(file.snapshot, file.sourceFileName), document, newLine);
|
|
109
|
+
return (0, completions_js_1.enhancedResolveCompletionItem)(resolvedCompletionItem);
|
|
44
110
|
},
|
|
45
111
|
async provideSemanticDiagnostics(document, token) {
|
|
46
112
|
const [_, source] = context.documents.getVirtualFileByUri(document.uri);
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { HTMLDocument, Node, Range, TextDocument, TextEdit } from 'vscode-html-languageservice';
|
|
2
|
+
import type { FrontmatterStatus } from '../core/parseAstro.js';
|
|
3
|
+
export declare function isJSDocument(languageId: string): boolean;
|
|
4
|
+
/**
|
|
5
|
+
* Return true if a specific node could be a component.
|
|
6
|
+
* 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
|
|
7
|
+
*/
|
|
8
|
+
export declare function isPossibleComponent(node: Node): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Return if a given offset is inside the start tag of a component
|
|
11
|
+
*/
|
|
12
|
+
export declare function isInComponentStartTag(html: HTMLDocument, offset: number): boolean;
|
|
13
|
+
/**
|
|
14
|
+
* Return if a given position is inside a JSX expression
|
|
15
|
+
*/
|
|
16
|
+
export declare function isInsideExpression(html: string, tagStart: number, position: number): boolean;
|
|
17
|
+
/**
|
|
18
|
+
* Return if a given offset is inside the frontmatter
|
|
19
|
+
*/
|
|
20
|
+
export declare function isInsideFrontmatter(offset: number, frontmatter: FrontmatterStatus): boolean;
|
|
21
|
+
type FrontmatterEditPosition = 'top' | 'bottom';
|
|
22
|
+
export declare function ensureProperEditForFrontmatter(edit: TextEdit, frontmatter: FrontmatterStatus, newLine: string, position?: FrontmatterEditPosition): TextEdit;
|
|
23
|
+
/**
|
|
24
|
+
* Force a range to be at the start of the frontmatter if it is outside
|
|
25
|
+
*/
|
|
26
|
+
export declare function ensureRangeIsInFrontmatter(range: Range, frontmatter: FrontmatterStatus, position?: FrontmatterEditPosition): Range;
|
|
27
|
+
export declare function getNewFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
28
|
+
export declare function getOpenFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
29
|
+
type FrontmatterEditValidity = {
|
|
30
|
+
itShould: false;
|
|
31
|
+
position: undefined;
|
|
32
|
+
} | {
|
|
33
|
+
itShould: true;
|
|
34
|
+
position: FrontmatterEditPosition;
|
|
35
|
+
};
|
|
36
|
+
export declare function editShouldBeInFrontmatter(range: Range, astroDocument?: TextDocument): FrontmatterEditValidity;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.editShouldBeInFrontmatter = exports.getOpenFrontmatterEdit = exports.getNewFrontmatterEdit = exports.ensureRangeIsInFrontmatter = exports.ensureProperEditForFrontmatter = exports.isInsideFrontmatter = exports.isInsideExpression = exports.isInComponentStartTag = exports.isPossibleComponent = exports.isJSDocument = void 0;
|
|
4
|
+
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
|
|
5
|
+
function isJSDocument(languageId) {
|
|
6
|
+
return (languageId === 'javascript' ||
|
|
7
|
+
languageId === 'typescript' ||
|
|
8
|
+
languageId === 'javascriptreact' ||
|
|
9
|
+
languageId === 'typescriptreact');
|
|
10
|
+
}
|
|
11
|
+
exports.isJSDocument = isJSDocument;
|
|
12
|
+
/**
|
|
13
|
+
* Return true if a specific node could be a component.
|
|
14
|
+
* 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
|
|
15
|
+
*/
|
|
16
|
+
function isPossibleComponent(node) {
|
|
17
|
+
return !!node.tag?.[0].match(/[A-Z]/) || !!node.tag?.match(/.+[.][A-Z]?/);
|
|
18
|
+
}
|
|
19
|
+
exports.isPossibleComponent = isPossibleComponent;
|
|
20
|
+
/**
|
|
21
|
+
* Return if a given offset is inside the start tag of a component
|
|
22
|
+
*/
|
|
23
|
+
function isInComponentStartTag(html, offset) {
|
|
24
|
+
const node = html.findNodeAt(offset);
|
|
25
|
+
return isPossibleComponent(node) && (!node.startTagEnd || offset < node.startTagEnd);
|
|
26
|
+
}
|
|
27
|
+
exports.isInComponentStartTag = isInComponentStartTag;
|
|
28
|
+
/**
|
|
29
|
+
* Return if a given position is inside a JSX expression
|
|
30
|
+
*/
|
|
31
|
+
function isInsideExpression(html, tagStart, position) {
|
|
32
|
+
const charactersInNode = html.substring(tagStart, position);
|
|
33
|
+
return charactersInNode.lastIndexOf('{') > charactersInNode.lastIndexOf('}');
|
|
34
|
+
}
|
|
35
|
+
exports.isInsideExpression = isInsideExpression;
|
|
36
|
+
/**
|
|
37
|
+
* Return if a given offset is inside the frontmatter
|
|
38
|
+
*/
|
|
39
|
+
function isInsideFrontmatter(offset, frontmatter) {
|
|
40
|
+
switch (frontmatter.status) {
|
|
41
|
+
case 'closed':
|
|
42
|
+
return offset > frontmatter.position.start.offset && offset < frontmatter.position.end.offset;
|
|
43
|
+
case 'open':
|
|
44
|
+
return offset > frontmatter.position.start.offset;
|
|
45
|
+
case 'doesnt-exist':
|
|
46
|
+
return false;
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
exports.isInsideFrontmatter = isInsideFrontmatter;
|
|
50
|
+
function ensureProperEditForFrontmatter(edit, frontmatter, newLine, position = 'top') {
|
|
51
|
+
switch (frontmatter.status) {
|
|
52
|
+
case 'open':
|
|
53
|
+
return getOpenFrontmatterEdit(edit, newLine);
|
|
54
|
+
case 'closed':
|
|
55
|
+
return {
|
|
56
|
+
newText: edit.newText,
|
|
57
|
+
range: ensureRangeIsInFrontmatter(edit.range, frontmatter, position),
|
|
58
|
+
};
|
|
59
|
+
case 'doesnt-exist':
|
|
60
|
+
return getNewFrontmatterEdit(edit, newLine);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.ensureProperEditForFrontmatter = ensureProperEditForFrontmatter;
|
|
64
|
+
/**
|
|
65
|
+
* Force a range to be at the start of the frontmatter if it is outside
|
|
66
|
+
*/
|
|
67
|
+
function ensureRangeIsInFrontmatter(range, frontmatter, position = 'top') {
|
|
68
|
+
if (frontmatter.status === 'open' || frontmatter.status === 'closed') {
|
|
69
|
+
// Q: Why not use PointToPosition?
|
|
70
|
+
// A: The Astro compiler returns positions at the exact line where the frontmatter is, which is not adequate for mapping
|
|
71
|
+
// edits as we want edits *inside* the frontmatter and not on the same line, or you would end up with things like `---import ...`
|
|
72
|
+
const frontmatterStartPosition = {
|
|
73
|
+
line: frontmatter.position.start.line,
|
|
74
|
+
character: frontmatter.position.start.column - 1,
|
|
75
|
+
};
|
|
76
|
+
const frontmatterEndPosition = frontmatter.position.end
|
|
77
|
+
? { line: frontmatter.position.end.line - 1, character: 0 }
|
|
78
|
+
: undefined;
|
|
79
|
+
// If the range start is outside the frontmatter, return a range at the start of the frontmatter
|
|
80
|
+
if (range.start.line < frontmatterStartPosition.line ||
|
|
81
|
+
(frontmatterEndPosition && range.start.line > frontmatterEndPosition.line)) {
|
|
82
|
+
if (frontmatterEndPosition && position === 'bottom') {
|
|
83
|
+
return vscode_html_languageservice_1.Range.create(frontmatterEndPosition, frontmatterEndPosition);
|
|
84
|
+
}
|
|
85
|
+
return vscode_html_languageservice_1.Range.create(frontmatterStartPosition, frontmatterStartPosition);
|
|
86
|
+
}
|
|
87
|
+
return range;
|
|
88
|
+
}
|
|
89
|
+
return range;
|
|
90
|
+
}
|
|
91
|
+
exports.ensureRangeIsInFrontmatter = ensureRangeIsInFrontmatter;
|
|
92
|
+
function getNewFrontmatterEdit(edit, newLine) {
|
|
93
|
+
edit.newText = `---${newLine}${edit.newText}---${newLine}${newLine}`;
|
|
94
|
+
edit.range = vscode_html_languageservice_1.Range.create(0, 0, 0, 0);
|
|
95
|
+
return edit;
|
|
96
|
+
}
|
|
97
|
+
exports.getNewFrontmatterEdit = getNewFrontmatterEdit;
|
|
98
|
+
function getOpenFrontmatterEdit(edit, newLine) {
|
|
99
|
+
edit.newText = edit.newText.startsWith(newLine)
|
|
100
|
+
? `${edit.newText}---`
|
|
101
|
+
: `${newLine}${edit.newText}---`;
|
|
102
|
+
return edit;
|
|
103
|
+
}
|
|
104
|
+
exports.getOpenFrontmatterEdit = getOpenFrontmatterEdit;
|
|
105
|
+
// Most edits that are at 0:0, or outside the document are intended for the frontmatter
|
|
106
|
+
function editShouldBeInFrontmatter(range, astroDocument) {
|
|
107
|
+
const isAtZeroZero = range.start.line === 0 && range.start.character === 0;
|
|
108
|
+
const isPastFile = astroDocument && range.start.line > astroDocument.lineCount;
|
|
109
|
+
const shouldIt = isAtZeroZero || isPastFile;
|
|
110
|
+
return shouldIt
|
|
111
|
+
? { itShould: true, position: isPastFile ? 'bottom' : 'top' }
|
|
112
|
+
: { itShould: false, position: undefined };
|
|
113
|
+
}
|
|
114
|
+
exports.editShouldBeInFrontmatter = editShouldBeInFrontmatter;
|
|
115
|
+
//# sourceMappingURL=utils.js.map
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,39 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
* Return if a given offset is inside the start tag of a component
|
|
12
|
-
*/
|
|
13
|
-
export declare function isInComponentStartTag(html: HTMLDocument, offset: number): boolean;
|
|
14
|
-
/**
|
|
15
|
-
* Return if a given position is inside a JSX expression
|
|
16
|
-
*/
|
|
17
|
-
export declare function isInsideExpression(html: string, tagStart: number, position: number): boolean;
|
|
18
|
-
/**
|
|
19
|
-
* Return if a given offset is inside the frontmatter
|
|
20
|
-
*/
|
|
21
|
-
export declare function isInsideFrontmatter(offset: number, frontmatter: FrontmatterStatus): boolean;
|
|
22
|
-
/**
|
|
23
|
-
* Transform a Point from the Astro compiler to an LSP Position
|
|
24
|
-
*/
|
|
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'>;
|
|
32
|
-
/**
|
|
33
|
-
* Force a range to be at the start of the frontmatter if it is outside
|
|
34
|
-
*/
|
|
35
|
-
export declare function ensureRangeIsInFrontmatter(range: Range, frontmatter: FrontmatterStatus): Range;
|
|
36
|
-
export declare function getNewFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
37
|
-
export declare function getOpenFrontmatterEdit(edit: TextEdit, newLine: string): TextEdit;
|
|
38
|
-
export declare function getWorkspacePnpPath(workspacePath: string): string | null;
|
|
39
|
-
export {};
|
|
1
|
+
export interface AstroInstall {
|
|
2
|
+
path: string;
|
|
3
|
+
version: {
|
|
4
|
+
full: string;
|
|
5
|
+
major: number;
|
|
6
|
+
minor: number;
|
|
7
|
+
patch: number;
|
|
8
|
+
};
|
|
9
|
+
}
|
|
10
|
+
export declare function getAstroInstall(basePaths: string[]): AstroInstall | undefined;
|
package/dist/utils.js
CHANGED
|
@@ -1,120 +1,70 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
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;
|
|
4
24
|
};
|
|
5
25
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
languageId === 'javascriptreact' ||
|
|
13
|
-
languageId === 'typescriptreact');
|
|
14
|
-
}
|
|
15
|
-
exports.isJSDocument = isJSDocument;
|
|
16
|
-
/**
|
|
17
|
-
* Return true if a specific node could be a component.
|
|
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
|
|
19
|
-
*/
|
|
20
|
-
function isPossibleComponent(node) {
|
|
21
|
-
return !!node.tag?.[0].match(/[A-Z]/) || !!node.tag?.match(/.+[.][A-Z]?/);
|
|
22
|
-
}
|
|
23
|
-
exports.isPossibleComponent = isPossibleComponent;
|
|
24
|
-
/**
|
|
25
|
-
* Return if a given offset is inside the start tag of a component
|
|
26
|
-
*/
|
|
27
|
-
function isInComponentStartTag(html, offset) {
|
|
28
|
-
const node = html.findNodeAt(offset);
|
|
29
|
-
return isPossibleComponent(node) && (!node.startTagEnd || offset < node.startTagEnd);
|
|
30
|
-
}
|
|
31
|
-
exports.isInComponentStartTag = isInComponentStartTag;
|
|
32
|
-
/**
|
|
33
|
-
* Return if a given position is inside a JSX expression
|
|
34
|
-
*/
|
|
35
|
-
function isInsideExpression(html, tagStart, position) {
|
|
36
|
-
const charactersInNode = html.substring(tagStart, position);
|
|
37
|
-
return charactersInNode.lastIndexOf('{') > charactersInNode.lastIndexOf('}');
|
|
38
|
-
}
|
|
39
|
-
exports.isInsideExpression = isInsideExpression;
|
|
40
|
-
/**
|
|
41
|
-
* Return if a given offset is inside the frontmatter
|
|
42
|
-
*/
|
|
43
|
-
function isInsideFrontmatter(offset, frontmatter) {
|
|
44
|
-
switch (frontmatter.status) {
|
|
45
|
-
case 'closed':
|
|
46
|
-
return offset > frontmatter.position.start.offset && offset < frontmatter.position.end.offset;
|
|
47
|
-
case 'open':
|
|
48
|
-
return offset > frontmatter.position.start.offset;
|
|
49
|
-
case 'doesnt-exist':
|
|
50
|
-
return false;
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
exports.isInsideFrontmatter = isInsideFrontmatter;
|
|
54
|
-
/**
|
|
55
|
-
* Transform a Point from the Astro compiler to an LSP Position
|
|
56
|
-
*/
|
|
57
|
-
function PointToPosition(point) {
|
|
58
|
-
// Columns are 0-based in LSP, but the compiler's Point are 1 based.
|
|
59
|
-
return vscode_html_languageservice_1.Position.create(point.line, point.column - 1);
|
|
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;
|
|
77
|
-
/**
|
|
78
|
-
* Force a range to be at the start of the frontmatter if it is outside
|
|
79
|
-
*/
|
|
80
|
-
function ensureRangeIsInFrontmatter(range, frontmatter) {
|
|
81
|
-
if (frontmatter.status === 'open' || frontmatter.status === 'closed') {
|
|
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;
|
|
92
|
-
}
|
|
93
|
-
return range;
|
|
94
|
-
}
|
|
95
|
-
exports.ensureRangeIsInFrontmatter = ensureRangeIsInFrontmatter;
|
|
96
|
-
function getNewFrontmatterEdit(edit, newLine) {
|
|
97
|
-
edit.newText = `---${newLine}${edit.newText}---${newLine}${newLine}`;
|
|
98
|
-
edit.range = vscode_html_languageservice_1.Range.create(0, 0, 0, 0);
|
|
99
|
-
return edit;
|
|
100
|
-
}
|
|
101
|
-
exports.getNewFrontmatterEdit = getNewFrontmatterEdit;
|
|
102
|
-
function getOpenFrontmatterEdit(edit, newLine) {
|
|
103
|
-
edit.newText = edit.newText.startsWith(newLine)
|
|
104
|
-
? `${edit.newText}---`
|
|
105
|
-
: `${newLine}${edit.newText}---`;
|
|
106
|
-
return edit;
|
|
107
|
-
}
|
|
108
|
-
exports.getOpenFrontmatterEdit = getOpenFrontmatterEdit;
|
|
109
|
-
function getWorkspacePnpPath(workspacePath) {
|
|
26
|
+
exports.getAstroInstall = void 0;
|
|
27
|
+
const path = __importStar(require("node:path"));
|
|
28
|
+
const importPackage_js_1 = require("./importPackage.js");
|
|
29
|
+
function getAstroInstall(basePaths) {
|
|
30
|
+
let astroPath;
|
|
31
|
+
let version;
|
|
110
32
|
try {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
33
|
+
astroPath = (0, importPackage_js_1.getPackagePath)('astro', basePaths);
|
|
34
|
+
if (!astroPath) {
|
|
35
|
+
throw Error;
|
|
36
|
+
}
|
|
37
|
+
version = require(path.resolve(astroPath, 'package.json')).version;
|
|
114
38
|
}
|
|
115
39
|
catch {
|
|
116
|
-
|
|
40
|
+
// If we couldn't find it inside the workspace's node_modules, it might means we're in the monorepo
|
|
41
|
+
try {
|
|
42
|
+
astroPath = (0, importPackage_js_1.getPackagePath)('./packages/astro', basePaths);
|
|
43
|
+
if (!astroPath) {
|
|
44
|
+
throw Error;
|
|
45
|
+
}
|
|
46
|
+
version = require(path.resolve(astroPath, 'package.json')).version;
|
|
47
|
+
}
|
|
48
|
+
catch (e) {
|
|
49
|
+
// If we still couldn't find it, it probably just doesn't exist
|
|
50
|
+
console.error(`${basePaths[0]} seems to be an Astro project, but we couldn't find Astro or Astro is not installed`);
|
|
51
|
+
return undefined;
|
|
52
|
+
}
|
|
117
53
|
}
|
|
54
|
+
let [major, minor, patch] = version.split('.');
|
|
55
|
+
if (patch.includes('-')) {
|
|
56
|
+
const patchParts = patch.split('-');
|
|
57
|
+
patch = patchParts[0];
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
path: astroPath,
|
|
61
|
+
version: {
|
|
62
|
+
full: version,
|
|
63
|
+
major: Number(major),
|
|
64
|
+
minor: Number(minor),
|
|
65
|
+
patch: Number(patch),
|
|
66
|
+
},
|
|
67
|
+
};
|
|
118
68
|
}
|
|
119
|
-
exports.
|
|
69
|
+
exports.getAstroInstall = getAstroInstall;
|
|
120
70
|
//# sourceMappingURL=utils.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/language-server",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.17",
|
|
4
4
|
"author": "withastro",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -20,36 +20,37 @@
|
|
|
20
20
|
"astro-ls": "./bin/nodeServer.js"
|
|
21
21
|
},
|
|
22
22
|
"dependencies": {
|
|
23
|
-
"@astrojs/compiler": "^1.5.
|
|
23
|
+
"@astrojs/compiler": "^1.5.1",
|
|
24
24
|
"@jridgewell/sourcemap-codec": "^1.4.15",
|
|
25
|
-
"@volar/kit": "1.
|
|
26
|
-
"@volar/language-core": "1.
|
|
27
|
-
"@volar/language-server": "1.
|
|
28
|
-
"@volar/language-service": "1.
|
|
29
|
-
"@volar/source-map": "1.
|
|
25
|
+
"@volar/kit": "1.7.4",
|
|
26
|
+
"@volar/language-core": "1.7.4",
|
|
27
|
+
"@volar/language-server": "1.7.4",
|
|
28
|
+
"@volar/language-service": "1.7.4",
|
|
29
|
+
"@volar/source-map": "1.7.4",
|
|
30
|
+
"@volar/typescript": "1.7.4",
|
|
30
31
|
"fast-glob": "^3.2.12",
|
|
31
32
|
"muggle-string": "^0.3.1",
|
|
32
|
-
"volar-service-css": "0.0.
|
|
33
|
-
"volar-service-emmet": "0.0.
|
|
34
|
-
"volar-service-html": "0.0.
|
|
35
|
-
"volar-service-prettier": "0.0.
|
|
36
|
-
"volar-service-typescript": "0.0.
|
|
37
|
-
"volar-service-typescript-twoslash-queries": "0.0.
|
|
38
|
-
"vscode-html-languageservice": "^5.0.
|
|
33
|
+
"volar-service-css": "0.0.7",
|
|
34
|
+
"volar-service-emmet": "0.0.7",
|
|
35
|
+
"volar-service-html": "0.0.7",
|
|
36
|
+
"volar-service-prettier": "0.0.7",
|
|
37
|
+
"volar-service-typescript": "0.0.7",
|
|
38
|
+
"volar-service-typescript-twoslash-queries": "0.0.7",
|
|
39
|
+
"vscode-html-languageservice": "^5.0.6",
|
|
39
40
|
"vscode-uri": "^3.0.7"
|
|
40
41
|
},
|
|
41
42
|
"devDependencies": {
|
|
42
|
-
"@astrojs/svelte": "^
|
|
43
|
-
"@astrojs/vue": "^2.2.
|
|
43
|
+
"@astrojs/svelte": "^3.0.0",
|
|
44
|
+
"@astrojs/vue": "^2.2.1",
|
|
44
45
|
"@types/chai": "^4.3.5",
|
|
45
46
|
"@types/mocha": "^10.0.1",
|
|
46
47
|
"@types/node": "^16.18.26",
|
|
47
|
-
"@types/prettier": "^2.7.
|
|
48
|
-
"astro": "^2.
|
|
48
|
+
"@types/prettier": "^2.7.3",
|
|
49
|
+
"astro": "^2.6.2",
|
|
49
50
|
"chai": "^4.3.7",
|
|
50
51
|
"mocha": "^10.2.0",
|
|
51
52
|
"tsx": "^3.12.7",
|
|
52
|
-
"typescript": "~5.
|
|
53
|
+
"typescript": "~5.1.3",
|
|
53
54
|
"vscode-languageserver-protocol": "^3.17.3",
|
|
54
55
|
"vscode-languageserver-textdocument": "^1.0.8"
|
|
55
56
|
},
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
import { CodeAction } from '@volar/language-server';
|
|
2
|
-
import type { TextDocument } from 'vscode-html-languageservice';
|
|
3
|
-
import type { AstroFile } from '../../core/index.js';
|
|
4
|
-
export declare function enhancedProvideCodeActions(codeActions: CodeAction[], file: AstroFile, document: TextDocument, originalDocument: TextDocument, newLine: string): CodeAction[];
|
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.enhancedProvideCodeActions = void 0;
|
|
4
|
-
const language_server_1 = require("@volar/language-server");
|
|
5
|
-
const vscode_uri_1 = require("vscode-uri");
|
|
6
|
-
const utils_js_1 = require("../../utils.js");
|
|
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) {
|
|
10
|
-
codeActions = codeActions.map((codeAction) => {
|
|
11
|
-
if (!codeAction.edit)
|
|
12
|
-
return codeAction;
|
|
13
|
-
if (file.scriptFiles.includes(vscode_uri_1.URI.parse(originalDocument.uri).path))
|
|
14
|
-
return codeAction;
|
|
15
|
-
codeAction.edit.documentChanges = codeAction.edit.documentChanges?.map((change) => {
|
|
16
|
-
if (language_server_1.TextDocumentEdit.is(change)) {
|
|
17
|
-
change.edits = change.edits.map((edit) => {
|
|
18
|
-
// Move code actions adding new imports to the frontmatter, as by default they'll be outside of it
|
|
19
|
-
// TODO: This is a bit brittle, but we're unfortunately too late into the process to be able to tell the `fixName`
|
|
20
|
-
// Maybe contribute upstream to pass the `fixName` through `data`?
|
|
21
|
-
if (edit.newText.trim().startsWith('import ')) {
|
|
22
|
-
if (file.astroMeta.frontmatter.status === 'doesnt-exist') {
|
|
23
|
-
return (0, utils_js_1.getNewFrontmatterEdit)(edit, newLine);
|
|
24
|
-
}
|
|
25
|
-
if (file.astroMeta.frontmatter.status === 'open') {
|
|
26
|
-
return (0, utils_js_1.getOpenFrontmatterEdit)(edit, newLine);
|
|
27
|
-
}
|
|
28
|
-
edit.range = (0, utils_js_1.ensureRangeIsInFrontmatter)(edit.range, file.astroMeta.frontmatter);
|
|
29
|
-
}
|
|
30
|
-
// Some code actions will insert code at the end of the generated TSX file, so we'll manually
|
|
31
|
-
// redirect it to the end of the frontmatter instead, or create a frontmatter if one doesn't exist
|
|
32
|
-
if (edit.range.start.line > document.lineCount) {
|
|
33
|
-
switch (file.astroMeta.frontmatter.status) {
|
|
34
|
-
case 'open':
|
|
35
|
-
return (0, utils_js_1.getOpenFrontmatterEdit)(edit, newLine);
|
|
36
|
-
case 'closed':
|
|
37
|
-
const position = (0, utils_js_1.PointToPosition)(file.astroMeta.frontmatter.position.end);
|
|
38
|
-
edit.range = language_server_1.Range.create(position, position);
|
|
39
|
-
return edit;
|
|
40
|
-
case 'doesnt-exist':
|
|
41
|
-
return (0, utils_js_1.getNewFrontmatterEdit)(edit, newLine);
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
return edit;
|
|
45
|
-
});
|
|
46
|
-
}
|
|
47
|
-
return change;
|
|
48
|
-
});
|
|
49
|
-
return codeAction;
|
|
50
|
-
});
|
|
51
|
-
return codeActions;
|
|
52
|
-
}
|
|
53
|
-
exports.enhancedProvideCodeActions = enhancedProvideCodeActions;
|
|
54
|
-
//# sourceMappingURL=codeActions.js.map
|