Clean up dependencies
All checks were successful
Build and Push / build (push) Successful in 18s

This commit is contained in:
2026-02-16 15:12:59 -05:00
parent d181f77fb2
commit 2f15523a55
14941 changed files with 0 additions and 2078483 deletions

View File

@@ -1,3 +0,0 @@
import type { Mapping } from '@volar/language-core';
import type { Segment } from 'muggle-string';
export declare function buildMappings<T>(chunks: Segment<T>[]): Mapping<T>[];

View File

@@ -1,23 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildMappings = buildMappings;
function buildMappings(chunks) {
let length = 0;
const mappings = [];
for (const segment of chunks) {
if (typeof segment === 'string') {
length += segment.length;
}
else {
mappings.push({
sourceOffsets: [segment[2]],
generatedOffsets: [length],
lengths: [segment[0].length],
data: segment[3],
});
length += segment[0].length;
}
}
return mappings;
}
//# sourceMappingURL=buildMappings.js.map

View File

@@ -1,39 +0,0 @@
import * as kit from '@volar/kit';
import { Diagnostic, DiagnosticSeverity } from '@volar/language-server';
export { Diagnostic, DiagnosticSeverity };
export interface CheckResult {
status: 'completed' | 'cancelled' | undefined;
fileChecked: number;
errors: number;
warnings: number;
hints: number;
fileResult: {
errors: kit.Diagnostic[];
fileUrl: URL;
fileContent: string;
text: string;
}[];
}
export declare class AstroCheck {
private readonly workspacePath;
private readonly typescriptPath;
private readonly tsconfigPath;
private ts;
linter: ReturnType<(typeof kit)['createTypeScriptChecker']>;
constructor(workspacePath: string, typescriptPath: string | undefined, tsconfigPath: string | undefined);
/**
* Lint a list of files or the entire project and optionally log the errors found
* @param fileNames List of files to lint, if undefined, all files included in the project will be linted
* @param logErrors Whether to log errors by itself. This is disabled by default.
* @return {CheckResult} The result of the lint, including a list of errors, the file's content and its file path.
*/
lint({ fileNames, cancel, logErrors, }: {
fileNames?: string[] | undefined;
cancel?: () => boolean;
logErrors?: {
level: 'error' | 'warning' | 'hint';
} | undefined;
}): Promise<CheckResult>;
private initialize;
private getTsconfig;
}

View File

@@ -1,159 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AstroCheck = exports.DiagnosticSeverity = exports.Diagnostic = void 0;
const node_fs_1 = require("node:fs");
const node_os_1 = require("node:os");
const node_path_1 = require("node:path");
const node_url_1 = require("node:url");
const kit = __importStar(require("@volar/kit"));
const language_server_1 = require("@volar/language-server");
Object.defineProperty(exports, "Diagnostic", { enumerable: true, get: function () { return language_server_1.Diagnostic; } });
Object.defineProperty(exports, "DiagnosticSeverity", { enumerable: true, get: function () { return language_server_1.DiagnosticSeverity; } });
const fast_glob_1 = __importDefault(require("fast-glob"));
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("./core/index.js");
const svelte_js_1 = require("./core/svelte.js");
const vue_js_1 = require("./core/vue.js");
const utils_js_1 = require("./utils.js");
const astro_js_1 = require("./plugins/astro.js");
const index_js_2 = require("./plugins/typescript/index.js");
class AstroCheck {
constructor(workspacePath, typescriptPath, tsconfigPath) {
this.workspacePath = workspacePath;
this.typescriptPath = typescriptPath;
this.tsconfigPath = tsconfigPath;
this.initialize();
}
/**
* Lint a list of files or the entire project and optionally log the errors found
* @param fileNames List of files to lint, if undefined, all files included in the project will be linted
* @param logErrors Whether to log errors by itself. This is disabled by default.
* @return {CheckResult} The result of the lint, including a list of errors, the file's content and its file path.
*/
async lint({ fileNames = undefined, cancel = () => false, logErrors = undefined, }) {
let files = (fileNames !== undefined ? fileNames : this.linter.getRootFileNames()).filter((file) => {
// We don't have the same understanding of Svelte and Vue files as their own respective tools (vue-tsc, svelte-check)
// So we don't want to check them here
return !file.endsWith('.vue') && !file.endsWith('.svelte');
});
const result = {
status: undefined,
fileChecked: 0,
errors: 0,
warnings: 0,
hints: 0,
fileResult: [],
};
for (const file of files) {
if (cancel()) {
result.status = 'cancelled';
return result;
}
const fileDiagnostics = await this.linter.check(file);
// Filter diagnostics based on the logErrors level
const fileDiagnosticsToPrint = fileDiagnostics.filter((diag) => {
const severity = diag.severity ?? language_server_1.DiagnosticSeverity.Error;
switch (logErrors?.level ?? 'hint') {
case 'error':
return severity <= language_server_1.DiagnosticSeverity.Error;
case 'warning':
return severity <= language_server_1.DiagnosticSeverity.Warning;
case 'hint':
return severity <= language_server_1.DiagnosticSeverity.Hint;
}
});
if (fileDiagnostics.length > 0) {
const errorText = this.linter.printErrors(file, fileDiagnosticsToPrint);
if (logErrors !== undefined && errorText) {
console.info(errorText);
}
const fileSnapshot = this.linter.language.scripts.get(vscode_uri_1.URI.file(file))?.snapshot;
const fileContent = fileSnapshot?.getText(0, fileSnapshot.getLength());
result.fileResult.push({
errors: fileDiagnostics,
fileContent: fileContent ?? '',
fileUrl: (0, node_url_1.pathToFileURL)(file),
text: errorText,
});
result.errors += fileDiagnostics.filter((diag) => diag.severity === language_server_1.DiagnosticSeverity.Error).length;
result.warnings += fileDiagnostics.filter((diag) => diag.severity === language_server_1.DiagnosticSeverity.Warning).length;
result.hints += fileDiagnostics.filter((diag) => diag.severity === language_server_1.DiagnosticSeverity.Hint).length;
}
result.fileChecked += 1;
}
result.status = 'completed';
return result;
}
initialize() {
this.ts = this.typescriptPath ? require(this.typescriptPath) : require('typescript');
const tsconfigPath = this.getTsconfig();
const languagePlugins = [
(0, index_js_1.getAstroLanguagePlugin)(),
(0, svelte_js_1.getSvelteLanguagePlugin)(),
(0, vue_js_1.getVueLanguagePlugin)(),
];
const services = [...(0, index_js_2.create)(this.ts), (0, astro_js_1.create)(this.ts)];
if (tsconfigPath) {
const includeProjectReference = false; // #920
this.linter = kit.createTypeScriptChecker(languagePlugins, services, tsconfigPath, includeProjectReference, ({ project }) => {
const { languageServiceHost } = project.typescript;
const astroInstall = (0, utils_js_1.getAstroInstall)([this.workspacePath]);
(0, index_js_1.addAstroTypes)(typeof astroInstall === 'string' ? undefined : astroInstall, this.ts, languageServiceHost);
});
}
else {
this.linter = kit.createTypeScriptInferredChecker(languagePlugins, services, () => {
return fast_glob_1.default.sync('**/*.astro', {
cwd: this.workspacePath,
ignore: ['node_modules'],
absolute: true,
});
}, undefined, ({ project }) => {
const { languageServiceHost } = project.typescript;
const astroInstall = (0, utils_js_1.getAstroInstall)([this.workspacePath]);
(0, index_js_1.addAstroTypes)(typeof astroInstall === 'string' ? undefined : astroInstall, this.ts, languageServiceHost);
});
}
}
getTsconfig() {
if (this.tsconfigPath) {
const tsconfig = (0, node_path_1.resolve)(this.workspacePath, this.tsconfigPath.replace(/^~/, (0, node_os_1.homedir)()));
if (!(0, node_fs_1.existsSync)(tsconfig)) {
throw new Error(`Specified tsconfig file \`${tsconfig}\` does not exist.`);
}
return tsconfig;
}
const searchPath = this.workspacePath;
const tsconfig = this.ts.findConfigFile(searchPath, this.ts.sys.fileExists) ||
this.ts.findConfigFile(searchPath, this.ts.sys.fileExists, 'jsconfig.json');
return tsconfig;
}
}
exports.AstroCheck = AstroCheck;
//# sourceMappingURL=check.js.map

View File

@@ -1,59 +0,0 @@
import type { ConvertToTSXOptions, TSXExtractedScript, TSXExtractedStyle, TSXResult } from '@astrojs/compiler/types';
import type { VirtualCode } from '@volar/language-core';
import { Range } from '@volar/language-server';
export interface LSPTSXRanges {
frontmatter: Range;
body: Range;
scripts: TSXExtractedScript[];
styles: TSXExtractedStyle[];
}
export declare function safeConvertToTSX(content: string, options: ConvertToTSXOptions): TSXResult | {
code: string;
map: {
file: string;
sources: never[];
sourcesContent: never[];
names: never[];
mappings: string;
version: number;
};
diagnostics: {
code: 1000;
location: {
file: string;
line: number;
column: number;
length: number;
};
severity: 1;
text: string;
}[];
metaRanges: {
frontmatter: {
start: number;
end: number;
};
body: {
start: number;
end: number;
};
scripts: never[];
styles: never[];
};
};
export declare function getTSXRangesAsLSPRanges(tsx: TSXResult): LSPTSXRanges;
export declare function astro2tsx(input: string, fileName: string): {
virtualCode: VirtualCode;
diagnostics: import("@astrojs/compiler").DiagnosticMessage[] | {
code: 1000;
location: {
file: string;
line: number;
column: number;
length: number;
};
severity: 1;
text: string;
}[];
ranges: LSPTSXRanges;
};

View File

@@ -1,144 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.safeConvertToTSX = safeConvertToTSX;
exports.getTSXRangesAsLSPRanges = getTSXRangesAsLSPRanges;
exports.astro2tsx = astro2tsx;
const sync_1 = require("@astrojs/compiler/sync");
const sourcemap_codec_1 = require("@jridgewell/sourcemap-codec");
const language_server_1 = require("@volar/language-server");
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
const utils_js_1 = require("./utils.js");
function safeConvertToTSX(content, options) {
try {
const tsx = (0, sync_1.convertToTSX)(content, {
filename: options.filename,
includeScripts: false,
includeStyles: false,
});
return tsx;
}
catch (e) {
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}.`);
return {
code: '',
map: {
file: options.filename ?? '',
sources: [],
sourcesContent: [],
names: [],
mappings: '',
version: 0,
},
diagnostics: [
{
code: 1000,
location: { file: options.filename, line: 1, column: 1, length: content.length },
severity: 1,
text: `The Astro compiler encountered an unknown error while transform this file to TSX. Please create an issue with your code and the error shown in the server's logs: https://github.com/withastro/language-tools/issues`,
},
],
metaRanges: {
frontmatter: {
start: 0,
end: 0,
},
body: {
start: 0,
end: 0,
},
scripts: [],
styles: [],
},
};
}
}
function getTSXRangesAsLSPRanges(tsx) {
const textDocument = vscode_html_languageservice_1.TextDocument.create('', 'typescriptreact', 0, tsx.code);
return {
frontmatter: language_server_1.Range.create(textDocument.positionAt(tsx.metaRanges.frontmatter.start), textDocument.positionAt(tsx.metaRanges.frontmatter.end)),
body: language_server_1.Range.create(textDocument.positionAt(tsx.metaRanges.body.start), textDocument.positionAt(tsx.metaRanges.body.end)),
scripts: tsx.metaRanges.scripts ?? [],
styles: tsx.metaRanges.styles ?? [],
};
}
function astro2tsx(input, fileName) {
const tsx = safeConvertToTSX(input, { filename: fileName });
return {
virtualCode: getVirtualCodeTSX(input, tsx, fileName),
diagnostics: tsx.diagnostics,
ranges: getTSXRangesAsLSPRanges(tsx),
};
}
function getVirtualCodeTSX(input, tsx, fileName) {
tsx.code = (0, utils_js_1.patchTSX)(tsx.code, fileName);
const v3Mappings = (0, sourcemap_codec_1.decode)(tsx.map.mappings);
const sourcedDoc = vscode_html_languageservice_1.TextDocument.create('', 'astro', 0, input);
const genDoc = vscode_html_languageservice_1.TextDocument.create('', 'typescriptreact', 0, tsx.code);
const mappings = [];
let current;
for (let genLine = 0; genLine < v3Mappings.length; genLine++) {
for (const segment of v3Mappings[genLine]) {
const genCharacter = segment[0];
const genOffset = genDoc.offsetAt({ line: genLine, character: genCharacter });
if (current) {
let length = genOffset - current.genOffset;
const sourceText = input.substring(current.sourceOffset, current.sourceOffset + length);
const genText = tsx.code.substring(current.genOffset, current.genOffset + length);
if (sourceText !== genText) {
length = 0;
for (let i = 0; i < genOffset - current.genOffset; i++) {
if (sourceText[i] === genText[i]) {
length = i + 1;
}
else {
break;
}
}
}
if (length > 0) {
const lastMapping = mappings.length ? mappings[mappings.length - 1] : undefined;
if (lastMapping &&
lastMapping.generatedOffsets[0] + lastMapping.lengths[0] === current.genOffset &&
lastMapping.sourceOffsets[0] + lastMapping.lengths[0] === current.sourceOffset) {
lastMapping.lengths[0] += length;
}
else {
mappings.push({
sourceOffsets: [current.sourceOffset],
generatedOffsets: [current.genOffset],
lengths: [length],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
});
}
}
current = undefined;
}
if (segment[2] !== undefined && segment[3] !== undefined) {
const sourceOffset = sourcedDoc.offsetAt({ line: segment[2], character: segment[3] });
current = {
genOffset,
sourceOffset,
};
}
}
}
return {
id: 'tsx',
languageId: 'typescriptreact',
snapshot: {
getText: (start, end) => tsx.code.substring(start, end),
getLength: () => tsx.code.length,
getChangeRange: () => undefined,
},
mappings: mappings,
embeddedCodes: [],
};
}
//# sourceMappingURL=astro2tsx.js.map

