From 51f58dd8712c84cba73e12e69a9affa4516612a8 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Tue, 21 Nov 2023 07:44:50 +0800 Subject: [PATCH] sync https://github.com/volarjs/volar.js/pull/91 --- .../language-server/src/core/astro2tsx.ts | 59 ++++----- packages/language-server/src/core/index.ts | 118 +++++++++--------- packages/language-server/src/core/parseCSS.ts | 51 +++++--- .../language-server/src/core/parseHTML.ts | 16 +-- packages/language-server/src/core/parseJS.ts | 38 ++---- packages/language-server/src/core/svelte.ts | 24 ++-- packages/language-server/src/core/utils.ts | 12 +- packages/language-server/src/core/vue.ts | 24 ++-- .../src/languageServerPlugin.ts | 18 +-- packages/language-server/src/plugins/astro.ts | 4 +- packages/language-server/src/plugins/html.ts | 2 +- .../src/plugins/typescript-addons/index.ts | 2 +- .../src/plugins/typescript/index.ts | 30 +++-- packages/ts-plugin/src/astro2tsx.ts | 31 ++--- packages/ts-plugin/src/index.ts | 2 +- packages/ts-plugin/src/language.ts | 17 ++- 16 files changed, 213 insertions(+), 235 deletions(-) diff --git a/packages/language-server/src/core/astro2tsx.ts b/packages/language-server/src/core/astro2tsx.ts index 2658f603..94224f9d 100644 --- a/packages/language-server/src/core/astro2tsx.ts +++ b/packages/language-server/src/core/astro2tsx.ts @@ -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'; @@ -38,14 +38,14 @@ 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, }; } @@ -53,14 +53,14 @@ export function astro2tsx( 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'] = []; @@ -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({ @@ -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, diff --git a/packages/language-server/src/core/index.ts b/packages/language-server/src/core/index.ts index f9dd37a2..aa913568 100644 --- a/packages/language-server/src/core/index.ts +++ b/packages/language-server/src/core/index.ts @@ -1,8 +1,6 @@ import type { DiagnosticMessage, ParseResult } from '@astrojs/compiler/types'; import { - FileCapabilities, FileKind, - FileRangeCapabilities, type Language, type VirtualFile, } from '@volar/language-core'; @@ -21,83 +19,83 @@ export function getLanguageModule( ts: typeof import('typescript/lib/tsserverlibrary.js') ): Language { 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(); } @@ -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 @@ -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 ); @@ -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 ); diff --git a/packages/language-server/src/core/parseCSS.ts b/packages/language-server/src/core/parseCSS.ts index 8d9a79af..f0ead279 100644 --- a/packages/language-server/src/core/parseCSS.ts +++ b/packages/language-server/src/core/parseCSS.ts @@ -1,6 +1,6 @@ import type { ParentNode, ParseResult } from '@astrojs/compiler/types'; import { is } from '@astrojs/compiler/utils'; -import { FileKind, FileRangeCapabilities, VirtualFile } from '@volar/language-core'; +import { FileKind, CodeInformations, VirtualFile } from '@volar/language-core'; import * as SourceMap from '@volar/source-map'; import * as muggle from 'muggle-string'; import type ts from 'typescript/lib/tsserverlibrary'; @@ -8,27 +8,48 @@ import type { HTMLDocument, Node } from 'vscode-html-languageservice'; import type { AttributeNodeWithPosition } from './compilerUtils.js'; export function extractStylesheets( - fileName: string, + fileId: string, snapshot: ts.IScriptSnapshot, htmlDocument: HTMLDocument, ast: ParseResult['ast'] ): VirtualFile[] { const embeddedCSSFiles: VirtualFile[] = findEmbeddedStyles( - fileName, + fileId, snapshot, htmlDocument.roots ); const inlineStyles = findInlineStyles(ast); if (inlineStyles.length > 0) { - const codes: muggle.Segment[] = []; + const codes: muggle.Segment[] = []; for (const inlineStyle of inlineStyles) { codes.push('x { '); codes.push([ inlineStyle.value, undefined, inlineStyle.position.start.offset + 'style="'.length, - FileRangeCapabilities.full, + // disable all but only keep document colors + { + 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, + }, ]); codes.push(' }\n'); } @@ -37,15 +58,13 @@ export function extractStylesheets( const text = muggle.toString(codes); embeddedCSSFiles.push({ - fileName: fileName + '.inline.css', + id: fileId + '.inline.css', languageId: 'css', - codegenStacks: [], snapshot: { getText: (start, end) => text.substring(start, end), getLength: () => text.length, getChangeRange: () => undefined, }, - capabilities: { documentSymbol: true }, embeddedFiles: [], kind: FileKind.TextFile, mappings, @@ -60,7 +79,7 @@ export function extractStylesheets( * Embedded styles are styles that are defined in `