Skip to content

Commit

Permalink
feat: Update to Volar 2.4 alpha (#879)
Browse files Browse the repository at this point in the history
* Upgrade to Volar 2.3

* Fix tests

* bump

* Remove updateVirtualCode hooks

* Update Volar

* Update client.ts

* Update Volar

* Update to 2.3.0

* Fix tests

* Add muggle-string

* chore: bump Volar

* chore: bump Volar

* Update init.test.ts

* chore: bump Volar

* chore: bump Volar

* Update to Volar 3.4 alpha

* Update pnpm-lock.yaml

* Fix tests

* Update init.test.ts

* getVueLanguageModule -> getVueLanguagePlugin

* chore: changeset

---------

Co-authored-by: Princesseuh <3019731+Princesseuh@users.noreply.github.com>
  • Loading branch information
johnsoncodehk and Princesseuh authored Jul 8, 2024
1 parent a1769da commit b8a6af3
Show file tree
Hide file tree
Showing 27 changed files with 478 additions and 393 deletions.
8 changes: 8 additions & 0 deletions .changeset/wild-rings-bow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@astrojs/language-server": minor
"@astrojs/check": minor
"@astrojs/ts-plugin": minor
"astro-vscode": minor
---

Upgrades to the latest version of Volar, the underlying framework powering the Astro language server. This update should fix some of the recent issues regarding intellisense inside script tags.
4 changes: 1 addition & 3 deletions packages/astro-check/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,7 @@ export async function check(flags: Partial<Flags>): Promise<boolean | void> {
// Dynamically get the list of extensions to watch from the files already included in the project
const checkedExtensions = Array.from(
new Set(
checker.linter.language
.typescript!.projectHost.getScriptFileNames()
.map((fileName) => path.extname(fileName))
checker.linter.projectHost.getScriptFileNames().map((fileName) => path.extname(fileName))
)
);
createWatcher(workspaceRoot, checkedExtensions)
Expand Down
27 changes: 14 additions & 13 deletions packages/language-server/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -23,32 +23,33 @@
"dependencies": {
"@astrojs/compiler": "^2.7.0",
"@jridgewell/sourcemap-codec": "^1.4.15",
"@volar/kit": "~2.2.3",
"@volar/language-core": "~2.2.3",
"@volar/language-server": "~2.2.3",
"@volar/language-service": "~2.2.3",
"@volar/typescript": "~2.2.3",
"@volar/kit": "~2.4.0-alpha.15",
"@volar/language-core": "~2.4.0-alpha.15",
"@volar/language-server": "~2.4.0-alpha.15",
"@volar/language-service": "~2.4.0-alpha.15",
"@volar/typescript": "~2.4.0-alpha.15",
"fast-glob": "^3.2.12",
"volar-service-css": "0.0.45",
"volar-service-emmet": "0.0.45",
"volar-service-html": "0.0.45",
"volar-service-prettier": "0.0.45",
"volar-service-typescript": "0.0.45",
"volar-service-typescript-twoslash-queries": "0.0.45",
"muggle-string": "^0.4.1",
"volar-service-css": "volar-2.4",
"volar-service-emmet": "volar-2.4",
"volar-service-html": "volar-2.4",
"volar-service-prettier": "volar-2.4",
"volar-service-typescript": "volar-2.4",
"volar-service-typescript-twoslash-queries": "volar-2.4",
"vscode-html-languageservice": "^5.2.0",
"vscode-uri": "^3.0.8"
},
"devDependencies": {
"svelte": "^4.2.10",
"@astrojs/svelte": "^5.0.3",
"@astrojs/vue": "^4.0.8",
"@types/chai": "^4.3.5",
"@types/mocha": "^10.0.1",
"@types/node": "^18.17.8",
"@volar/test-utils": "~2.2.3",
"@volar/test-utils": "~2.4.0-alpha.15",
"astro": "^4.3.5",
"chai": "^4.3.7",
"mocha": "^10.2.0",
"svelte": "^4.2.10",
"tsx": "^3.12.7",
"typescript": "^5.2.2",
"vscode-languageserver-protocol": "^3.17.5",
Expand Down
21 changes: 21 additions & 0 deletions packages/language-server/src/buildMappings.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import type { Mapping } from '@volar/language-core';
import type { Segment } from 'muggle-string';

export function buildMappings<T>(chunks: Segment<T>[]) {
let length = 0;
const mappings: Mapping<T>[] = [];
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;
}
24 changes: 11 additions & 13 deletions packages/language-server/src/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import { pathToFileURL } from 'node:url';
import * as kit from '@volar/kit';
import { Diagnostic, DiagnosticSeverity } from '@volar/language-server';
import fg from 'fast-glob';
import { getLanguageModule } from './core/index.js';
import { getSvelteLanguageModule } from './core/svelte.js';
import { getVueLanguageModule } from './core/vue.js';
import { getAstroLanguagePlugin } from './core/index.js';
import { getSvelteLanguagePlugin } from './core/svelte.js';
import { getVueLanguagePlugin } from './core/vue.js';
import { getAstroInstall } from './utils.js';

import { create as createAstroService } from './plugins/astro.js';
Expand Down Expand Up @@ -62,9 +62,7 @@ export class AstroCheck {
| undefined;
}): Promise<CheckResult> {
let files = (
fileNames !== undefined
? fileNames
: this.linter.language.typescript!.projectHost.getScriptFileNames()
fileNames !== undefined ? fileNames : this.linter.projectHost.getScriptFileNames()
).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
Expand Down Expand Up @@ -106,7 +104,7 @@ export class AstroCheck {
console.info(errorText);
}

const fileSnapshot = this.linter.language.typescript!.projectHost.getScriptSnapshot(file);
const fileSnapshot = this.linter.projectHost.getScriptSnapshot(file);
const fileContent = fileSnapshot?.getText(0, fileSnapshot.getLength());

result.fileResult.push({
Expand Down Expand Up @@ -139,17 +137,17 @@ export class AstroCheck {
const tsconfigPath = this.getTsconfig();

const astroInstall = getAstroInstall([this.workspacePath]);
const languages = [
getLanguageModule(typeof astroInstall === 'string' ? undefined : astroInstall, this.ts),
getSvelteLanguageModule(),
getVueLanguageModule(),
const languagePlugins = [
getAstroLanguagePlugin(typeof astroInstall === 'string' ? undefined : astroInstall, this.ts),
getSvelteLanguagePlugin(),
getVueLanguagePlugin(),
];
const services = [...createTypeScriptServices(this.ts), createAstroService(this.ts)];

if (tsconfigPath) {
this.linter = kit.createTypeScriptChecker(languages, services, tsconfigPath);
this.linter = kit.createTypeScriptChecker(languagePlugins, services, tsconfigPath);
} else {
this.linter = kit.createTypeScriptInferredChecker(languages, services, () => {
this.linter = kit.createTypeScriptInferredChecker(languagePlugins, services, () => {
return fg.sync('**/*.astro', {
cwd: this.workspacePath,
ignore: ['node_modules'],
Expand Down
41 changes: 13 additions & 28 deletions packages/language-server/src/core/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,43 +2,37 @@ import * as path from 'node:path';
import type { DiagnosticMessage } from '@astrojs/compiler/types';
import {
type CodeMapping,
type ExtraServiceScript,
type LanguagePlugin,
type VirtualCode,
forEachEmbeddedCode,
} from '@volar/language-core';
import type { TypeScriptExtraServiceScript } from '@volar/typescript';
import type ts from 'typescript';
import type { HTMLDocument } from 'vscode-html-languageservice';
import { URI } from 'vscode-uri';
import type { URI } from 'vscode-uri';
import { type AstroInstall, getLanguageServerTypesDir } from '../utils.js';
import { astro2tsx } from './astro2tsx';
import { AstroMetadata, getAstroMetadata } from './parseAstro';
import { extractStylesheets } from './parseCSS';
import { parseHTML } from './parseHTML';
import { extractScriptTags } from './parseJS.js';

export function getLanguageModule(
export function getAstroLanguagePlugin(
astroInstall: AstroInstall | undefined,
ts: typeof import('typescript')
): LanguagePlugin<AstroVirtualCode> {
): LanguagePlugin<URI, AstroVirtualCode> {
return {
getLanguageId(scriptId) {
if (scriptId.endsWith('.astro')) {
getLanguageId(uri) {
if (uri.path.endsWith('.astro')) {
return 'astro';
}
},
createVirtualCode(scriptId, languageId, snapshot) {
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'astro') {
const fileName = scriptId.includes('://')
? URI.parse(scriptId).fsPath.replace(/\\/g, '/')
: scriptId;
const fileName = uri.fsPath.replace(/\\/g, '/');
return new AstroVirtualCode(fileName, snapshot);
}
},
updateVirtualCode(_scriptId, astroCode, snapshot) {
astroCode.update(snapshot);
return astroCode;
},
typescript: {
extraFileExtensions: [{ extension: 'astro', isMixedContent: true, scriptKind: 7 }],
getServiceScript(astroCode) {
Expand All @@ -54,7 +48,7 @@ export function getLanguageModule(
return undefined;
},
getExtraServiceScripts(fileName, astroCode) {
const result: ExtraServiceScript[] = [];
const result: TypeScriptExtraServiceScript[] = [];
for (const code of forEachEmbeddedCode(astroCode)) {
if (code.id.endsWith('.mjs') || code.id.endsWith('.mts')) {
const fileExtension = code.id.endsWith('.mjs') ? '.mjs' : '.mts';
Expand Down Expand Up @@ -150,19 +144,6 @@ export class AstroVirtualCode implements VirtualCode {
public fileName: string,
public snapshot: ts.IScriptSnapshot
) {
this.onSnapshotUpdated();
}

get hasCompilationErrors(): boolean {
return this.compilerDiagnostics.filter((diag) => diag.severity === 1).length > 0;
}

public update(newSnapshot: ts.IScriptSnapshot) {
this.snapshot = newSnapshot;
this.onSnapshotUpdated();
}

onSnapshotUpdated() {
this.mappings = [
{
sourceOffsets: [0],
Expand Down Expand Up @@ -220,4 +201,8 @@ export class AstroVirtualCode implements VirtualCode {
this.compilerDiagnostics.push(...tsx.diagnostics);
this.embeddedCodes.push(tsx.virtualCode);
}

get hasCompilationErrors(): boolean {
return this.compilerDiagnostics.filter((diag) => diag.severity === 1).length > 0;
}
}
10 changes: 3 additions & 7 deletions packages/language-server/src/core/parseCSS.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import type { ParentNode, ParseResult } from '@astrojs/compiler/types';
import { is } from '@astrojs/compiler/utils';
import {
type CodeInformation,
Segment,
type VirtualCode,
buildMappings,
toString,
} from '@volar/language-core';
import type { CodeInformation, VirtualCode } from '@volar/language-core';
import { Segment, toString } from 'muggle-string';
import type ts from 'typescript';
import type { HTMLDocument, Node } from 'vscode-html-languageservice';
import { buildMappings } from '../buildMappings.js';
import type { AttributeNodeWithPosition } from './compilerUtils.js';

export function extractStylesheets(
Expand Down
10 changes: 3 additions & 7 deletions packages/language-server/src/core/parseJS.ts
Original file line number Diff line number Diff line change
@@ -1,14 +1,10 @@
import type { ParentNode, ParseResult } from '@astrojs/compiler/types';
import { is } from '@astrojs/compiler/utils';
import {
type CodeInformation,
type Segment,
type VirtualCode,
buildMappings,
toString,
} from '@volar/language-core';
import type { CodeInformation, VirtualCode } from '@volar/language-core';
import { Segment, toString } from 'muggle-string';
import type ts from 'typescript';
import type { HTMLDocument, Node } from 'vscode-html-languageservice';
import { buildMappings } from '../buildMappings';

export function extractScriptTags(
snapshot: ts.IScriptSnapshot,
Expand Down
27 changes: 6 additions & 21 deletions packages/language-server/src/core/svelte.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,22 @@ import {
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import { URI } from 'vscode-uri';
import type { URI } from 'vscode-uri';
import { framework2tsx } from './utils.js';

export function getSvelteLanguageModule(): LanguagePlugin<SvelteVirtualCode> {
export function getSvelteLanguagePlugin(): LanguagePlugin<URI, SvelteVirtualCode> {
return {
getLanguageId(scriptId) {
if (scriptId.endsWith('.svelte')) {
getLanguageId(uri) {
if (uri.path.endsWith('.svelte')) {
return 'svelte';
}
},
createVirtualCode(scriptId, languageId, snapshot) {
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'svelte') {
const fileName = scriptId.includes('://')
? URI.parse(scriptId).fsPath.replace(/\\/g, '/')
: scriptId;
const fileName = uri.fsPath.replace(/\\/g, '/');
return new SvelteVirtualCode(fileName, snapshot);
}
},
updateVirtualCode(_scriptId, svelteCode, snapshot) {
svelteCode.update(snapshot);
return svelteCode;
},
typescript: {
extraFileExtensions: [{ extension: 'svelte', isMixedContent: true, scriptKind: 7 }],
getServiceScript(svelteCode) {
Expand Down Expand Up @@ -56,15 +50,6 @@ class SvelteVirtualCode implements VirtualCode {
public fileName: string,
public snapshot: ts.IScriptSnapshot
) {
this.onSnapshotUpdated();
}

public update(newSnapshot: ts.IScriptSnapshot) {
this.snapshot = newSnapshot;
this.onSnapshotUpdated();
}

private onSnapshotUpdated() {
this.mappings = [];

this.embeddedCodes = [];
Expand Down
27 changes: 6 additions & 21 deletions packages/language-server/src/core/vue.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,22 @@ import {
forEachEmbeddedCode,
} from '@volar/language-core';
import type ts from 'typescript';
import { URI } from 'vscode-uri';
import type { URI } from 'vscode-uri';
import { framework2tsx } from './utils.js';

export function getVueLanguageModule(): LanguagePlugin<VueVirtualCode> {
export function getVueLanguagePlugin(): LanguagePlugin<URI, VueVirtualCode> {
return {
getLanguageId(scriptId) {
if (scriptId.endsWith('.vue')) {
getLanguageId(uri) {
if (uri.path.endsWith('.vue')) {
return 'vue';
}
},
createVirtualCode(scriptId, languageId, snapshot) {
createVirtualCode(uri, languageId, snapshot) {
if (languageId === 'vue') {
const fileName = scriptId.includes('://')
? URI.parse(scriptId).fsPath.replace(/\\/g, '/')
: scriptId;
const fileName = uri.fsPath.replace(/\\/g, '/');
return new VueVirtualCode(fileName, snapshot);
}
},
updateVirtualCode(_scriptId, vueCode, snapshot) {
vueCode.update(snapshot);
return vueCode;
},
typescript: {
extraFileExtensions: [{ extension: 'vue', isMixedContent: true, scriptKind: 7 }],
getServiceScript(vueCode) {
Expand Down Expand Up @@ -56,15 +50,6 @@ class VueVirtualCode implements VirtualCode {
public fileName: string,
public snapshot: ts.IScriptSnapshot
) {
this.onSnapshotUpdated();
}

public update(newSnapshot: ts.IScriptSnapshot) {
this.snapshot = newSnapshot;
this.onSnapshotUpdated();
}

private onSnapshotUpdated() {
this.mappings = [];

this.embeddedCodes = [];
Expand Down
Loading

0 comments on commit b8a6af3

Please sign in to comment.