View File

@@ -1,11 +0,0 @@
import type { AttributeNode, Point } from '@astrojs/compiler';
import { Position as LSPPosition } from '@volar/language-server';
/**
* Transform a Point from the Astro compiler to an LSP Position
*/
export declare function PointToPosition(point: Point): LSPPosition;
type WithRequired<T, K extends keyof T> = T & {
[P in K]-?: T[P];
};
export type AttributeNodeWithPosition = WithRequired<AttributeNode, 'position'>;
export {};

View File

@@ -1,12 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.PointToPosition = PointToPosition;
const language_server_1 = require("@volar/language-server");
/**
* Transform a Point from the Astro compiler to an LSP Position
*/
function PointToPosition(point) {
// Columns and lines are 0-based in LSP, but the compiler's Point are 1 based.
return language_server_1.Position.create(point.line - 1, point.column - 1);
}
//# sourceMappingURL=compilerUtils.js.map

View File

@@ -1,38 +0,0 @@
import { type CodeMapping, type LanguagePlugin, type VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';
export declare const SUPPORTED_FRONTMATTER_EXTENSIONS: {
md: string;
mdx: string;
mdoc: string;
};
export declare const SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS: string[];
export declare const frontmatterRE: RegExp;
export type CollectionConfig = {
reload: (folders: {
uri: string;
}[]) => void;
configs: {
folder: URI;
config: CollectionConfigInstance;
}[];
};
export type CollectionConfigInstance = {
collections: {
hasSchema: boolean;
name: string;
}[];
entries: Record<string, string>;
};
export declare function getFrontmatterLanguagePlugin(collectionConfig: CollectionConfig): LanguagePlugin<URI, FrontmatterHolder>;
export declare class FrontmatterHolder implements VirtualCode {
fileName: string;
languageId: string;
snapshot: ts.IScriptSnapshot;
collection: string | undefined;
id: string;
mappings: CodeMapping[];
embeddedCodes: VirtualCode[];
hasFrontmatter: boolean;
constructor(fileName: string, languageId: string, snapshot: ts.IScriptSnapshot, collection: string | undefined);
}

View File

@@ -1,119 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.FrontmatterHolder = exports.frontmatterRE = exports.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS = exports.SUPPORTED_FRONTMATTER_EXTENSIONS = void 0;
exports.getFrontmatterLanguagePlugin = getFrontmatterLanguagePlugin;
const yaml2ts_1 = require("@astrojs/yaml2ts");
const language_core_1 = require("@volar/language-core");
exports.SUPPORTED_FRONTMATTER_EXTENSIONS = { md: 'markdown', mdx: 'mdx', mdoc: 'markdoc' };
exports.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS = Object.keys(exports.SUPPORTED_FRONTMATTER_EXTENSIONS);
const SUPPORTED_FRONTMATTER_EXTENSIONS_VALUES = Object.values(exports.SUPPORTED_FRONTMATTER_EXTENSIONS);
exports.frontmatterRE = /^---(.*?)^---/ms;
function getCollectionName(collectionConfig, fileURI) {
for (const collection of collectionConfig.configs) {
if (collection.config.entries[fileURI]) {
return collection.config.entries[fileURI];
}
}
}
function getFrontmatterLanguagePlugin(collectionConfig) {
return {
getLanguageId(scriptId) {
const fileType = exports.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS.find((ext) => scriptId.path.endsWith(`.${ext}`));
if (fileType) {
return exports.SUPPORTED_FRONTMATTER_EXTENSIONS[fileType];
}
},
createVirtualCode(scriptId, languageId, snapshot) {
if (SUPPORTED_FRONTMATTER_EXTENSIONS_VALUES.includes(languageId)) {
return new FrontmatterHolder(scriptId.fsPath.replace(/\\/g, '/'), languageId, snapshot, getCollectionName(collectionConfig,
// The scriptId here is encoded and somewhat normalized, as such we can't use it directly to compare with
// the file URLs in the collection config entries that Astro generates.
decodeURIComponent(scriptId.toString()).toLowerCase()));
}
},
typescript: {
extraFileExtensions: exports.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS.map((ext) => ({
extension: ext,
isMixedContent: true,
scriptKind: 7,
})),
getServiceScript(astroCode) {
for (const code of (0, language_core_1.forEachEmbeddedCode)(astroCode)) {
if (code.id === yaml2ts_1.VIRTUAL_CODE_ID) {
return {
code,
extension: '.ts',
scriptKind: 3,
};
}
}
return undefined;
},
},
};
}
class FrontmatterHolder {
constructor(fileName, languageId, snapshot, collection) {
this.fileName = fileName;
this.languageId = languageId;
this.snapshot = snapshot;
this.collection = collection;
this.id = 'frontmatter-holder';
this.hasFrontmatter = false;
this.mappings = [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [this.snapshot.getLength()],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: true,
},
},
];
this.embeddedCodes = [];
this.snapshot = snapshot;
// If the file is not part of a collection, we don't need to do anything
if (!this.collection) {
return;
}
const frontmatterContent = exports.frontmatterRE
.exec(this.snapshot.getText(0, this.snapshot.getLength()))?.[0]
.replaceAll('---', ' ') ?? '';
this.hasFrontmatter = frontmatterContent.length > 0;
this.embeddedCodes.push({
id: `yaml_frontmatter_${this.collection}`,
languageId: 'yaml',
snapshot: {
getText: (start, end) => frontmatterContent.substring(start, end),
getLength: () => frontmatterContent.length,
getChangeRange: () => undefined,
},
mappings: [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [frontmatterContent.length],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
},
],
});
if (this.hasFrontmatter) {
const yaml2tsResult = (0, yaml2ts_1.yaml2ts)(frontmatterContent, this.collection);
this.embeddedCodes.push(yaml2tsResult.virtualCode);
}
}
}
exports.FrontmatterHolder = FrontmatterHolder;
//# sourceMappingURL=frontmatterHolders.js.map

View File

@@ -1,23 +0,0 @@
import type { DiagnosticMessage } from '@astrojs/compiler/types';
import { type CodeMapping, type LanguagePlugin, type VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import type { HTMLDocument } from 'vscode-html-languageservice';
import type { URI } from 'vscode-uri';
import type { PackageInfo } from '../importPackage.js';
import type { AstroMetadata } from './parseAstro';
export declare function addAstroTypes(astroInstall: PackageInfo | undefined, ts: typeof import('typescript'), host: ts.LanguageServiceHost): void;
export declare function getAstroLanguagePlugin(): LanguagePlugin<URI, AstroVirtualCode>;
export declare class AstroVirtualCode implements VirtualCode {
fileName: string;
snapshot: ts.IScriptSnapshot;
id: string;
languageId: string;
mappings: CodeMapping[];
embeddedCodes: VirtualCode[];
astroMeta: AstroMetadata;
compilerDiagnostics: DiagnosticMessage[];
htmlDocument: HTMLDocument;
codegenStacks: never[];
constructor(fileName: string, snapshot: ts.IScriptSnapshot);
get hasCompilationErrors(): boolean;
}

View File

@@ -1,175 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.AstroVirtualCode = void 0;
exports.addAstroTypes = addAstroTypes;
exports.getAstroLanguagePlugin = getAstroLanguagePlugin;
const path = __importStar(require("node:path"));
const language_core_1 = require("@volar/language-core");
const utils_js_1 = require("../utils.js");
const astro2tsx_1 = require("./astro2tsx");
const parseAstro_1 = require("./parseAstro");
const parseCSS_1 = require("./parseCSS");
const parseHTML_1 = require("./parseHTML");
const parseJS_js_1 = require("./parseJS.js");
const decoratedHosts = new WeakSet();
function addAstroTypes(astroInstall, ts, host) {
if (decoratedHosts.has(host)) {
return;
}
decoratedHosts.add(host);
const getScriptFileNames = host.getScriptFileNames.bind(host);
const getCompilationSettings = host.getCompilationSettings.bind(host);
host.getScriptFileNames = () => {
const languageServerTypesDirectory = (0, utils_js_1.getLanguageServerTypesDir)(ts);
const fileNames = getScriptFileNames();
const addedFileNames = [];
if (astroInstall) {
addedFileNames.push(...['./env.d.ts', './astro-jsx.d.ts'].map((filePath) => ts.sys.resolvePath(path.resolve(astroInstall.directory, filePath))));
// If Astro version is < 4.0.8, add jsx-runtime-augment.d.ts to the files to fake `JSX` being available from "astro/jsx-runtime".
// TODO: Remove this once a majority of users are on Astro 4.0.8+, erika - 2023-12-28
if (astroInstall.version.major < 4 ||
(astroInstall.version.major === 4 &&
astroInstall.version.minor === 0 &&
astroInstall.version.patch < 8)) {
addedFileNames.push(...['./jsx-runtime-augment.d.ts'].map((filePath) => ts.sys.resolvePath(path.resolve(languageServerTypesDirectory, filePath))));
}
}
else {
// If we don't have an Astro installation, add the fallback types from the language server.
// See the README in packages/language-server/types for more information.
addedFileNames.push(...['./env.d.ts', './astro-jsx.d.ts', './jsx-runtime-fallback.d.ts'].map((f) => ts.sys.resolvePath(path.resolve(languageServerTypesDirectory, f))));
}
return [...fileNames, ...addedFileNames];
};
host.getCompilationSettings = () => {
const baseCompilationSettings = getCompilationSettings();
return {
...baseCompilationSettings,
module: ts.ModuleKind.ESNext ?? 99,
target: ts.ScriptTarget.ESNext ?? 99,
jsx: ts.JsxEmit.Preserve ?? 1,
resolveJsonModule: true,
allowJs: true, // Needed for inline scripts, which are virtual .js files
isolatedModules: true,
moduleResolution: baseCompilationSettings.moduleResolution === ts.ModuleResolutionKind.Classic ||
!baseCompilationSettings.moduleResolution
? ts.ModuleResolutionKind.Node10
: baseCompilationSettings.moduleResolution,
};
};
}
function getAstroLanguagePlugin() {
return {
getLanguageId(uri) {
if (uri.path.endsWith('.astro')) {
return 'astro';
}
},
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'astro') {
const fileName = uri.fsPath.replace(/\\/g, '/');
return new AstroVirtualCode(fileName, snapshot);
}
},
typescript: {
extraFileExtensions: [{ extension: 'astro', isMixedContent: true, scriptKind: 7 }],
getServiceScript(astroCode) {
for (const code of (0, language_core_1.forEachEmbeddedCode)(astroCode)) {
if (code.id === 'tsx') {
return {
code,
extension: '.tsx',
scriptKind: 4,
};
}
}
return undefined;
},
getExtraServiceScripts(fileName, astroCode) {
const result = [];
for (const code of (0, language_core_1.forEachEmbeddedCode)(astroCode)) {
if (code.id.endsWith('.mjs') || code.id.endsWith('.mts')) {
const fileExtension = code.id.endsWith('.mjs') ? '.mjs' : '.mts';
result.push({
fileName: fileName + '.' + code.id,
code,
extension: fileExtension,
scriptKind: fileExtension === '.mjs'
? 1
: 3,
});
}
}
return result;
},
},
};
}
class AstroVirtualCode {
constructor(fileName, snapshot) {
this.fileName = fileName;
this.snapshot = snapshot;
this.id = 'root';
this.languageId = 'astro';
this.codegenStacks = [];
this.mappings = [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [this.snapshot.getLength()],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: true,
},
},
];
const tsx = (0, astro2tsx_1.astro2tsx)(this.snapshot.getText(0, this.snapshot.getLength()), this.fileName);
const astroMetadata = (0, parseAstro_1.getAstroMetadata)(this.fileName, this.snapshot.getText(0, this.snapshot.getLength()));
const { htmlDocument, virtualCode: htmlVirtualCode } = (0, parseHTML_1.parseHTML)(this.snapshot, astroMetadata.frontmatter.status === 'closed'
? astroMetadata.frontmatter.position.end.offset
: 0);
this.htmlDocument = htmlDocument;
htmlVirtualCode.embeddedCodes = [
...(0, parseCSS_1.extractStylesheets)(tsx.ranges.styles),
...(0, parseJS_js_1.extractScriptTags)(tsx.ranges.scripts),
];
this.astroMeta = { ...astroMetadata, tsxRanges: tsx.ranges };
this.compilerDiagnostics = [...tsx.diagnostics, ...astroMetadata.diagnostics];
this.embeddedCodes = [htmlVirtualCode, tsx.virtualCode];
}
get hasCompilationErrors() {
return (
// eslint-disable-next-line @typescript-eslint/no-unsafe-enum-comparison
this.compilerDiagnostics.filter((diag) => diag.severity === 1)
.length > 0);
}
}
exports.AstroVirtualCode = AstroVirtualCode;
//# sourceMappingURL=index.js.map

View File

