Skip to content

Commit

Permalink
feat: Support for generating virtual file from multiple sources (#2253)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Dec 24, 2022
1 parent d58a65f commit 2bb908d
Show file tree
Hide file tree
Showing 69 changed files with 1,105 additions and 1,067 deletions.
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

0 comments on commit 2bb908d

Please sign in to comment.