Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Nov 20, 2023
1 parent fc3c13c commit 51f58dd
Show file tree
Hide file tree
Showing 16 changed files with 213 additions and 235 deletions.
59 changes: 30 additions & 29 deletions packages/language-server/src/core/astro2tsx.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { convertToTSX } from '@astrojs/compiler/sync';
import type { ConvertToTSXOptions, TSXResult } from '@astrojs/compiler/types';
import { decode } from '@jridgewell/sourcemap-codec';
import { FileKind, FileRangeCapabilities, VirtualFile } from '@volar/language-core';
import { FileKind, CodeInformations, VirtualFile } from '@volar/language-core';
import { HTMLDocument, TextDocument } from 'vscode-html-languageservice';
import { patchTSX } from './utils.js';

Expand Down Expand Up @@ -38,29 +38,29 @@ function safeConvertToTSX(content: string, options: ConvertToTSXOptions) {

export function astro2tsx(
input: string,
fileName: string,
fileId: string,
ts: typeof import('typescript/lib/tsserverlibrary.js'),
htmlDocument: HTMLDocument
) {
const tsx = safeConvertToTSX(input, { filename: fileName });
const tsx = safeConvertToTSX(input, { filename: fileId });

return {
virtualFile: getVirtualFileTSX(input, tsx, fileName, ts, htmlDocument),
virtualFile: getVirtualFileTSX(input, tsx, fileId, ts, htmlDocument),
diagnostics: tsx.diagnostics,
};
}

function getVirtualFileTSX(
input: string,
tsx: TSXResult,
fileName: string,
fileId: string,
ts: typeof import('typescript/lib/tsserverlibrary.js'),
htmlDocument: HTMLDocument
): VirtualFile {
tsx.code = patchTSX(tsx.code, fileName);
tsx.code = patchTSX(tsx.code, fileId);
const v3Mappings = decode(tsx.map.mappings);
const sourcedDoc = TextDocument.create(fileName, 'astro', 0, input);
const genDoc = TextDocument.create(fileName + '.tsx', 'typescriptreact', 0, tsx.code);
const sourcedDoc = TextDocument.create(fileId, 'astro', 0, input);
const genDoc = TextDocument.create(fileId + '.tsx', 'typescriptreact', 0, tsx.code);

const mappings: VirtualFile['mappings'] = [];

Expand Down Expand Up @@ -102,19 +102,29 @@ function getVirtualFileTSX(
// Disable features inside script tags. This is a bit annoying to do, I wonder if maybe leaving script tags
// unmapped would be better.
const node = htmlDocument.findNodeAt(current.sourceOffset);
const rangeCapabilities: FileRangeCapabilities =
const rangeCapabilities: CodeInformations =
node.tag !== 'script'
? FileRangeCapabilities.full
? {}
: {
completion: false,
definition: false,
diagnostic: false,
displayWithLink: false,
hover: false,
references: false,
referencesCodeLens: false,
rename: false,
semanticTokens: false,
diagnostics: false,
renameEdits: false,
formattingEdits: false,
definitions: false,
references: false,
foldingRanges: false,
inlayHints: false,
codeActions: false,
symbols: false,
selectionRanges: false,
linkedEditingRanges: false,
colors: false,
autoInserts: false,
codeLenses: false,
highlights: false,
links: false,
semanticTokens: false,
hover: false,
signatureHelps: false,
};

mappings.push({
Expand Down Expand Up @@ -146,18 +156,9 @@ function getVirtualFileTSX(
}

return {
fileName: fileName + '.tsx',
id: fileId + '.tsx',
languageId: 'typescriptreact',
kind: FileKind.TypeScriptHostFile,
capabilities: {
codeAction: true,
documentFormatting: false,
diagnostic: true,
documentSymbol: true,
inlayHint: true,
foldingRange: true,
},
codegenStacks: [],
snapshot: {
getText: (start, end) => tsx.code.substring(start, end),
getLength: () => tsx.code.length,
Expand Down
118 changes: 58 additions & 60 deletions packages/language-server/src/core/index.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
import type { DiagnosticMessage, ParseResult } from '@astrojs/compiler/types';
import {
FileCapabilities,
FileKind,
FileRangeCapabilities,
type Language,
type VirtualFile,
} from '@volar/language-core';
Expand All @@ -21,83 +19,83 @@ export function getLanguageModule(
ts: typeof import('typescript/lib/tsserverlibrary.js')
): Language<AstroFile> {
return {
createVirtualFile(fileName, snapshot) {
if (fileName.endsWith('.astro')) {
return new AstroFile(fileName, snapshot, ts);
createVirtualFile(id, languageId, snapshot) {
if (languageId === 'astro') {
return new AstroFile(id, snapshot, ts);
}
},
updateVirtualFile(astroFile, snapshot) {
astroFile.update(snapshot);
},
resolveTypeScriptProjectHost(host) {
return {
...host,
resolveModuleName(moduleName, impliedNodeFormat) {
if (
impliedNodeFormat === ts.ModuleKind.ESNext &&
(moduleName.endsWith('.astro') ||
moduleName.endsWith('.vue') ||
moduleName.endsWith('.svelte'))
) {
return `${moduleName}.js`;
}
return host.resolveModuleName?.(moduleName, impliedNodeFormat) ?? moduleName;
},
getScriptFileNames() {
const fileNames = host.getScriptFileNames();
return [
...fileNames,
...(astroInstall
? ['./env.d.ts', './astro-jsx.d.ts'].map((filePath) =>
typescript: {
resolveModuleName(moduleName, impliedNodeFormat) {
if (
impliedNodeFormat === ts.ModuleKind.ESNext &&
(moduleName.endsWith('.astro') ||
moduleName.endsWith('.vue') ||
moduleName.endsWith('.svelte'))
) {
return `${moduleName}.js`;
}
},
resolveLanguageServiceHost(host) {
return {
...host,
getScriptFileNames() {
const fileNames = host.getScriptFileNames();
return [
...fileNames,
...(astroInstall
? ['./env.d.ts', './astro-jsx.d.ts'].map((filePath) =>
ts.sys.resolvePath(path.resolve(astroInstall.path, filePath))
)
: []),
];
},
getCompilationSettings() {
const baseCompilationSettings = host.getCompilationSettings();
return {
...baseCompilationSettings,
module: ts.ModuleKind.ESNext ?? 99,
target: ts.ScriptTarget.ESNext ?? 99,
jsx: ts.JsxEmit.Preserve ?? 1,
jsxImportSource: undefined,
jsxFactory: 'astroHTML',
resolveJsonModule: true,
allowJs: true,
isolatedModules: true,
moduleResolution:
baseCompilationSettings.moduleResolution === ts.ModuleResolutionKind.Classic ||
!baseCompilationSettings.moduleResolution
? ts.ModuleResolutionKind.Node10
: baseCompilationSettings.moduleResolution,
};
},
};
)
: []),
];
},
getCompilationSettings() {
const baseCompilationSettings = host.getCompilationSettings();
return {
...baseCompilationSettings,
module: ts.ModuleKind.ESNext ?? 99,
target: ts.ScriptTarget.ESNext ?? 99,
jsx: ts.JsxEmit.Preserve ?? 1,
jsxImportSource: undefined,
jsxFactory: 'astroHTML',
resolveJsonModule: true,
allowJs: true,
isolatedModules: true,
moduleResolution:
baseCompilationSettings.moduleResolution === ts.ModuleResolutionKind.Classic ||
!baseCompilationSettings.moduleResolution
? ts.ModuleResolutionKind.Node10
: baseCompilationSettings.moduleResolution,
};
},
};
},
},
};
}

export class AstroFile implements VirtualFile {
kind = FileKind.TextFile;
capabilities = FileCapabilities.full;

fileName: string;
id: string;
languageId = 'astro';
mappings!: VirtualFile['mappings'];
embeddedFiles!: VirtualFile['embeddedFiles'];
astroMeta!: ParseResult & { frontmatter: FrontmatterStatus };
compilerDiagnostics!: DiagnosticMessage[];
htmlDocument!: HTMLDocument;
scriptFiles!: string[];
scriptFileIds!: string[];
codegenStacks = [];

constructor(
public sourceFileName: string,
public sourceFileId: string,
public snapshot: ts.IScriptSnapshot,
private readonly ts: typeof import('typescript/lib/tsserverlibrary.js')
) {
this.fileName = sourceFileName;
this.id = sourceFileId;
this.onSnapshotUpdated();
}

Expand All @@ -115,14 +113,14 @@ export class AstroFile implements VirtualFile {
{
sourceRange: [0, this.snapshot.getLength()],
generatedRange: [0, this.snapshot.getLength()],
data: FileRangeCapabilities.full,
data: {},
},
];

this.astroMeta = getAstroMetadata(this.snapshot.getText(0, this.snapshot.getLength()));

const { htmlDocument, virtualFile: htmlVirtualFile } = parseHTML(
this.fileName,
this.id,
this.snapshot,
this.astroMeta.frontmatter.status === 'closed'
? this.astroMeta.frontmatter.position.end.offset
Expand All @@ -131,16 +129,16 @@ export class AstroFile implements VirtualFile {
this.htmlDocument = htmlDocument;

const scriptTags = extractScriptTags(
this.fileName,
this.id,
this.snapshot,
htmlDocument,
this.astroMeta.ast
);

this.scriptFiles = scriptTags.map((scriptTag) => scriptTag.fileName);
this.scriptFileIds = scriptTags.map((scriptTag) => scriptTag.id);

htmlVirtualFile.embeddedFiles.push(
...extractStylesheets(this.fileName, this.snapshot, htmlDocument, this.astroMeta.ast),
...extractStylesheets(this.id, this.snapshot, htmlDocument, this.astroMeta.ast),
...scriptTags
);

Expand All @@ -149,7 +147,7 @@ export class AstroFile implements VirtualFile {

const tsx = astro2tsx(
this.snapshot.getText(0, this.snapshot.getLength()),
this.fileName,
this.id,
this.ts,
htmlDocument
);
Expand Down
Loading

0 comments on commit 51f58dd

Please sign in to comment.