@@ -1,27 +0,0 @@
import type { ParseOptions, ParseResult, Point } from '@astrojs/compiler/types';
import type { LSPTSXRanges } from './astro2tsx.js';
export type AstroMetadata = ParseResult & {
frontmatter: FrontmatterStatus;
tsxRanges: LSPTSXRanges;
};
export declare function getAstroMetadata(fileName: string, input: string, options?: ParseOptions): Omit<AstroMetadata, 'tsxRanges'>;
interface FrontmatterOpen {
status: 'open';
position: {
start: Point;
end: undefined;
};
}
interface FrontmatterClosed {
status: 'closed';
position: {
start: Point;
end: Point;
};
}
interface FrontmatterNull {
status: 'doesnt-exist';
position: undefined;
}
export type FrontmatterStatus = FrontmatterOpen | FrontmatterClosed | FrontmatterNull;
export {};

View File

@@ -1,85 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getAstroMetadata = getAstroMetadata;
const sync_1 = require("@astrojs/compiler/sync");
function getAstroMetadata(fileName, input, options = { position: true }) {
const parseResult = safeParseAst(fileName, input, options);
return {
...parseResult,
frontmatter: getFrontmatterStatus(parseResult.ast, input),
};
}
function safeParseAst(fileName, input, parseOptions) {
try {
const parseResult = (0, sync_1.parse)(input, parseOptions);
return parseResult;
}
catch (e) {
console.error(`There was an error parsing ${fileName}'s AST. An empty AST will be returned instead to avoid breaking the server. Please create an issue: https://github.com/withastro/language-tools/issues\nError: ${e}.`);
return {
ast: {
type: 'root',
children: [],
},
diagnostics: [
{
code: 1000,
location: {
file: fileName,
line: 1,
column: 1,
length: input.length,
},
severity: 1,
text: `The Astro compiler encountered an unknown error while parsing this file's AST. Please create an issue with your code and the error shown in the server's logs: https://github.com/withastro/language-tools/issues`,
},
],
};
}
}
function getFrontmatterStatus(ast, text) {
if (!ast.children || (ast.children && ast.children.length === 0)) {
return {
status: 'doesnt-exist',
position: undefined,
};
}
if (ast.children[0].type === 'frontmatter') {
const frontmatter = ast.children[0];
if (frontmatter.position) {
if (frontmatter.position.end) {
// HACK: The compiler as of 1.5.5 always return an ending position, even if there's only a frontmatter opening
// This hack checks if the frontmatter's ending is the end of the file, and if so, checks if there's a `---`.
// If there's not, it means the compiler returned the EOF with an opened frontmatter
if (frontmatter.position.end.offset === text.length && !text.endsWith('---')) {
return {
status: 'open',
position: {
start: frontmatter.position.start,
end: undefined,
},
};
}
return {
status: 'closed',
position: {
start: frontmatter.position.start,
end: frontmatter.position.end,
},
};
}
return {
status: 'open',
position: {
start: frontmatter.position.start,
end: undefined,
},
};
}
}
return {
status: 'doesnt-exist',
position: undefined,
};
}
//# sourceMappingURL=parseAstro.js.map

View File

@@ -1,3 +0,0 @@
import type { TSXExtractedStyle } from '@astrojs/compiler/types';
import type { VirtualCode } from '@volar/language-core';
export declare function extractStylesheets(styles: TSXExtractedStyle[]): VirtualCode[];

View File

@@ -1,63 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractStylesheets = extractStylesheets;
const muggle_string_1 = require("muggle-string");
const buildMappings_js_1 = require("../buildMappings.js");
const SUPPORTED_LANGUAGES = ['css', 'scss', 'less'];
function isSupportedLanguage(lang) {
return SUPPORTED_LANGUAGES.includes(lang);
}
function extractStylesheets(styles) {
return mergeCSSContextsByLanguage(styles);
}
function mergeCSSContextsByLanguage(inlineStyles) {
const codes = {
css: [],
scss: [],
less: [],
};
for (const cssContext of inlineStyles) {
const currentCode = isSupportedLanguage(cssContext.lang) ? codes[cssContext.lang] : codes.css;
const isStyleAttribute = cssContext.type === 'style-attribute';
if (isStyleAttribute)
currentCode.push('__ { ');
currentCode.push([
cssContext.content,
undefined,
cssContext.position.start,
{
verification: false,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
]);
if (isStyleAttribute)
currentCode.push(' }\n');
}
let virtualCodes = [];
for (const lang of SUPPORTED_LANGUAGES) {
if (codes[lang].length) {
virtualCodes.push(createVirtualCodeForLanguage(codes[lang], lang));
}
}
return virtualCodes;
}
function createVirtualCodeForLanguage(code, lang) {
const mappings = (0, buildMappings_js_1.buildMappings)(code);
const text = (0, muggle_string_1.toString)(code);
return {
id: `style.${lang}`,
languageId: lang,
snapshot: {
getText: (start, end) => text.substring(start, end),
getLength: () => text.length,
getChangeRange: () => undefined,
},
embeddedCodes: [],
mappings,
};
}
//# sourceMappingURL=parseCSS.js.map

View File

@@ -1,11 +0,0 @@
import type { VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import * as html from 'vscode-html-languageservice';
export declare function parseHTML(snapshot: ts.IScriptSnapshot, frontmatterEnd: number): {
virtualCode: VirtualCode;
htmlDocument: html.HTMLDocument;
};
/**
* scan the text and remove any `>` or `<` that cause the tag to end short
*/
export declare function preprocessHTML(text: string, frontmatterEnd?: number): string;

View File

@@ -1,114 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.parseHTML = parseHTML;
exports.preprocessHTML = preprocessHTML;
const html = __importStar(require("vscode-html-languageservice"));
const utils_1 = require("../plugins/utils");
const htmlLs = html.getLanguageService();
function parseHTML(snapshot, frontmatterEnd) {
const htmlContent = preprocessHTML(snapshot.getText(0, snapshot.getLength()), frontmatterEnd);
return {
virtualCode: getHTMLVirtualCode(htmlContent),
htmlDocument: getHTMLDocument(htmlContent),
};
}
const createScanner = htmlLs.createScanner;
/**
* scan the text and remove any `>` or `<` that cause the tag to end short
*/
function preprocessHTML(text, frontmatterEnd) {
let content = text.split('').fill(' ', 0, frontmatterEnd).join('');
let scanner = createScanner(content);
let token = scanner.scan();
let currentStartTagStart = null;
while (token !== html.TokenType.EOS) {
const offset = scanner.getTokenOffset();
if (token === html.TokenType.StartTagOpen) {
currentStartTagStart = offset;
}
if (token === html.TokenType.StartTagClose) {
if (shouldBlankStartOrEndTagLike(offset)) {
blankStartOrEndTagLike(offset);
}
else {
currentStartTagStart = null;
}
}
if (token === html.TokenType.StartTagSelfClose) {
currentStartTagStart = null;
}
// <Foo checked={a < 1}>
// https://github.com/microsoft/vscode-html-languageservice/blob/71806ef57be07e1068ee40900ef8b0899c80e68a/src/parser/htmlScanner.ts#L327
if (token === html.TokenType.Unknown &&
scanner.getScannerState() === html.ScannerState.WithinTag &&
scanner.getTokenText() === '<' &&
shouldBlankStartOrEndTagLike(offset)) {
blankStartOrEndTagLike(offset);
}
// TODO: Handle TypeScript generics inside expressions / Use the compiler to parse HTML instead?
token = scanner.scan();
}
return content;
function shouldBlankStartOrEndTagLike(offset) {
// not null rather than falsy, otherwise it won't work on first tag(0)
return (currentStartTagStart !== null && (0, utils_1.isInsideExpression)(content, currentStartTagStart, offset));
}
function blankStartOrEndTagLike(offset, state) {
content = content.substring(0, offset) + ' ' + content.substring(offset + 1);
scanner = createScanner(content, offset, state ?? html.ScannerState.WithinTag);
}
}
function getHTMLVirtualCode(preprocessedHTML) {
return {
id: `html`,
languageId: 'html',
snapshot: {
getText: (start, end) => preprocessedHTML.substring(start, end),
getLength: () => preprocessedHTML.length,
getChangeRange: () => undefined,
},
mappings: [
{
sourceOffsets: [0],
generatedOffsets: [0],
lengths: [preprocessedHTML.length],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
},
],
embeddedCodes: [],
};
}
function getHTMLDocument(preprocessedHTML) {
return htmlLs.parseHTMLDocument({ getText: () => preprocessedHTML });
}
//# sourceMappingURL=parseHTML.js.map

View File

@@ -1,3 +0,0 @@
import type { TSXExtractedScript } from '@astrojs/compiler/types';
import type { VirtualCode } from '@volar/language-core';
export declare function extractScriptTags(scripts: TSXExtractedScript[]): VirtualCode[];

View File

@@ -1,130 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.extractScriptTags = extractScriptTags;
const muggle_string_1 = require("muggle-string");
const buildMappings_1 = require("../buildMappings");
function extractScriptTags(scripts) {
const embeddedJSCodes = [];
const moduleScripts = scripts
.filter((script) => script.type === 'module' || script.type === 'processed-module')
.map(moduleScriptToVirtualCode);
const inlineScripts = scripts
.filter((script) =>
// TODO: Change this at some point so that unknown scripts are not included
// We can't guarantee that they are JavaScript, so we shouldn't treat them as such, even if it might work in some cases
// Perhaps we should make it so that the user has to specify the language of the script if it's not a known type (ex: lang="js"), not sure.
script.type === 'event-attribute' || script.type === 'inline' || script.type === 'unknown')
.sort((a, b) => a.position.start - b.position.start);
embeddedJSCodes.push(...moduleScripts);
const mergedJSContext = mergeJSContexts(inlineScripts);
if (mergedJSContext) {
embeddedJSCodes.push(mergedJSContext);
}
const JSONScripts = scripts
.filter((script) => script.type === 'json')
.map(jsonScriptToVirtualCode);
embeddedJSCodes.push(...JSONScripts);
return embeddedJSCodes;
}
function moduleScriptToVirtualCode(script, index) {
let extension = 'mts';
let languageId = 'typescript';
if (script.type === 'module') {
extension = 'mjs';
languageId = 'javascript';
}
return {
id: `${index}.${extension}`,
languageId,
snapshot: {
getText: (start, end) => script.content.substring(start, end),
getLength: () => script.content.length,
getChangeRange: () => undefined,
},
mappings: [
{
sourceOffsets: [script.position.start],
generatedOffsets: [0],
lengths: [script.content.length],
data: {
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
},
],
embeddedCodes: [],
};
}
function jsonScriptToVirtualCode(script, index) {
return {
id: `${index}.json`,
languageId: 'json',
snapshot: {
getText: (start, end) => script.content.substring(start, end),
getLength: () => script.content.length,
getChangeRange: () => undefined,
},
mappings: [
{
sourceOffsets: [script.position.start],
generatedOffsets: [0],
lengths: [script.content.length],
// TODO: Support JSON features
data: {
verification: false,
completion: false,
semantic: false,
navigation: false,
structure: false,
format: false,
},
},
],
embeddedCodes: [],
};
}
/**
* Merge all the inline and non-hoisted scripts into a single `.mjs` file
*/
function mergeJSContexts(inlineScripts) {
if (inlineScripts.length === 0) {
return undefined;
}
const codes = [];
for (const javascriptContext of inlineScripts) {
codes.push([
// Add a semicolon to the end of the event attribute to attempt to prevent errors from spreading to the rest of the document
// This is not perfect, but it's better than nothing
// See: https://github.com/microsoft/vscode/blob/e8e04769ec817a3374c3eaa26a08d3ae491820d5/extensions/html-language-features/server/src/modes/embeddedSupport.ts#L192
javascriptContext.content + ';',
undefined,
javascriptContext.position.start,
{
verification: true,
completion: true,
semantic: true,
navigation: true,
structure: true,
format: false,
},
]);
}
const mappings = (0, buildMappings_1.buildMappings)(codes);
const text = (0, muggle_string_1.toString)(codes);
return {
id: 'inline.mjs',
languageId: 'javascript',
snapshot: {
getText: (start, end) => text.substring(start, end),
getLength: () => text.length,
getChangeRange: () => undefined,
},
embeddedCodes: [],
mappings,
};
}
//# sourceMappingURL=parseJS.js.map

View File

@@ -1,15 +0,0 @@
import { type CodeInformation, type LanguagePlugin, type Mapping, type VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';
export declare function getSvelteLanguagePlugin(): LanguagePlugin<URI, SvelteVirtualCode>;
declare class SvelteVirtualCode implements VirtualCode {
fileName: string;
snapshot: ts.IScriptSnapshot;
id: string;
languageId: string;
mappings: Mapping<CodeInformation>[];
embeddedCodes: VirtualCode[];
codegenStacks: never[];
constructor(fileName: string, snapshot: ts.IScriptSnapshot);
}
export {};

View File

@@ -1,47 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSvelteLanguagePlugin = getSvelteLanguagePlugin;
const language_core_1 = require("@volar/language-core");
const utils_js_1 = require("./utils.js");
function getSvelteLanguagePlugin() {
return {
getLanguageId(uri) {
if (uri.path.endsWith('.svelte')) {
return 'svelte';
}
},
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'svelte') {
const fileName = uri.fsPath.replace(/\\/g, '/');
return new SvelteVirtualCode(fileName, snapshot);
}
},
typescript: {
extraFileExtensions: [{ extension: 'svelte', isMixedContent: true, scriptKind: 7 }],
getServiceScript(svelteCode) {
for (const code of (0, language_core_1.forEachEmbeddedCode)(svelteCode)) {
if (code.id === 'tsx') {
return {
code,
extension: '.tsx',
scriptKind: 4,
};
}
}
},
},
};
}
class SvelteVirtualCode {
constructor(fileName, snapshot) {
this.fileName = fileName;
this.snapshot = snapshot;
this.id = 'root';
this.languageId = 'svelte';
this.codegenStacks = [];
this.mappings = [];
this.embeddedCodes = [];
this.embeddedCodes.push((0, utils_js_1.framework2tsx)(this.fileName, this.snapshot.getText(0, this.snapshot.getLength()), 'svelte'));
}
}
//# sourceMappingURL=svelte.js.map

View File

@@ -1,4 +0,0 @@
import type { VirtualCode } from '@volar/language-core';
export declare function framework2tsx(filePath: string, sourceCode: string, framework: 'vue' | 'svelte'): VirtualCode;
export declare function classNameFromFilename(filename: string): string;
export declare function patchTSX(code: string, filePath: string): string;

View File

@@ -1,73 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.framework2tsx = framework2tsx;
exports.classNameFromFilename = classNameFromFilename;
exports.patchTSX = patchTSX;
const vscode_uri_1 = require("vscode-uri");
const importPackage_1 = require("../importPackage");
function framework2tsx(filePath, sourceCode, framework) {
const integrationEditorEntrypoint = framework === 'vue' ? (0, importPackage_1.importVueIntegration)(filePath) : (0, importPackage_1.importSvelteIntegration)(filePath);
if (!integrationEditorEntrypoint) {
const EMPTY_FILE = '';
return getVirtualCode(EMPTY_FILE);
}
const className = classNameFromFilename(filePath);
const tsx = patchTSX(integrationEditorEntrypoint.toTSX(sourceCode, className), filePath);
return getVirtualCode(tsx);
function getVirtualCode(content) {
return {
id: 'tsx',
languageId: 'typescript',
snapshot: {
getText: (start, end) => content.substring(start, end),
getLength: () => content.length,
getChangeRange: () => undefined,
},
mappings: [],
embeddedCodes: [],
};
}
}
/**
* Transform a string into PascalCase
*/
function toPascalCase(string) {
return `${string}`
.replace(new RegExp(/[-_]+/, 'g'), ' ')
.replace(new RegExp(/[^\w\s]/, 'g'), '')
.replace(new RegExp(/\s+(.)(\w*)/, 'g'), ($1, $2, $3) => `${$2.toUpperCase() + $3.toLowerCase()}`)
.replace(new RegExp(/\w/), (s) => s.toUpperCase());
}
function classNameFromFilename(filename) {
const url = vscode_uri_1.URI.parse(filename);
const withoutExtensions = vscode_uri_1.Utils.basename(url).slice(0, -vscode_uri_1.Utils.extname(url).length);
const withoutInvalidCharacters = withoutExtensions
.split('')
// Although "-" is invalid, we leave it in, pascal-case-handling will throw it out later
.filter((char) => /[\w$-]/.test(char))
.join('');
const firstValidCharIdx = withoutInvalidCharacters
.split('')
// Although _ and $ are valid first characters for classes, they are invalid first characters
// for tag names. For a better import autocompletion experience, we therefore throw them out.
.findIndex((char) => /[A-Za-z]/.test(char));
const withoutLeadingInvalidCharacters = withoutInvalidCharacters.substring(firstValidCharIdx);
const inPascalCase = toPascalCase(withoutLeadingInvalidCharacters);
const finalName = firstValidCharIdx === -1 ? `A${inPascalCase}` : inPascalCase;
return finalName;
}
// TODO: Patch the upstream packages with these changes
function patchTSX(code, filePath) {
const basename = filePath.split('/').pop();
const isDynamic = basename.startsWith('[') && basename.endsWith(']');
return code.replace(/\b(\S*)__AstroComponent_/g, (fullMatch, m1) => {
// If we don't have a match here, it usually means the file has a weird name that couldn't be expressed with valid identifier characters
if (!m1) {
if (basename === '404')
return 'FourOhFour';
return fullMatch;
}
return isDynamic ? `_${m1}_` : m1[0].toUpperCase() + m1.slice(1);
});
}
//# sourceMappingURL=utils.js.map

View File

@@ -1,15 +0,0 @@
import { type CodeInformation, type LanguagePlugin, type Mapping, type VirtualCode } from '@volar/language-core';
import type ts from 'typescript';
import type { URI } from 'vscode-uri';
export declare function getVueLanguagePlugin(): LanguagePlugin<URI, VueVirtualCode>;
declare class VueVirtualCode implements VirtualCode {
fileName: string;
snapshot: ts.IScriptSnapshot;
id: string;
languageId: string;
mappings: Mapping<CodeInformation>[];
embeddedCodes: VirtualCode[];
codegenStacks: never[];
constructor(fileName: string, snapshot: ts.IScriptSnapshot);
}
export {};

View File

@@ -1,47 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getVueLanguagePlugin = getVueLanguagePlugin;
const language_core_1 = require("@volar/language-core");
const utils_js_1 = require("./utils.js");
function getVueLanguagePlugin() {
return {
getLanguageId(uri) {
if (uri.path.endsWith('.vue')) {
return 'vue';
}
},
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'vue') {
const fileName = uri.fsPath.replace(/\\/g, '/');
return new VueVirtualCode(fileName, snapshot);
}
},
typescript: {
extraFileExtensions: [{ extension: 'vue', isMixedContent: true, scriptKind: 7 }],
getServiceScript(vueCode) {
for (const code of (0, language_core_1.forEachEmbeddedCode)(vueCode)) {
if (code.id === 'tsx') {
return {
code,
extension: '.tsx',
scriptKind: 4,
};
}
}
},
},
};
}
class VueVirtualCode {
constructor(fileName, snapshot) {
this.fileName = fileName;
this.snapshot = snapshot;
this.id = 'root';
this.languageId = 'vue';
this.codegenStacks = [];
this.mappings = [];
this.embeddedCodes = [];
this.embeddedCodes.push((0, utils_js_1.framework2tsx)(this.fileName, this.snapshot.getText(0, this.snapshot.getLength()), 'vue'));
}
}
//# sourceMappingURL=vue.js.map

