Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support for generating virtual file from multiple sources #2253

Merged
merged 10 commits into from Dec 24, 2022
22 changes: 11 additions & 11 deletions examples/angular-language-core/src/modules/html.ts
@@ -1,4 +1,4 @@
import { DocumentCapabilities, EmbeddedFileKind, LanguageModule, VirtualFile } from '@volar/language-core';
import { DocumentCapabilities, VirtualFileKind, LanguageModule, VirtualFile } from '@volar/language-core';
import type { TmplAstNode, TmplAstTemplate, ParsedTemplate, ParseSourceSpan } from '@angular/compiler';
import { Codegen } from './ts';
import type * as ts from 'typescript/lib/tsserverlibrary';
Expand All @@ -11,9 +11,9 @@ export class HTMLTemplateFile implements VirtualFile {
public capabilities: DocumentCapabilities = {
diagnostic: true,
};
public kind = EmbeddedFileKind.TextFile;
public kind = VirtualFileKind.TextFile;
public mappings: VirtualFile['mappings'] = [];
public embeddeds: VirtualFile['embeddeds'] = [];
public embeddedFiles: VirtualFile['embeddedFiles'] = [];
public parsed: ParsedTemplate;

constructor(
Expand All @@ -34,10 +34,10 @@ export class HTMLTemplateFile implements VirtualFile {
sourceRange: [0, this.text.length],
},
];
this.embeddeds = [
this.embeddedFiles = [
{
fileName: fileName + '.__template.ts',
text: generated.codegen.text,
snapshot: this.ts.ScriptSnapshot.fromString(generated.codegen.text),
capabilities: {
diagnostic: true,
foldingRange: false,
Expand All @@ -46,9 +46,9 @@ export class HTMLTemplateFile implements VirtualFile {
codeAction: false,
inlayHint: true,
},
kind: EmbeddedFileKind.TypeScriptHostFile,
kind: VirtualFileKind.TypeScriptHostFile,
mappings: generated.codegen.mappings,
embeddeds: [],
embeddedFiles: [],
},
];
this.parsed = generated.parsed;
Expand All @@ -66,20 +66,20 @@ export class HTMLTemplateFile implements VirtualFile {
sourceRange: [0, this.text.length],
},
];
this.embeddeds[0].text = generated.codegen.text;
this.embeddeds[0].mappings = generated.codegen.mappings;
this.embeddedFiles[0].snapshot = this.ts.ScriptSnapshot.fromString(generated.codegen.text);
this.embeddedFiles[0].mappings = generated.codegen.mappings;
this.parsed = generated.parsed;
}
}