View File

@@ -1,26 +0,0 @@
import type * as svelte from '@astrojs/svelte/dist/editor.cjs';
import type * as vue from '@astrojs/vue/dist/editor.cjs';
import type * as prettier from 'prettier';
type PackageVersion = {
full: string;
major: number;
minor: number;
patch: number;
};
export declare function setIsTrusted(_isTrusted: boolean): void;
export type PackageInfo = {
entrypoint: string;
directory: string;
version: PackageVersion;
};
/**
* Get the path of a package's directory from the paths in `fromPath`, if `root` is set to false, it will return the path of the package's entry point
*/
export declare function getPackageInfo(packageName: string, fromPath: string[]): PackageInfo | undefined;
export declare function importSvelteIntegration(fromPath: string): typeof svelte | undefined;
export declare function importVueIntegration(fromPath: string): typeof vue | undefined;
export declare function importPrettier(fromPath: string): typeof prettier | undefined;
export declare function getPrettierPluginPath(fromPath: string): string | undefined;
export declare function getWorkspacePnpPath(workspacePath: string): string | null;
export declare function parsePackageVersion(version: string): PackageVersion;
export {};

View File

@@ -1,106 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.setIsTrusted = setIsTrusted;
exports.getPackageInfo = getPackageInfo;
exports.importSvelteIntegration = importSvelteIntegration;
exports.importVueIntegration = importVueIntegration;
exports.importPrettier = importPrettier;
exports.getPrettierPluginPath = getPrettierPluginPath;
exports.getWorkspacePnpPath = getWorkspacePnpPath;
exports.parsePackageVersion = parsePackageVersion;
const node_path_1 = require("node:path");
let isTrusted = true;
function setIsTrusted(_isTrusted) {
isTrusted = _isTrusted;
}
/**
* Get the path of a package's directory from the paths in `fromPath`, if `root` is set to false, it will return the path of the package's entry point
*/
function getPackageInfo(packageName, fromPath) {
const paths = [];
if (isTrusted) {
paths.unshift(...fromPath);
}
try {
const packageJSON = require.resolve(packageName + '/package.json', { paths });
return {
directory: (0, node_path_1.dirname)(packageJSON),
entrypoint: require.resolve(packageName, { paths }),
version: parsePackageVersion(require(packageJSON).version),
};
}
catch {
return undefined;
}
}
function importEditorIntegration(packageName, fromPath) {
const pkgPath = getPackageInfo(packageName, [fromPath])?.directory;
if (pkgPath) {
try {
const main = (0, node_path_1.resolve)(pkgPath, 'dist', 'editor.cjs');
return require(main);
}
catch (e) {
console.error(`Couldn't load editor module from ${pkgPath}. Make sure you're using at least version v0.2.1 of the corresponding integration. Reason: ${e}`);
return undefined;
}
}
else {
console.info(`Couldn't find package ${packageName} (searching from ${fromPath}). Make sure it's installed. If you believe this to be an error, please open an issue.`);
}
return undefined;
}
function importSvelteIntegration(fromPath) {
return importEditorIntegration('@astrojs/svelte', fromPath);
}
function importVueIntegration(fromPath) {
return importEditorIntegration('@astrojs/vue', fromPath);
}
function importPrettier(fromPath) {
let prettierPkg = getPackageInfo('prettier', [fromPath, __dirname]);
if (!prettierPkg) {
return undefined;
}
if (prettierPkg.version.major < 3) {
console.error(`Prettier version ${prettierPkg.version.full} from ${prettierPkg.directory} is not supported, please update to at least version 3.0.0. Falling back to bundled version to ensure formatting works correctly.`);
prettierPkg = getPackageInfo('prettier', [__dirname]);
if (!prettierPkg) {
return undefined;
}
}
return require(prettierPkg.entrypoint);
}
function getPrettierPluginPath(fromPath) {
const prettierPluginPath = getPackageInfo('prettier-plugin-astro', [
fromPath,
__dirname,
])?.entrypoint;
if (!prettierPluginPath) {
return undefined;
}
return prettierPluginPath;
}
function getWorkspacePnpPath(workspacePath) {
try {
const possiblePath = (0, node_path_1.resolve)(workspacePath, '.pnp.cjs');
require.resolve(possiblePath);
return possiblePath;
}
catch {
return null;
}
}
function parsePackageVersion(version) {
let [major, minor, patch] = version.split('.');
if (patch.includes('-')) {
const patchParts = patch.split('-');
patch = patchParts[0];
}
return {
full: version,
major: Number(major),
minor: Number(minor),
patch: Number(patch),
};
}
//# sourceMappingURL=importPackage.js.map

View File

@@ -1 +0,0 @@
export { AstroCheck, CheckResult, Diagnostic, DiagnosticSeverity } from './check.js';

View File

@@ -1,8 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DiagnosticSeverity = exports.Diagnostic = exports.AstroCheck = void 0;
var check_js_1 = require("./check.js");
Object.defineProperty(exports, "AstroCheck", { enumerable: true, get: function () { return check_js_1.AstroCheck; } });
Object.defineProperty(exports, "Diagnostic", { enumerable: true, get: function () { return check_js_1.Diagnostic; } });
Object.defineProperty(exports, "DiagnosticSeverity", { enumerable: true, get: function () { return check_js_1.DiagnosticSeverity; } });
//# sourceMappingURL=index.js.map

View File

@@ -1,5 +0,0 @@
import { type Connection, type LanguagePlugin } from '@volar/language-server/node';
import { URI } from 'vscode-uri';
import { type CollectionConfig } from './core/frontmatterHolders.js';
export declare function getLanguagePlugins(collectionConfig: CollectionConfig): LanguagePlugin<URI, import("@volar/language-server/node").VirtualCode>[];
export declare function getLanguageServicePlugins(connection: Connection, ts: typeof import('typescript'), collectionConfig: CollectionConfig): import("@volar/language-server/node").LanguageServicePlugin<any>[];

View File

@@ -1,116 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLanguagePlugins = getLanguagePlugins;
exports.getLanguageServicePlugins = getLanguageServicePlugins;
const node_1 = require("@volar/language-server/node");
const vscode_uri_1 = require("vscode-uri");
const core_1 = require("./core");
const svelte_js_1 = require("./core/svelte.js");
const vue_js_1 = require("./core/vue.js");
const importPackage_js_1 = require("./importPackage.js");
// Services
const volar_service_css_1 = require("volar-service-css");
const volar_service_emmet_1 = require("volar-service-emmet");
const volar_service_prettier_1 = require("volar-service-prettier");
const volar_service_typescript_twoslash_queries_1 = require("volar-service-typescript-twoslash-queries");
const frontmatterHolders_js_1 = require("./core/frontmatterHolders.js");
const astro_js_1 = require("./plugins/astro.js");
const html_js_1 = require("./plugins/html.js");
const index_js_1 = require("./plugins/typescript-addons/index.js");
const index_js_2 = require("./plugins/typescript/index.js");
const yaml_js_1 = require("./plugins/yaml.js");
function getLanguagePlugins(collectionConfig) {
const languagePlugins = [
(0, core_1.getAstroLanguagePlugin)(),
(0, vue_js_1.getVueLanguagePlugin)(),
(0, svelte_js_1.getSvelteLanguagePlugin)(),
(0, frontmatterHolders_js_1.getFrontmatterLanguagePlugin)(collectionConfig),
];
return languagePlugins;
}
function getLanguageServicePlugins(connection, ts, collectionConfig) {
const LanguageServicePlugins = [
(0, html_js_1.create)(),
(0, volar_service_css_1.create)(),
(0, volar_service_emmet_1.create)(),
...(0, index_js_2.create)(ts),
(0, volar_service_typescript_twoslash_queries_1.create)(ts),
(0, index_js_1.create)(),
(0, astro_js_1.create)(ts),
getPrettierService(),
(0, yaml_js_1.create)(collectionConfig),
];
return LanguageServicePlugins;
function getPrettierService() {
let prettier;
let prettierPluginPath;
let hasShownNotification = false;
return (0, volar_service_prettier_1.create)((context) => {
for (const workspaceFolder of context.env.workspaceFolders) {
if (workspaceFolder.scheme === 'file') {
prettier = (0, importPackage_js_1.importPrettier)(workspaceFolder.fsPath);
prettierPluginPath = (0, importPackage_js_1.getPrettierPluginPath)(workspaceFolder.fsPath);
if ((!prettier || !prettierPluginPath) && !hasShownNotification) {
connection.sendNotification(node_1.ShowMessageNotification.type, {
message: "Couldn't load `prettier` or `prettier-plugin-astro`. Formatting will not work. Please make sure those two packages are installed into your project and restart the language server.",
type: node_1.MessageType.Warning,
});
hasShownNotification = true;
}
return prettier;
}
}
}, {
documentSelector: ['astro'],
getFormattingOptions: async (prettierInstance, document, formatOptions, context) => {
const uri = vscode_uri_1.URI.parse(document.uri);
const documentUri = context.decodeEmbeddedDocumentUri(uri)?.[0] ?? uri;
const filePath = documentUri.fsPath;
if (!filePath) {
return {};
}
let configOptions = null;
try {
configOptions = await prettierInstance.resolveConfig(filePath, {
// This seems to be broken since Prettier 3, and it'll always use its cumbersome cache. Hopefully it works one day.
useCache: false,
editorconfig: true,
});
}
catch (e) {
connection.sendNotification(node_1.ShowMessageNotification.type, {
message: `Failed to load Prettier config.\n\nError:\n${e}`,
type: node_1.MessageType.Warning,
});
console.error('Failed to load Prettier config.', e);
}
const editorOptions = await context.env.getConfiguration?.('prettier', document.uri);
// Return a config with the following cascade:
// - Prettier config file should always win if it exists, if it doesn't:
// - Prettier config from the VS Code extension is used, if it doesn't exist:
// - Use the editor's basic configuration settings
const resolvedConfig = {
filepath: filePath,
tabWidth: formatOptions.tabSize,
useTabs: !formatOptions.insertSpaces,
...editorOptions,
...configOptions,
};
return {
...resolvedConfig,
plugins: [...(await getAstroPrettierPlugin()), ...(resolvedConfig.plugins ?? [])],
parser: 'astro',
};
async function getAstroPrettierPlugin() {
if (!prettier || !prettierPluginPath) {
return [];
}
const hasPluginLoadedAlready = (await prettier.getSupportInfo()).languages.some((l) => l.name === 'astro') ||
resolvedConfig.plugins?.includes('prettier-plugin-astro'); // getSupportInfo doesn't seems to work very well in Prettier 3 for plugins
return hasPluginLoadedAlready ? [] : [prettierPluginPath];
}
},
});
}
}
//# sourceMappingURL=languageServerPlugin.js.map

View File

@@ -1 +0,0 @@
export {};

View File

@@ -1,102 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const node_1 = require("@volar/language-server/node");
const vscode_uri_1 = require("vscode-uri");
const frontmatterHolders_js_1 = require("./core/frontmatterHolders.js");
const index_js_1 = require("./core/index.js");
const languageServerPlugin_js_1 = require("./languageServerPlugin.js");
const utils_js_1 = require("./utils.js");
const connection = (0, node_1.createConnection)();
const server = (0, node_1.createServer)(connection);
let contentIntellisenseEnabled = false;
connection.listen();
connection.onInitialize((params) => {
const tsdk = params.initializationOptions?.typescript?.tsdk;
if (!tsdk) {
throw new Error('The `typescript.tsdk` init option is required. It should point to a directory containing a `typescript.js` or `tsserverlibrary.js` file, such as `node_modules/typescript/lib`.');
}
const { typescript, diagnosticMessages } = (0, node_1.loadTsdkByPath)(tsdk, params.locale);
contentIntellisenseEnabled = params.initializationOptions?.contentIntellisense ?? false;
const collectionConfig = {
reload(folders) {
this.configs = loadCollectionConfig(folders);
},
configs: contentIntellisenseEnabled
? loadCollectionConfig(
// The vast majority of clients support workspaceFolders, but sometimes some unusual environments like tests don't
params.workspaceFolders ?? (params.rootUri ? [{ uri: params.rootUri }] : []) ?? [])
: [],
};
function loadCollectionConfig(folders) {
return folders.flatMap((folder) => {
try {
const folderUri = vscode_uri_1.URI.parse(folder.uri);
let config = server.fileSystem.readFile(vscode_uri_1.Utils.joinPath(folderUri, '.astro/collections/collections.json'));
if (!config) {
return [];
}
// `server.fs.readFile` can theoretically be async, but in practice it's always sync
const collections = JSON.parse(config);
return { folder: folderUri, config: collections };
}
catch (err) {
// If the file doesn't exist, we don't really care, but if it's something else, we want to know
if (err && err.code !== 'ENOENT')
console.error(err);
return [];
}
});
}
return server.initialize(params, (0, node_1.createTypeScriptProject)(typescript, diagnosticMessages, ({ env }) => {
return {
languagePlugins: (0, languageServerPlugin_js_1.getLanguagePlugins)(collectionConfig),
setup({ project }) {
const { languageServiceHost, configFileName } = project.typescript;
const rootPath = configFileName
? configFileName.split('/').slice(0, -1).join('/')
: env.workspaceFolders[0].fsPath;
const nearestPackageJson = typescript.findConfigFile(rootPath, typescript.sys.fileExists, 'package.json');
const astroInstall = (0, utils_js_1.getAstroInstall)([rootPath], {
nearestPackageJson: nearestPackageJson,
readDirectory: typescript.sys.readDirectory,
});
if (astroInstall === 'not-found') {
connection.sendNotification(node_1.ShowMessageNotification.type, {
message: `Couldn't find Astro in workspace "${rootPath}". Experience might be degraded. For the best experience, please make sure Astro is installed into your project and restart the language server.`,
type: node_1.MessageType.Warning,
});
}
(0, index_js_1.addAstroTypes)(typeof astroInstall === 'string' ? undefined : astroInstall, typescript, languageServiceHost);
},
};
}), (0, languageServerPlugin_js_1.getLanguageServicePlugins)(connection, typescript, collectionConfig));
});
connection.onInitialized(() => {
server.initialized();
const extensions = [
'js',
'cjs',
'mjs',
'ts',
'cts',
'mts',
'jsx',
'tsx',
'json',
'astro',
'vue',
'svelte',
];
if (contentIntellisenseEnabled) {
extensions.push(...frontmatterHolders_js_1.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS);
server.fileWatcher.watchFiles(['**/*.schema.json', '**/collections.json']);
server.fileWatcher.onDidChangeWatchedFiles(({ changes }) => {
const shouldReload = changes.some((change) => change.uri.endsWith('.schema.json') || change.uri.endsWith('collections.json'));
if (shouldReload) {
server.project.reload();
}
});
}
server.fileWatcher.watchFiles([`**/*.{${extensions.join(',')}}`]);
});
//# sourceMappingURL=nodeServer.js.map

View File

@@ -1,2 +0,0 @@
import type { LanguageServicePlugin } from '@volar/language-server';
export declare const create: (ts: typeof import("typescript")) => LanguageServicePlugin;

View File

@@ -1,155 +0,0 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0;
const node_path_1 = require("node:path");
const language_server_1 = require("@volar/language-server");
const fast_glob_1 = __importDefault(require("fast-glob"));
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../core/index.js");
const utils_js_1 = require("./utils.js");
const create = (ts) => {
return {
capabilities: {
completionProvider: {
triggerCharacters: ['-'],
},
diagnosticProvider: {
interFileDependencies: false,
workspaceDiagnostics: false,
},
codeLensProvider: {},
},
create(context) {
return {
provideCompletionItems(document, position, completionContext, token) {
if (token.isCancellationRequested)
return null;
let items = [];
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
if (!(virtualCode instanceof index_js_1.AstroVirtualCode))
return;
if (completionContext.triggerCharacter === '-') {
const frontmatterCompletion = getFrontmatterCompletion(virtualCode, document, position);
if (frontmatterCompletion)
items.push(frontmatterCompletion);
}
return {
isIncomplete: false,
items: items,
};
},
provideDiagnostics(document, token) {
if (token.isCancellationRequested)
return [];
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
if (!(virtualCode instanceof index_js_1.AstroVirtualCode))
return;
return virtualCode.compilerDiagnostics.map(compilerMessageToDiagnostic);
function compilerMessageToDiagnostic(message) {
const start = language_server_1.Position.create(message.location.line - 1, message.location.column - 1);
const end = document.positionAt(document.offsetAt(start) + message.location.length);
return {
message: message.text + (message.hint ? '\n\n' + message.hint : ''),
range: language_server_1.Range.create(start, end),
code: message.code,
severity: message.severity,
source: 'astro',
};
}
},
provideCodeLenses(document, token) {
if (token.isCancellationRequested)
return;
if (!(0, utils_js_1.isJSDocument)(document.languageId))
return;
if (!context.project.typescript)
return;
const { uriConverter } = context.project.typescript;
const languageService = context.inject('typescript/languageService');
if (!languageService)
return;
const tsProgram = languageService.getProgram();
if (!tsProgram)
return;
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
if (!decoded)
return;
const globcodeLens = [];
const sourceFile = tsProgram.getSourceFile(decoded[0].fsPath);
function walk() {
return ts.forEachChild(sourceFile, function cb(node) {
if (ts.isCallExpression(node) && node.expression.getText() === 'Astro.glob') {
const globArgument = node.arguments.at(0);
if (globArgument && decoded) {
globcodeLens.push(getGlobResultAsCodeLens(globArgument.getText().slice(1, -1), (0, node_path_1.dirname)(uriConverter.asFileName(decoded[0])), document.positionAt(node.arguments.pos)));
}
}
return ts.forEachChild(node, cb);
});
}
walk();
return globcodeLens;
},
};
},
};
};
exports.create = create;
function getGlobResultAsCodeLens(globText, dir, position) {
const globResult = fast_glob_1.default.sync(globText, {
cwd: dir,
onlyFiles: true,
});
return {
range: language_server_1.Range.create(position, position),
command: { title: `Matches ${globResult.length} files`, command: '' },
};
}
function getFrontmatterCompletion(file, document, position) {
const base = {
kind: language_server_1.CompletionItemKind.Snippet,
label: '---',
sortText: '\0',
preselect: true,
detail: 'Create component script block',
insertTextFormat: language_server_1.InsertTextFormat.Snippet,
commitCharacters: [],
};
const documentLines = document.getText().split(/\r?\n/);
const { line, character } = document.positionAt(document.offsetAt(position));
const prefix = documentLines[line].slice(0, character);
if (file.astroMeta.frontmatter.status === 'doesnt-exist') {
return {
...base,
insertText: '---\n$0\n---',
textEdit: /^\s*-+/.test(prefix)
? language_server_1.TextEdit.replace({ start: { ...position, character: 0 }, end: position }, '---\n$0\n---')
: undefined,
};
}
if (file.astroMeta.frontmatter.status === 'open') {
let insertText = '---';
// If the current line is a full component script starter/ender, the user expects a full frontmatter
// completion and not just a completion for "---" on the same line (which result in, well, nothing)
if (prefix === '---') {
insertText = '---\n$0\n---';
}
return {
...base,
insertText,
detail: insertText === '---' ? 'Close component script block' : 'Create component script block',
textEdit: /^\s*-+/.test(prefix)
? language_server_1.TextEdit.replace({ start: { ...position, character: 0 }, end: position }, insertText)
: undefined,
};
}
return null;
}
//# sourceMappingURL=astro.js.map

View File

@@ -1,4 +0,0 @@
export declare const classListAttribute: import("vscode-html-languageservice").IHTMLDataProvider;
export declare const astroElements: import("vscode-html-languageservice").IHTMLDataProvider;
export declare const astroAttributes: import("vscode-html-languageservice").IHTMLDataProvider;
export declare const astroDirectives: import("vscode-html-languageservice").IHTMLDataProvider;

View File