export function createHtmlLanguageModule(ts: typeof import('typescript/lib/tsserverlibrary')): LanguageModule<HTMLTemplateFile> {
return {
createSourceFile(fileName, snapshot) {
createFile(fileName, snapshot) {
if (fileName.endsWith('.html')) {
return new HTMLTemplateFile(ts, fileName, snapshot);
}
},
updateSourceFile(sourceFile, snapshot) {
updateFile(sourceFile, snapshot) {
sourceFile.update(snapshot);
},
};
Expand Down
12 changes: 6 additions & 6 deletions examples/angular-language-core/src/modules/ts.ts
@@ -1,4 +1,4 @@
import { LanguageModule, VirtualFile, EmbeddedFileKind, PositionCapabilities } from '@volar/language-core';
import { LanguageModule, VirtualFile, VirtualFileKind, PositionCapabilities } from '@volar/language-core';
import type * as ts from 'typescript/lib/tsserverlibrary';
import * as path from 'path';
import type { Mapping } from '@volar/source-map';
Expand All @@ -8,7 +8,7 @@ export function createTsLanguageModule(
) {

const languageModule: LanguageModule<VirtualFile & { ast: ts.SourceFile, snapshot: ts.IScriptSnapshot; }> = {
createSourceFile(fileName, snapshot) {
createFile(fileName, snapshot) {
if (fileName.endsWith('.ts')) {
const text = snapshot.getText(0, snapshot.getLength());
const ast = ts.createSourceFile(fileName, text, ts.ScriptTarget.Latest);
Expand All @@ -26,13 +26,13 @@ export function createTsLanguageModule(
codeAction: true,
inlayHint: true,
},
kind: EmbeddedFileKind.TypeScriptHostFile,
kind: VirtualFileKind.TypeScriptHostFile,
mappings: virtualFile.mappings,
embeddeds: [],
embeddedFiles: [],
};
}
},
updateSourceFile(sourceFile, snapshot) {
updateFile(sourceFile, snapshot) {
const text = snapshot.getText(0, snapshot.getLength());
const change = snapshot.getChangeRange(sourceFile.snapshot);

Expand All @@ -43,7 +43,7 @@ export function createTsLanguageModule(
sourceFile.snapshot = snapshot;

const gen = createVirtualFile(sourceFile.ast);
sourceFile.text = gen.text;
sourceFile.snapshot = ts.ScriptSnapshot.fromString(gen.text);
sourceFile.mappings = gen.mappings;
},
};
Expand Down
7 changes: 3 additions & 4 deletions examples/angular-language-server/src/index.ts
@@ -1,7 +1,7 @@
import { createTsLanguageModule, createHtmlLanguageModule, HTMLTemplateFile } from '@volar-examples/angular-language-core';
import createTsPlugin from '@volar-plugins/typescript';
import { createLanguageServer, LanguageServerPlugin } from '@volar/language-server/node';
import type { LanguageServicePlugin, SourceFileDocuments, Diagnostic } from '@volar/language-service';
import type { LanguageServicePlugin, DocumentsAndSourceMaps, Diagnostic } from '@volar/language-service';

const plugin: LanguageServerPlugin = () => ({
extraFileExtensions: [{ extension: 'html', isMixedContent: true, scriptKind: 7 }],
Expand Down Expand Up @@ -34,15 +34,15 @@ const plugin: LanguageServerPlugin = () => ({
},
});

function createNgTemplateLsPlugin(docs: SourceFileDocuments): LanguageServicePlugin {
function createNgTemplateLsPlugin(docs: DocumentsAndSourceMaps): LanguageServicePlugin {

return {

validation: {

onSyntactic(document) {

const file = docs.get(document.uri)?.file;
const file = docs.getRootFileBySourceFileUri(document.uri);

if (file instanceof HTMLTemplateFile) {
return (file.parsed.errors ?? []).map<Diagnostic>(error => ({
Expand All @@ -61,4 +61,3 @@ function createNgTemplateLsPlugin(docs: SourceFileDocuments): LanguageServicePlu
}

createLanguageServer([plugin]);

33 changes: 21 additions & 12 deletions examples/svelte-language-core/src/index.ts
@@ -1,20 +1,19 @@
import { decode } from '@jridgewell/sourcemap-codec';
import { VirtualFile, EmbeddedFileKind, LanguageModule } from '@volar/language-core';
import { VirtualFile, VirtualFileKind, LanguageModule } from '@volar/language-core';
import { svelte2tsx } from 'svelte2tsx';
import { TextDocument } from 'vscode-languageserver-textdocument';
import { URI } from 'vscode-uri';

export * from '@volar/language-core';

export const languageModule: LanguageModule = {
createSourceFile(fileName, snapshot) {
createFile(fileName, snapshot) {
if (fileName.endsWith('.svelte')) {
const text = snapshot.getText(0, snapshot.getLength());
return {
fileName,
text,
kind: EmbeddedFileKind.TextFile,
embeddeds: getEmbeddeds(fileName, text),
snapshot,
kind: VirtualFileKind.TextFile,
embeddedFiles: getEmbeddeds(fileName, snapshot.getText(0, snapshot.getLength())),
capabilities: {
diagnostic: true,
foldingRange: true,
Expand All @@ -27,9 +26,9 @@ export const languageModule: LanguageModule = {
};
}
},
updateSourceFile(sourceFile, snapshot) {
sourceFile.text = snapshot.getText(0, snapshot.getLength());
sourceFile.embeddeds = getEmbeddeds(sourceFile.fileName, sourceFile.text);
updateFile(sourceFile, snapshot) {
sourceFile.snapshot = snapshot;
sourceFile.embeddedFiles = getEmbeddeds(sourceFile.fileName, sourceFile.snapshot.getText(0, sourceFile.snapshot.getLength()));
},
};

Expand Down Expand Up @@ -108,8 +107,18 @@ function getEmbeddeds(fileName: string, text: string) {

embeddeds.push({
fileName: fileName + '.ts',
text: tsx.code,
kind: EmbeddedFileKind.TypeScriptHostFile,
snapshot: {
getText(start, end) {
return tsx.code.substring(start, end);
},
getLength() {
return tsx.code.length;
},
getChangeRange() {
return undefined;
},
},
kind: VirtualFileKind.TypeScriptHostFile,
capabilities: {
diagnostic: true,
foldingRange: false,
Expand All @@ -119,7 +128,7 @@ function getEmbeddeds(fileName: string, text: string) {
documentFormatting: false,
},
mappings: mappings,
embeddeds: [],
embeddedFiles: [],
});

return embeddeds;
Expand Down
4 changes: 2 additions & 2 deletions examples/vue-and-svelte-language-server/src/index.ts
Expand Up @@ -43,12 +43,12 @@ const plugin: LanguageServerPlugin<LanguageServerInitializationOptions, vue.Lang
getLanguageModules(ts, env) {
const vueLanguagePlugins = vue.getDefaultVueLanguagePlugins(ts, shared.getPathOfUri(env.rootUri.toString()), {}, {}, []);
const vueLanguageModule: LanguageModule = {
createSourceFile(fileName, snapshot) {
createFile(fileName, snapshot) {
if (fileName.endsWith('.vue')) {
return new vue.VueFile(fileName, snapshot, ts, vueLanguagePlugins);
}
},
updateSourceFile(sourceFile: vue.VueFile, snapshot) {
updateFile(sourceFile: vue.VueFile, snapshot) {
sourceFile.update(snapshot);
},
};
Expand Down