@@ -1,277 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.astroDirectives = exports.astroAttributes = exports.astroElements = exports.classListAttribute = void 0;
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
const defaultProvider = (0, vscode_html_languageservice_1.getDefaultHTMLDataProvider)();
const slotAttr = defaultProvider.provideAttributes('div').find((attr) => attr.name === 'slot');
exports.classListAttribute = (0, vscode_html_languageservice_1.newHTMLDataProvider)('class-list', {
version: 1,
globalAttributes: [
{
name: 'class:list',
description: 'Utility to provide a list of classes of the element. Takes an array of class values and converts them into a class string.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#classlist',
},
],
},
],
});
exports.astroElements = (0, vscode_html_languageservice_1.newHTMLDataProvider)('astro-elements', {
version: 1,
tags: [
{
name: 'slot',
description: 'The slot element is a placeholder for external HTML content, allowing you to inject (or “slot”) child elements from other files into your component template.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/core-concepts/astro-components/#slots',
},
],
attributes: [
{
name: 'name',
description: 'The name attribute allows you to pass only HTML elements with the corresponding slot name into a slots location.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/core-concepts/astro-components/#named-slots',
},
],
},
],
},
{
name: 'script',
attributes: [
{
// The VS Code tag definitions does not provide a description for the deprecated `charset` attribute on script tags
// Which mean that since we get no hover info for this, we instead get JSX hover info. So we'll just specify a description ourselves for this specific case
name: 'charset',
description: "**Deprecated**\n\nIt's unnecessary to specify the charset attribute, because documents must use UTF-8, and the script element inherits its character encoding from the document.",
},
{
name: 'define:vars',
description: 'Passes serializable server-side variables into a client-side script element.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#definevars',
},
],
},
{
name: 'hoist',
description: '**Deprecated in Astro >= 0.26.0**\n\nBuilds, optimizes, and bundles your script with the other JavaScript on the page.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/core-concepts/astro-components/#using-hoisted-scripts',
},
],
},
{
name: 'is:inline',
description: 'Leave a script tag inline in the page template. No processing will be done on its content.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#isinline',
},
],
},
{
name: 'data-astro-rerun',
description: 'Force a script to be reexecuted when using <ViewTransitions/>. This will make your script is:inline as well.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/guides/view-transitions/#script-behavior',
},
],
},
],
},
{
name: 'style',
attributes: [
{
name: 'define:vars',
description: 'Passes serializable server-side variables into a client-side style element.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#definevars',
},
],
},
{
name: 'global',
description: '**Deprecated in favor of `is:global` in >= Astro 0.26.0**\n\nOpts-out of automatic CSS scoping, all contents will be available globally.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#isglobal',
},
],
},
{
name: 'is:global',
description: 'Opts-out of automatic CSS scoping, all contents will be available globally.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#isglobal',
},
],
},
{
name: 'is:inline',
description: 'Leave a style tag inline in the page template. No processing will be done on its content.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#isinline',
},
],
},
],
},
],
});
exports.astroAttributes = (0, vscode_html_languageservice_1.newHTMLDataProvider)('astro-attributes', {
version: 1,
globalAttributes: [
{
name: 'set:html',
description: 'Inject unescaped HTML into this tag.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#sethtml',
},
],
},
{
name: 'set:text',
description: 'Inject escaped text into this tag.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#settext',
},
],
},
{
name: 'is:raw',
description: 'Instructs the Astro compiler to treat any children of this element as text.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#israw',
},
],
},
{
name: 'transition:animate',
description: 'Specifies an animation to use with this element on page transition.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/guides/view-transitions/#transition-directives',
},
],
},
{
name: 'transition:name',
description: 'Specifies a `view-transition-name` for this element. The name must be unique on the page.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/guides/view-transitions/#transition-directives',
},
],
},
{
name: 'transition:persist',
description: 'Marks this element to be moved to the next page during view transitions.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/guides/view-transitions/#transition-directives',
},
],
},
slotAttr,
],
});
exports.astroDirectives = (0, vscode_html_languageservice_1.newHTMLDataProvider)('astro-directives', {
version: 1,
globalAttributes: [
{
name: 'client:load',
description: 'Start importing the component JS at page load. Hydrate the component when import completes.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#clientload',
},
],
},
{
name: 'client:idle',
description: 'Start importing the component JS as soon as main thread is free (uses requestIdleCallback()). Hydrate the component when import completes.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#clientidle',
},
],
},
{
name: 'client:visible',
description: 'Start importing the component JS as soon as the element enters the viewport (uses IntersectionObserver). Hydrate the component when import completes. Useful for content lower down on the page.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#clientvisible',
},
],
},
{
name: 'client:media',
description: 'Start importing the component JS as soon as the browser matches the given media query (uses matchMedia). Hydrate the component when import completes. Useful for sidebar toggles, or other elements that should only display on mobile or desktop devices.',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#clientmedia',
},
],
},
{
name: 'client:only',
description: 'Start importing the component JS at page load and hydrate when the import completes, similar to client:load. The component will be skipped at build time, useful for components that are entirely dependent on client-side APIs. This is best avoided unless absolutely needed, in most cases it is best to render placeholder content on the server and delay any browser API calls until the component hydrates in the browser.',
valueSet: 'v',
references: [
{
name: 'Astro reference',
url: 'https://docs.astro.build/en/reference/directives-reference/#clientonly',
},
],
},
],
});
//# sourceMappingURL=html-data.js.map

View File

@@ -1,2 +0,0 @@
import type { LanguageServicePlugin } from '@volar/language-server';
export declare const create: () => LanguageServicePlugin;

View File

@@ -1,93 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0;
const language_server_1 = require("@volar/language-server");
const volar_service_html_1 = require("volar-service-html");
const html = __importStar(require("vscode-html-languageservice"));
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../core/index.js");
const html_data_js_1 = require("./html-data.js");
const utils_js_1 = require("./utils.js");
const create = () => {
const htmlPlugin = (0, volar_service_html_1.create)({
getCustomData: async (context) => {
const customData = (await context.env.getConfiguration?.('html.customData')) ?? [];
const newData = [];
for (const customDataPath of customData) {
for (const workspaceFolder of context.env.workspaceFolders) {
const uri = vscode_uri_1.Utils.resolvePath(workspaceFolder, customDataPath);
const json = await context.env.fs?.readFile?.(uri);
if (json) {
try {
const data = JSON.parse(json);
newData.push(html.newHTMLDataProvider(customDataPath, data));
}
catch (error) {
console.error(error);
}
break;
}
}
}
return [...newData, html_data_js_1.astroAttributes, html_data_js_1.astroElements, html_data_js_1.classListAttribute];
},
});
return {
...htmlPlugin,
create(context) {
const htmlPluginInstance = htmlPlugin.create(context);
return {
...htmlPluginInstance,
async provideCompletionItems(document, position, completionContext, token) {
if (document.languageId !== 'html')
return;
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const root = sourceScript?.generated?.root;
if (!(root instanceof index_js_1.AstroVirtualCode))
return;
// Don't return completions if the current node is a component
if ((0, utils_js_1.isInComponentStartTag)(root.htmlDocument, document.offsetAt(position))) {
return null;
}
const completions = await htmlPluginInstance.provideCompletionItems(document, position, completionContext, token);
if (!completions) {
return null;
}
// We don't want completions for file references, as they're mostly invalid for Astro
completions.items = completions.items.filter((completion) => completion.kind !== language_server_1.CompletionItemKind.File);
return completions;
},
// Document links provided by `vscode-html-languageservice` are invalid for Astro
provideDocumentLinks() {
return [];
},
};
},
};
};
exports.create = create;
//# sourceMappingURL=html.js.map

View File

@@ -1,2 +0,0 @@
import type { LanguageServicePlugin } from '@volar/language-server';
export declare const create: () => LanguageServicePlugin;

View File

@@ -1,52 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0;
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../../core/index.js");
const utils_js_1 = require("../utils.js");
const snippets_js_1 = require("./snippets.js");
const create = () => {
return {
capabilities: {
completionProvider: {
resolveProvider: true,
},
},
create(context) {
return {
isAdditionalCompletion: true,
// Q: Why the empty transform and resolve functions?
// A: Volar will skip mapping the completion items if those functions are defined, as such we can return the snippets
// completions as-is, this is notably useful for snippets that insert to the frontmatter, since we don't need to map anything.
transformCompletionItem(item) {
return item;
},
provideCompletionItems(document, position, completionContext, token) {
if (!context ||
!utils_js_1.isJSDocument ||
token.isCancellationRequested ||
completionContext.triggerKind === 2)
return null;
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const root = sourceScript?.generated?.root;
if (!(root instanceof index_js_1.AstroVirtualCode))
return undefined;
if (!(0, utils_js_1.isInsideFrontmatter)(document.offsetAt(position), root.astroMeta.frontmatter))
return null;
const completionList = {
items: [],
isIncomplete: false,
};
completionList.items.push(...(0, snippets_js_1.getSnippetCompletions)(root.astroMeta.frontmatter));
return completionList;
},
resolveCompletionItem(item) {
return item;
},
};
},
};
};
exports.create = create;
//# sourceMappingURL=index.js.map

View File

@@ -1,3 +0,0 @@
import { type CompletionItem } from '@volar/language-server';
import type { FrontmatterStatus } from '../../core/parseAstro.js';
export declare function getSnippetCompletions(frontmatter: FrontmatterStatus): CompletionItem[];

View File

@@ -1,65 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.getSnippetCompletions = getSnippetCompletions;
const language_server_1 = require("@volar/language-server");
function getSnippetCompletions(frontmatter) {
if (frontmatter.status === 'doesnt-exist')
return [];
const frontmatterStartPosition = {
line: frontmatter.position.start.line,
character: frontmatter.position.start.column - 1,
};
return [
{
label: 'interface Props',
kind: language_server_1.CompletionItemKind.Snippet,
labelDetails: { description: 'Create a new interface to type your props' },
documentation: {
kind: 'markdown',
value: [
'Create a new interface to type your props.',
'\n',
'[Astro reference](https://docs.astro.build/en/guides/typescript/#component-props)',
].join('\n'),
},
insertTextFormat: 2,
filterText: 'interface props',
insertText: 'interface Props {\n\t$1\n}',
},
{
label: 'getStaticPaths',
kind: language_server_1.CompletionItemKind.Snippet,
labelDetails: { description: 'Create a new getStaticPaths function' },
documentation: {
kind: 'markdown',
value: [
'Create a new getStaticPaths function.',
'\n',
'[Astro reference](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)',
].join('\n'),
},
insertText: 'export const getStaticPaths = (() => {\n\t$1\n\treturn [];\n}) satisfies GetStaticPaths;',
additionalTextEdits: [
language_server_1.TextEdit.insert(frontmatterStartPosition, 'import type { GetStaticPaths } from "astro";\n'),
],
filterText: 'getstaticpaths',
insertTextFormat: 2,
},
{
label: 'prerender',
kind: language_server_1.CompletionItemKind.Snippet,
labelDetails: { description: 'Add prerender export' },
documentation: {
kind: 'markdown',
value: [
'Add prerender export. When [using server-side rendering](https://docs.astro.build/en/guides/server-side-rendering/#enabling-ssr-in-your-project), this value will be used to determine whether to prerender the page or not.',
'\n',
'[Astro reference](https://docs.astro.build/en/guides/server-side-rendering/#configuring-individual-routes)',
].join('\n'),
},
insertText: 'export const prerender = ${1|true,false,import.meta.env.|}',
insertTextFormat: 2,
},
];
}
//# sourceMappingURL=snippets.js.map

View File

@@ -1,3 +0,0 @@
import type { CodeAction, LanguageServiceContext } from '@volar/language-service';
export declare function enhancedProvideCodeActions(codeActions: CodeAction[], context: LanguageServiceContext): CodeAction[];
export declare function enhancedResolveCodeAction(codeAction: CodeAction, context: LanguageServiceContext): CodeAction;

View File

@@ -1,37 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.enhancedProvideCodeActions = enhancedProvideCodeActions;
exports.enhancedResolveCodeAction = enhancedResolveCodeAction;
const language_server_1 = require("@volar/language-server");
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../../core/index.js");
const utils_js_1 = require("./utils.js");
function enhancedProvideCodeActions(codeActions, context) {
return codeActions.map((codeAction) => mapCodeAction(codeAction, context));
}
function enhancedResolveCodeAction(codeAction, context) {
/**
* TypeScript code actions don't come through here, as they're considered to be already fully resolved
* A lot of the code actions we'll encounter here are more tricky ones, such as fixAll or refactor
* For now, it seems like we don't need to do anything special here, but we'll keep this function around
*/
return mapCodeAction(codeAction, context);
}
function mapCodeAction(codeAction, context) {
if (!codeAction.edit || !codeAction.edit.documentChanges)
return codeAction;
codeAction.edit.documentChanges = codeAction.edit.documentChanges.map((change) => {
if (language_server_1.TextDocumentEdit.is(change)) {
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(change.textDocument.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
const root = sourceScript?.generated?.root;
if (!virtualCode || !(root instanceof index_js_1.AstroVirtualCode))
return change;
change.edits = change.edits.map((edit) => (0, utils_js_1.mapEdit)(edit, root, virtualCode.languageId));
}
return change;
});
return codeAction;
}
//# sourceMappingURL=codeActions.js.map

View File

@@ -1,3 +0,0 @@
import type { CompletionItem, CompletionList, LanguageServiceContext } from '@volar/language-server';
export declare function enhancedProvideCompletionItems(completions: CompletionList): CompletionList;
export declare function enhancedResolveCompletionItem(resolvedCompletion: CompletionItem, context: LanguageServiceContext): CompletionItem;

View File

@@ -1,76 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.enhancedProvideCompletionItems = enhancedProvideCompletionItems;
exports.enhancedResolveCompletionItem = enhancedResolveCompletionItem;
const language_server_1 = require("@volar/language-server");
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../../core/index.js");
const utils_js_1 = require("./utils.js");
function enhancedProvideCompletionItems(completions) {
completions.items = completions.items.filter(isValidCompletion).map((completion) => {
const source = completion?.data?.originalItem?.source;
if (source) {
// Sort completions starting with `astro:` higher than other imports
if (source.startsWith('astro:')) {
completion.sortText = '\u0000' + (completion.sortText ?? completion.label);
}
// For components import, use the file kind and sort them first, as they're often what the user want over something else
if (['.astro', '.svelte', '.vue'].some((ext) => source.endsWith(ext))) {
completion.kind = language_server_1.CompletionItemKind.File;
completion.detail = completion.detail + '\n\n' + source;
completion.sortText = '\u0001' + (completion.sortText ?? completion.label);
completion.data.isComponent = true;
}
}
return completion;
});
return completions;
}
function enhancedResolveCompletionItem(resolvedCompletion, context) {
// Make sure we keep our icons even when the completion is resolved
if (resolvedCompletion.data.isComponent) {
resolvedCompletion.detail = getDetailForFileCompletion(resolvedCompletion.detail ?? '', resolvedCompletion.data.originalItem.source);
}
if (resolvedCompletion.additionalTextEdits) {
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(resolvedCompletion.data.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]);
const root = sourceScript?.generated?.root;
if (!virtualCode || !(root instanceof index_js_1.AstroVirtualCode))
return resolvedCompletion;
resolvedCompletion.additionalTextEdits = resolvedCompletion.additionalTextEdits.map((edit) => (0, utils_js_1.mapEdit)(edit, root, virtualCode.languageId));
}
return resolvedCompletion;
}
function getDetailForFileCompletion(detail, source) {
return `${detail}\n\n${source}`;
}
// When Svelte components are imported, we have to reference the svelte2tsx's types to properly type the component
// An unfortunate downside of this is that it pollutes completions, so let's filter those internal types manually
const svelte2tsxTypes = new Set([
'Svelte2TsxComponent',
'Svelte2TsxComponentConstructorParameters',
'SvelteComponentConstructor',
'SvelteActionReturnType',
'SvelteTransitionConfig',
'SvelteTransitionReturnType',
'SvelteAnimationReturnType',
'SvelteWithOptionalProps',
'SvelteAllProps',
'SveltePropsAnyFallback',
'SvelteSlotsAnyFallback',
'SvelteRestProps',
'SvelteSlots',
'SvelteStore',
]);
function isValidCompletion(completion) {
const isSvelte2tsxCompletion = completion.label.startsWith('__sveltets_') || svelte2tsxTypes.has(completion.label);
// Filter out completions for the children prop, as it doesn't work in Astro
const isChildrenCompletion = completion.label === 'children?' &&
completion.kind === language_server_1.CompletionItemKind.Field &&
completion.filterText === 'children={$1}';
if (isSvelte2tsxCompletion || isChildrenCompletion)
return false;
return true;
}
//# sourceMappingURL=completions.js.map

View File

@@ -1,12 +0,0 @@
import type { Diagnostic } from '@volar/language-server';
export declare enum DiagnosticCodes {
IS_NOT_A_MODULE = 2306,// '{0}' is not a module.
CANNOT_FIND_MODULE = 2307,// Cannot find module '{0}' or its corresponding type declarations.
DUPLICATED_JSX_ATTRIBUTES = 17001,// JSX elements cannot have multiple attributes with the same name.
CANT_RETURN_OUTSIDE_FUNC = 1108,// A 'return' statement can only be used within a function body.
ISOLATED_MODULE_COMPILE_ERR = 1208,// '{0}' cannot be compiled under '--isolatedModules' because it is considered a global script file.
TYPE_NOT_ASSIGNABLE = 2322,// Type '{0}' is not assignable to type '{1}'.
JSX_NO_CLOSING_TAG = 17008,// JSX element '{0}' has no corresponding closing tag.
JSX_ELEMENT_NO_CALL = 2604
}
export declare function enhancedProvideSemanticDiagnostics(originalDiagnostics: Diagnostic[], tsxLineCount?: number | undefined): Diagnostic[];

View File

@@ -1,104 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.DiagnosticCodes = void 0;
exports.enhancedProvideSemanticDiagnostics = enhancedProvideSemanticDiagnostics;
// List of codes:
// https://github.com/Microsoft/TypeScript/blob/main/src/compiler/diagnosticMessages.json
var DiagnosticCodes;
(function (DiagnosticCodes) {
DiagnosticCodes[DiagnosticCodes["IS_NOT_A_MODULE"] = 2306] = "IS_NOT_A_MODULE";
DiagnosticCodes[DiagnosticCodes["CANNOT_FIND_MODULE"] = 2307] = "CANNOT_FIND_MODULE";
DiagnosticCodes[DiagnosticCodes["DUPLICATED_JSX_ATTRIBUTES"] = 17001] = "DUPLICATED_JSX_ATTRIBUTES";
DiagnosticCodes[DiagnosticCodes["CANT_RETURN_OUTSIDE_FUNC"] = 1108] = "CANT_RETURN_OUTSIDE_FUNC";
DiagnosticCodes[DiagnosticCodes["ISOLATED_MODULE_COMPILE_ERR"] = 1208] = "ISOLATED_MODULE_COMPILE_ERR";
DiagnosticCodes[DiagnosticCodes["TYPE_NOT_ASSIGNABLE"] = 2322] = "TYPE_NOT_ASSIGNABLE";
DiagnosticCodes[DiagnosticCodes["JSX_NO_CLOSING_TAG"] = 17008] = "JSX_NO_CLOSING_TAG";
DiagnosticCodes[DiagnosticCodes["JSX_ELEMENT_NO_CALL"] = 2604] = "JSX_ELEMENT_NO_CALL";
})(DiagnosticCodes || (exports.DiagnosticCodes = DiagnosticCodes = {}));
function enhancedProvideSemanticDiagnostics(originalDiagnostics, tsxLineCount) {
const diagnostics = originalDiagnostics
.filter((diagnostic) => (tsxLineCount ? diagnostic.range.start.line <= tsxLineCount : true) &&
isNoCantReturnOutsideFunction(diagnostic) &&
isNoIsolatedModuleError(diagnostic) &&
isNoJsxCannotHaveMultipleAttrsError(diagnostic))
.map((diag) => tsxLineCount ? generalEnhancements(astroEnhancements(diag)) : generalEnhancements(diag));
return diagnostics;
}
// General enhancements that apply to all files
function generalEnhancements(diagnostic) {
if (diagnostic.code === DiagnosticCodes.CANNOT_FIND_MODULE &&
diagnostic.message.includes('astro:content')) {
diagnostic.message +=
"\n\nIf you're using content collections, make sure to run `astro dev`, `astro build` or `astro sync` to first generate the types so you can import from them. If you already ran one of those commands, restarting the language server might be necessary in order for the change to take effect.";
return diagnostic;
}
return diagnostic;
}
/**
* Astro-specific enhancements. For instance, when the user tries to import a component from a framework that is not installed
* or a difference with JSX needing a different error message
*/
function astroEnhancements(diagnostic) {
// When the language integrations are not installed, the content of the imported snapshot is empty
// As such, it triggers the "is not a module error", which we can enhance with a more helpful message for the related framework
if (diagnostic.code === DiagnosticCodes.IS_NOT_A_MODULE) {
if (diagnostic.message.includes('.svelte')) {
diagnostic.message +=
'\n\nIs the `@astrojs/svelte` package installed? You can add it to your project by running the following command: `astro add svelte`. If already installed, restarting the language server might be necessary in order for the change to take effect.';
}
if (diagnostic.message.includes('.vue')) {
diagnostic.message +=
'\n\nIs the `@astrojs/vue` package installed? You can add it to your project by running the following command: `astro add vue`. If already installed, restarting the language server might be necessary in order for the change to take effect.';
}
return diagnostic;
}
// JSX element has no closing tag. JSX -> HTML
if (diagnostic.code === DiagnosticCodes.JSX_NO_CLOSING_TAG) {
return {
...diagnostic,
message: diagnostic.message.replace('JSX', 'HTML'),
};
}
// JSX Element can't be constructed or called. This happens on syntax errors / invalid components
if (diagnostic.code === DiagnosticCodes.JSX_ELEMENT_NO_CALL) {
return {
...diagnostic,
message: diagnostic.message
.replace('JSX element type', 'Component')
.replace('does not have any construct or call signatures.', 'is not a valid component.\n\nIf this is a Svelte or Vue component, it might have a syntax error that makes it impossible to parse.'),
};
}
// For the rare case where an user might try to put a client directive on something that is not a component
if (diagnostic.code === DiagnosticCodes.TYPE_NOT_ASSIGNABLE) {
if (diagnostic.message.includes("Property 'client:") &&
diagnostic.message.includes("to type 'HTMLAttributes")) {
return {
...diagnostic,
message: diagnostic.message + '\n\nClient directives are only available on framework components.',
};
}
}
return diagnostic;
}
/**
* Astro allows multiple attributes to have the same name
*/
function isNoJsxCannotHaveMultipleAttrsError(diagnostic) {
return diagnostic.code !== DiagnosticCodes.DUPLICATED_JSX_ATTRIBUTES;
}
/**
* Ignore "Can't return outside of function body"
* Since the frontmatter is at the top level, users trying to return a Response for SSR mode run into this
* TODO: Update the TSX shape so this is not an issue anymore
*/
function isNoCantReturnOutsideFunction(diagnostic) {
return diagnostic.code !== DiagnosticCodes.CANT_RETURN_OUTSIDE_FUNC;
}
/**
* When the content of the file is invalid and can't be parsed properly for TSX generation, TS will show an error about
* how the current module can't be compiled under --isolatedModule, this is confusing to users so let's ignore this
*/
function isNoIsolatedModuleError(diagnostic) {
return diagnostic.code !== DiagnosticCodes.ISOLATED_MODULE_COMPILE_ERR;
}
//# sourceMappingURL=diagnostics.js.map

View File

@@ -1,2 +0,0 @@
import type { LanguageServicePlugin } from '@volar/language-server';
export declare const create: (ts: typeof import("typescript")) => LanguageServicePlugin[];

View File

@@ -1,77 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0;
const volar_service_typescript_1 = require("volar-service-typescript");
const vscode_uri_1 = require("vscode-uri");
const index_js_1 = require("../../core/index.js");
const codeActions_js_1 = require("./codeActions.js");
const completions_js_1 = require("./completions.js");
const diagnostics_js_1 = require("./diagnostics.js");
const create = (ts) => {
const tsServicePlugins = (0, volar_service_typescript_1.create)(ts, {});
return tsServicePlugins.map((plugin) => {
if (plugin.name === 'typescript-semantic') {
return {
...plugin,
create(context) {
const typeScriptPlugin = plugin.create(context);
return {
...typeScriptPlugin,
async provideFileRenameEdits(oldUri, newUri, token) {
const astroConfig = await context.env.getConfiguration?.('astro');
// Check for `false` explicitly, as the default value is `true`, but it might not be set explicitly depending on the editor
if (astroConfig?.updateImportsOnFileMove.enabled === false) {
return null;
}
return typeScriptPlugin.provideFileRenameEdits(oldUri, newUri, token);
},
async provideCompletionItems(document, position, completionContext, token) {
const originalCompletions = await typeScriptPlugin.provideCompletionItems(document, position, completionContext, token);
if (!originalCompletions)
return null;
return (0, completions_js_1.enhancedProvideCompletionItems)(originalCompletions);
},
async resolveCompletionItem(item, token) {
const resolvedCompletionItem = await typeScriptPlugin.resolveCompletionItem(item, token);
if (!resolvedCompletionItem)
return item;
return (0, completions_js_1.enhancedResolveCompletionItem)(resolvedCompletionItem, context);
},
async provideCodeActions(document, range, codeActionContext, token) {
const originalCodeActions = await typeScriptPlugin.provideCodeActions(document, range, codeActionContext, token);
if (!originalCodeActions)
return null;
return (0, codeActions_js_1.enhancedProvideCodeActions)(originalCodeActions, context);
},
async resolveCodeAction(codeAction, token) {
const resolvedCodeAction = await typeScriptPlugin.resolveCodeAction(codeAction, token);
if (!resolvedCodeAction)
return codeAction;
return (0, codeActions_js_1.enhancedResolveCodeAction)(resolvedCodeAction, context);
},
async provideDiagnostics(document, token) {
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const root = sourceScript?.generated?.root;
let tsxLineCount = undefined;
if (root instanceof index_js_1.AstroVirtualCode && decoded?.[1] === 'tsx') {
// If we have compiler errors, our TSX isn't valid so don't bother showing TS errors
if (root.hasCompilationErrors)
return null;
// We'll use this to filter out diagnostics that are outside the mapped range of the TSX
tsxLineCount = root.astroMeta.tsxRanges.body.end.line;
}
const diagnostics = await typeScriptPlugin.provideDiagnostics(document, token);
if (!diagnostics)
return null;
return (0, diagnostics_js_1.enhancedProvideSemanticDiagnostics)(diagnostics, tsxLineCount);
},
};
},
};
}
return plugin;
});
};
exports.create = create;
//# sourceMappingURL=index.js.map

View File

@@ -1,3 +0,0 @@
import type { TextEdit } from 'vscode-html-languageservice';
import type { AstroVirtualCode } from '../../core/index.js';
export declare function mapEdit(edit: TextEdit, code: AstroVirtualCode, languageId: string): TextEdit;

View File

@@ -1,20 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.mapEdit = mapEdit;
const utils_js_1 = require("../utils.js");
function mapEdit(edit, code, languageId) {
// Don't attempt to move the edit to the frontmatter if the file isn't the root TSX file, it means it's a script tag
if (languageId === 'typescriptreact') {
if ((0, utils_js_1.editShouldBeInFrontmatter)(edit.range, code.astroMeta).itShould) {
edit = (0, utils_js_1.ensureProperEditForFrontmatter)(edit, code.astroMeta, '\n');
}
}
else {
// If the edit is at the start of the file, add a newline before it, otherwise we'll get `<script>text`
if (edit.range.start.line === 0 && edit.range.start.character === 0) {
edit.newText = '\n' + edit.newText;
}
}
return edit;
}
//# sourceMappingURL=utils.js.map

View File

@@ -1,38 +0,0 @@
import type { HTMLDocument, Node, TextEdit } from 'vscode-html-languageservice';
import { Range } from 'vscode-html-languageservice';
import type { AstroMetadata, FrontmatterStatus } from '../core/parseAstro.js';
export declare function isJSDocument(languageId: string): languageId is "typescript" | "typescriptreact" | "javascript" | "javascriptreact";
/**
* Return true if a specific node could be a component.
* 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
*/
export declare function isPossibleComponent(node: Node): boolean;
/**
* Return if a given offset is inside the start tag of a component
*/
export declare function isInComponentStartTag(html: HTMLDocument, offset: number): boolean;
/**
* Return if a given position is inside a JSX expression
*/
export declare function isInsideExpression(html: string, tagStart: number, position: number): boolean;
/**
* Return if a given offset is inside the frontmatter
*/
export declare function isInsideFrontmatter(offset: number, frontmatter: FrontmatterStatus): boolean;
type FrontmatterEditPosition = 'top' | 'bottom';
export declare function ensureProperEditForFrontmatter(edit: TextEdit, metadata: AstroMetadata, newLine: string, position?: FrontmatterEditPosition): TextEdit;
/**
* Force a range to be at the start of the frontmatter if it is outside
*/
export declare function ensureRangeIsInFrontmatter(range: Range, metadata: AstroMetadata, position?: FrontmatterEditPosition): Range;
export declare function getNewFrontmatterEdit(edit: TextEdit, astroMetadata: AstroMetadata, newLine: string): TextEdit;
export declare function getOpenFrontmatterEdit(edit: TextEdit, astroMetadata: AstroMetadata, newLine: string): TextEdit;
type FrontmatterEditValidity = {
itShould: false;
position: undefined;
} | {
itShould: true;
position: FrontmatterEditPosition;
};
export declare function editShouldBeInFrontmatter(range: Range, astroMetadata: AstroMetadata): FrontmatterEditValidity;
export {};

View File

@@ -1,114 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isJSDocument = isJSDocument;
exports.isPossibleComponent = isPossibleComponent;
exports.isInComponentStartTag = isInComponentStartTag;
exports.isInsideExpression = isInsideExpression;
exports.isInsideFrontmatter = isInsideFrontmatter;
exports.ensureProperEditForFrontmatter = ensureProperEditForFrontmatter;
exports.ensureRangeIsInFrontmatter = ensureRangeIsInFrontmatter;
exports.getNewFrontmatterEdit = getNewFrontmatterEdit;
exports.getOpenFrontmatterEdit = getOpenFrontmatterEdit;
exports.editShouldBeInFrontmatter = editShouldBeInFrontmatter;
const vscode_html_languageservice_1 = require("vscode-html-languageservice");
function isJSDocument(languageId) {
return (languageId === 'javascript' ||
languageId === 'typescript' ||
languageId === 'javascriptreact' ||
languageId === 'typescriptreact');
}
/**
* Return true if a specific node could be a component.
* 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
*/
function isPossibleComponent(node) {
if (!node.tag)
return false;
return !!/[A-Z]/.test(node.tag?.[0]) || !!/.+\.[A-Z]?/.test(node.tag);
}
/**
* Return if a given offset is inside the start tag of a component
*/
function isInComponentStartTag(html, offset) {
const node = html.findNodeAt(offset);
return isPossibleComponent(node) && (!node.startTagEnd || offset < node.startTagEnd);
}
/**
* Return if a given position is inside a JSX expression
*/
function isInsideExpression(html, tagStart, position) {
const charactersInNode = html.substring(tagStart, position);
return charactersInNode.lastIndexOf('{') > charactersInNode.lastIndexOf('}');
}
/**
* Return if a given offset is inside the frontmatter
*/
function isInsideFrontmatter(offset, frontmatter) {
switch (frontmatter.status) {
case 'closed':
return offset > frontmatter.position.start.offset && offset < frontmatter.position.end.offset;
case 'open':
return offset > frontmatter.position.start.offset;
case 'doesnt-exist':
return false;
}
}
function ensureProperEditForFrontmatter(edit, metadata, newLine, position = 'top') {
switch (metadata.frontmatter.status) {
case 'open':
return getOpenFrontmatterEdit(edit, metadata, newLine);
case 'closed':
const newRange = ensureRangeIsInFrontmatter(edit.range, metadata, position);
return {
newText: newRange.start.line === metadata.frontmatter.position.start.line &&
edit.newText.startsWith(newLine)
? edit.newText.trimStart()
: edit.newText,
range: newRange,
};
case 'doesnt-exist':
return getNewFrontmatterEdit(edit, metadata, newLine);
}
}
/**
* Force a range to be at the start of the frontmatter if it is outside
*/
function ensureRangeIsInFrontmatter(range, metadata, position = 'top') {
if (metadata.frontmatter.status === 'open' || metadata.frontmatter.status === 'closed') {
const frontmatterEndPosition = metadata.frontmatter.position.end
? metadata.tsxRanges.frontmatter.end
: undefined;
// If the range start is outside the frontmatter, return a range at the start of the frontmatter
if (range.start.line < metadata.tsxRanges.frontmatter.start.line ||
(frontmatterEndPosition && range.start.line > frontmatterEndPosition.line)) {
if (frontmatterEndPosition && position === 'bottom') {
return vscode_html_languageservice_1.Range.create(frontmatterEndPosition, frontmatterEndPosition);
}
return vscode_html_languageservice_1.Range.create(metadata.tsxRanges.frontmatter.start, metadata.tsxRanges.frontmatter.start);
}
return range;
}
return range;
}
function getNewFrontmatterEdit(edit, astroMetadata, newLine) {
edit.newText = `---${edit.newText.startsWith(newLine) ? '' : newLine}${edit.newText}---${newLine}${newLine}`;
edit.range = vscode_html_languageservice_1.Range.create(astroMetadata.tsxRanges.frontmatter.start, astroMetadata.tsxRanges.frontmatter.start);
return edit;
}
function getOpenFrontmatterEdit(edit, astroMetadata, newLine) {
edit.newText = edit.newText.startsWith(newLine)
? `${edit.newText}---`
: `${newLine}${edit.newText}---`;
edit.range = vscode_html_languageservice_1.Range.create(astroMetadata.tsxRanges.frontmatter.start, astroMetadata.tsxRanges.frontmatter.start);
return edit;
}
// Most edits that are at the beginning of the TSX, or outside the document are intended for the frontmatter
function editShouldBeInFrontmatter(range, astroMetadata) {
const isAtTSXStart = range.start.line < astroMetadata.tsxRanges.frontmatter.start.line;
const isPastFile = range.start.line > astroMetadata.tsxRanges.body.end.line;
const shouldIt = isAtTSXStart || isPastFile;
return shouldIt
? { itShould: true, position: isPastFile ? 'bottom' : 'top' }
: { itShould: false, position: undefined };
}
//# sourceMappingURL=utils.js.map

View File

@@ -1,7 +0,0 @@
import type { LanguageServicePlugin } from '@volar/language-service';
import type { Provide } from 'volar-service-yaml';
import type { CollectionConfig } from '../core/frontmatterHolders.js';
type LanguageSettings = Parameters<ReturnType<Provide['yaml/languageService']>['configure']>['0'];
export declare function getSettings(collectionConfig: CollectionConfig): LanguageSettings;
export declare const create: (collectionConfig: CollectionConfig) => LanguageServicePlugin;
export {};

View File

@@ -1,112 +0,0 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.create = void 0;
exports.getSettings = getSettings;
const language_server_1 = require("@volar/language-server");
const volar_service_yaml_1 = require("volar-service-yaml");
const vscode_uri_1 = require("vscode-uri");
const frontmatterHolders_js_1 = require("../core/frontmatterHolders.js");
function getSettings(collectionConfig) {
const schemas = collectionConfig.configs.flatMap((workspaceCollectionConfig) => {
return workspaceCollectionConfig.config.collections.flatMap((collection) => {
return {
fileMatch: frontmatterHolders_js_1.SUPPORTED_FRONTMATTER_EXTENSIONS_KEYS.map((ext) => `volar-embedded-content://yaml_frontmatter_${collection.name}/**/*${ext}`),
uri: vscode_uri_1.Utils.joinPath(workspaceCollectionConfig.folder, '.astro/collections', `${collection.name}.schema.json`).toString(),
};
});
});
return {
completion: true,
format: false,
hover: true,
validate: true,
customTags: [],
yamlVersion: '1.2',
isKubernetes: false,
parentSkeletonSelectedFirst: false,
disableDefaultProperties: false,
schemas: schemas,
};
}
const create = (collectionConfig) => {
const yamlPlugin = (0, volar_service_yaml_1.create)({
getLanguageSettings: () => getSettings(collectionConfig),
});
return {
...yamlPlugin,
capabilities: {
...yamlPlugin.capabilities,
codeLensProvider: undefined,
},
create(context) {
const yamlPluginInstance = yamlPlugin.create(context);
const languageService = yamlPluginInstance.provide?.['yaml/languageService']();
if (languageService && context.env.onDidChangeWatchedFiles) {
context.env.onDidChangeWatchedFiles(async (events) => {
const changedSchemas = events.changes.filter((change) => change.uri.endsWith('.schema.json'));
const changedConfig = events.changes.some((change) => change.uri.endsWith('collections.json'));
if (changedConfig) {
collectionConfig.reload(
// For some reason, context.env.workspaceFolders is not an array of WorkspaceFolders nor the older format, strange
context.env.workspaceFolders.map((folder) => ({ uri: folder.toString() })));
languageService.configure(getSettings(collectionConfig));
}
for (const change of changedSchemas) {
languageService.resetSchema(change.uri);
}
});
}
return {
...yamlPluginInstance,
// Disable codelenses, we'll provide our own
provideCodeLenses: undefined,
resolveCodeLens: undefined,
async provideDiagnostics(document, token) {
const originalDiagnostics = await yamlPluginInstance.provideDiagnostics(document, token);
if (!originalDiagnostics) {
return null;
}
const decoded = context.decodeEmbeddedDocumentUri(vscode_uri_1.URI.parse(document.uri));
const sourceScript = decoded && context.language.scripts.get(decoded[0]);
const root = sourceScript?.generated?.root;
if (!(root instanceof frontmatterHolders_js_1.FrontmatterHolder))
return undefined;
// If we don't have a frontmatter, but there are errors, it probably means a frontmatter was required
if (!root.hasFrontmatter && originalDiagnostics.length > 0) {
return [
language_server_1.Diagnostic.create(language_server_1.Range.create(0, 0, 0, 0), 'Frontmatter is required for this file.', language_server_1.DiagnosticSeverity.Error),
];
}
return originalDiagnostics.map((diagnostic) => {
// The YAML schema source is not useful to users, since it's generated. Also, it's quite long.
if (diagnostic.source?.startsWith('yaml-schema:')) {
diagnostic.source = 'astro';
// In Astro, schema errors are always fatal
diagnostic.severity = language_server_1.DiagnosticSeverity.Error;
// Map missing properties to the entire frontmatte
if (diagnostic.message.startsWith('Missing property')) {
diagnostic.range = language_server_1.Range.create({ line: 0, character: 0 }, document.positionAt(document.getText().length));
}
}
return diagnostic;
});
},
async provideHover(document, position, token) {
const originalHover = await yamlPluginInstance.provideHover(document, position, token);
if (!originalHover) {
return null;
}
if (language_server_1.MarkupContent.is(originalHover.contents)) {
// Remove last line that contains the source schema, it's not useful to users since they're generated
originalHover.contents.value = originalHover.contents.value
.replace(/\nSource:.*$/, '')
.trim();
}
return originalHover;
},
};
},
};
};
exports.create = create;
//# sourceMappingURL=yaml.js.map

View File

@@ -1,6 +0,0 @@
import type { PackageInfo } from './importPackage.js';
export declare function getLanguageServerTypesDir(ts: typeof import('typescript')): string;
export declare function getAstroInstall(basePaths: string[], checkForAstro?: {
nearestPackageJson: string | undefined;
readDirectory: typeof import('typescript').sys.readDirectory;
}): PackageInfo | 'not-an-astro-project' | 'not-found';

View File

@@ -1,65 +0,0 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.getLanguageServerTypesDir = getLanguageServerTypesDir;
exports.getAstroInstall = getAstroInstall;
const path = __importStar(require("node:path"));
const importPackage_js_1 = require("./importPackage.js");
function getLanguageServerTypesDir(ts) {
return ts.sys.resolvePath(path.resolve(__dirname, '../types'));
}
function getAstroInstall(basePaths, checkForAstro) {
if (checkForAstro && checkForAstro.nearestPackageJson) {
basePaths.push(path.dirname(checkForAstro.nearestPackageJson));
let deps = new Set();
try {
const packageJSON = require(checkForAstro.nearestPackageJson);
[
...Object.keys(packageJSON.dependencies ?? {}),
...Object.keys(packageJSON.devDependencies ?? {}),
...Object.keys(packageJSON.peerDependencies ?? {}),
].forEach((dep) => deps.add(dep));
}
catch { }
if (!deps.has('astro')) {
const directoryContent = checkForAstro.readDirectory(path.dirname(checkForAstro.nearestPackageJson), ['.js', '.mjs', '.cjs', '.ts', '.mts', '.cts'], undefined, undefined, 1);
if (!directoryContent.some((file) => path.basename(file).startsWith('astro.config'))) {
return 'not-an-astro-project';
}
}
}
let astroPackage = (0, importPackage_js_1.getPackageInfo)('astro', basePaths);
if (!astroPackage) {
// If we couldn't find it inside the workspace's node_modules, it might means we're in the Astro development monorepo
astroPackage = (0, importPackage_js_1.getPackageInfo)('./packages/astro', basePaths);
if (!astroPackage) {
console.error(`${basePaths[0]} seems to be an Astro project, but we couldn't find Astro or Astro is not installed`);
// If we still couldn't find it, it probably just doesn't exist
return 'not-found';
}
}
return astroPackage;
}
//# sourceMappingURL=utils.js.map