Skip to content

Commit

Permalink
sync volarjs/volar.js#86 changes [skip ci]
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Nov 17, 2023
1 parent d10b0e5 commit 1c3a7b5
Show file tree
Hide file tree
Showing 19 changed files with 204 additions and 135 deletions.
10 changes: 7 additions & 3 deletions packages/component-meta/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,8 +153,12 @@ export function baseCreate(
host.getCompilationSettings(),
vueCompilerOptions,
);
const project = vue.createTypeScriptProject(host, vueLanguages, vue.resolveCommonLanguageId);
const tsLsHost = createLanguageServiceHost(project.typescript!.projectHost, project.fileProvider, ts, ts.sys);
const fileNameResolutionHost = {
fileNameToId: (fileName: string) => fileName,
idToFileName: (id: string) => id,
};
const project = vue.createTypeScriptProject(host, vueLanguages, fileNameResolutionHost.fileNameToId, vue.resolveCommonLanguageId);
const tsLsHost = createLanguageServiceHost(project.typescript!.projectHost, project.fileProvider, fileNameResolutionHost, ts, ts.sys);
const tsLs = ts.createLanguageService(tsLsHost);

decorateLanguageService(project.fileProvider, tsLs, false);
Expand Down Expand Up @@ -297,7 +301,7 @@ ${vueCompilerOptions.target < 3 ? vue2TypeHelpersCode : typeHelpersCode}
const printer = ts.createPrinter(checkerOptions.printer);
const snapshot = host.getScriptSnapshot(componentPath)!;

const vueSourceFile = project.fileProvider.getSource(componentPath)?.root;
const vueSourceFile = project.fileProvider.getSourceFile(componentPath)?.root;
const vueDefaults = vueSourceFile && exportName === 'default'
? (vueSourceFile instanceof vue.VueFile ? readVueComponentDefaultProps(vueSourceFile, printer, ts, vueCompilerOptions) : {})
: {};
Expand Down
15 changes: 6 additions & 9 deletions packages/language-core/src/languageModule.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,18 +68,15 @@ export function createVueLanguage(
}

return {
createVirtualFile(fileName, snapshot, languageId) {
if (
(languageId && allowLanguageIds.has(languageId))
|| (!languageId && vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext)))
) {
if (fileRegistry.has(fileName)) {
const reusedVueFile = fileRegistry.get(fileName)!;
createVirtualFile(id, languageId, snapshot) {
if (allowLanguageIds.has(languageId)) {
if (fileRegistry.has(id)) {
const reusedVueFile = fileRegistry.get(id)!;
reusedVueFile.update(snapshot);
return reusedVueFile;
}
const vueFile = new VueFile(fileName, languageId, snapshot, vueCompilerOptions, plugins, ts, codegenStack);
fileRegistry.set(fileName, vueFile);
const vueFile = new VueFile(id, languageId, snapshot, vueCompilerOptions, plugins, ts, codegenStack);
fileRegistry.set(id, vueFile);
return vueFile;
}
},
Expand Down
23 changes: 16 additions & 7 deletions packages/language-core/src/virtualFile/computedFiles.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import { VirtualFile, resolveCommonLanguageId } from '@volar/language-core';
import { buildMappings, buildStacks, toString } from '@volar/source-map';
import { computed } from 'computeds';
import * as muggle from 'muggle-string';
import type * as ts from 'typescript/lib/tsserverlibrary';
import type { Sfc, SfcBlock, VueLanguagePlugin } from '../types';
import { VueEmbeddedFile } from './embeddedFile';
import { computed } from 'computeds';

export function computedFiles(
plugins: ReturnType<VueLanguagePlugin>[],
Expand Down Expand Up @@ -50,8 +50,11 @@ export function computedFiles(

for (const { file, snapshot, mappings, codegenStacks } of remain) {
embeddedFiles.push({
...file,
id: file.fileName,
languageId: resolveCommonLanguageId(file.fileName),
kind: file.kind,
capabilities: file.capabilities,
mirrorBehaviorMappings: file.mirrorBehaviorMappings,
snapshot,
mappings,
codegenStacks,
Expand All @@ -67,8 +70,11 @@ export function computedFiles(
const { file, snapshot, mappings, codegenStacks } = remain[i];
if (!file.parentFileName) {
embeddedFiles.push({
...file,
id: file.fileName,
languageId: resolveCommonLanguageId(file.fileName),
kind: file.kind,
capabilities: file.capabilities,
mirrorBehaviorMappings: file.mirrorBehaviorMappings,
snapshot,
mappings,
codegenStacks,
Expand All @@ -80,8 +86,11 @@ export function computedFiles(
const parent = findParentStructure(file.parentFileName, embeddedFiles);
if (parent) {
parent.embeddedFiles.push({
...file,
id: file.fileName,
languageId: resolveCommonLanguageId(file.fileName),
kind: file.kind,
capabilities: file.capabilities,
mirrorBehaviorMappings: file.mirrorBehaviorMappings,
snapshot,
mappings,
codegenStacks,
Expand All @@ -92,12 +101,12 @@ export function computedFiles(
}
}
}
function findParentStructure(fileName: string, current: VirtualFile[]): VirtualFile | undefined {
function findParentStructure(id: string, current: VirtualFile[]): VirtualFile | undefined {
for (const child of current) {
if (child.fileName === fileName) {
if (child.id === id) {
return child;
}
let parent = findParentStructure(fileName, child.embeddedFiles);
let parent = findParentStructure(id, child.embeddedFiles);
if (parent) {
return parent;
}
Expand Down
18 changes: 9 additions & 9 deletions packages/language-core/src/virtualFile/vueFile.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,10 @@ export class VueFile implements VirtualFile {

// computeds

getVueSfc = computedVueSfc(this.plugins, this.fileName, () => this._snapshot());
sfc = computedSfc(this.ts, this.plugins, this.fileName, () => this._snapshot(), this.getVueSfc);
getVueSfc = computedVueSfc(this.plugins, this.id, () => this._snapshot());
sfc = computedSfc(this.ts, this.plugins, this.id, () => this._snapshot(), this.getVueSfc);
getMappings = computedMappings(() => this._snapshot(), this.sfc);
getEmbeddedFiles = computedFiles(this.plugins, this.fileName, this.sfc, this.codegenStack);
getEmbeddedFiles = computedFiles(this.plugins, this.id, this.sfc, this.codegenStack);

// others

Expand All @@ -31,14 +31,14 @@ export class VueFile implements VirtualFile {
get embeddedFiles() {
return this.getEmbeddedFiles();
}
get mainScriptName() {
let res: string = '';
get mainTsFile() {
let result: VirtualFile | undefined;
forEachEmbeddedFile(this, file => {
if (file.kind === FileKind.TypeScriptHostFile && file.fileName.replace(this.fileName, '').match(jsxReg)) {
res = file.fileName;
if (file.kind === FileKind.TypeScriptHostFile && file.id.substring(this.id.length).match(jsxReg)) {
result = file;
}
});
return res;
return result;
}
get snapshot() {
return this._snapshot();
Expand All @@ -48,7 +48,7 @@ export class VueFile implements VirtualFile {
}

constructor(
public fileName: string,
public id: string,
public languageId: string,
public initSnapshot: ts.IScriptSnapshot,
public vueCompilerOptions: VueCompilerOptions,
Expand Down
32 changes: 16 additions & 16 deletions packages/language-service/src/helpers.ts
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
import * as vue from '@vue/language-core';
import type { CompilerDOM } from '@vue/language-core';
import * as embedded from '@volar/language-core';
import { computed } from 'computeds';
import type { CompilerDOM } from '@vue/language-core';
import * as vue from '@vue/language-core';
import { sharedTypes } from '@vue/language-core';
import { camelize, capitalize } from '@vue/shared';

import { computed } from 'computeds';
import type * as ts from 'typescript/lib/tsserverlibrary';
import type { ServiceEnvironment } from './types';

export function getPropsByTag(
ts: typeof import('typescript/lib/tsserverlibrary'),
tsLs: ts.LanguageService,
env: ServiceEnvironment,
sourceFile: embedded.VirtualFile,
tag: string,
vueCompilerOptions: vue.VueCompilerOptions,
requiredOnly = false,
) {

const checker = tsLs.getProgram()!.getTypeChecker();
const components = getVariableType(ts, tsLs, sourceFile, '__VLS_components');
const components = getVariableType(ts, tsLs, env, sourceFile, '__VLS_components');
if (!components)
return [];

Expand Down Expand Up @@ -83,13 +84,14 @@ export function getPropsByTag(
export function getEventsOfTag(
ts: typeof import('typescript/lib/tsserverlibrary'),
tsLs: ts.LanguageService,
env: ServiceEnvironment,
sourceFile: embedded.VirtualFile,
tag: string,
vueCompilerOptions: vue.VueCompilerOptions,
) {

const checker = tsLs.getProgram()!.getTypeChecker();
const components = getVariableType(ts, tsLs, sourceFile, '__VLS_components');
const components = getVariableType(ts, tsLs, env, sourceFile, '__VLS_components');
if (!components)
return [];

Expand Down Expand Up @@ -149,9 +151,10 @@ export function getEventsOfTag(
export function getTemplateCtx(
ts: typeof import('typescript/lib/tsserverlibrary'),
tsLs: ts.LanguageService,
env: ServiceEnvironment,
sourceFile: embedded.VirtualFile,
) {
return getVariableType(ts, tsLs, sourceFile, '__VLS_ctx')
return getVariableType(ts, tsLs, env, sourceFile, '__VLS_ctx')
?.type
?.getProperties()
.map(c => c.name);
Expand All @@ -160,10 +163,11 @@ export function getTemplateCtx(
export function getComponentNames(
ts: typeof import('typescript/lib/tsserverlibrary'),
tsLs: ts.LanguageService,
env: ServiceEnvironment,
sourceFile: embedded.VirtualFile,
vueCompilerOptions: vue.VueCompilerOptions,
) {
return getVariableType(ts, tsLs, sourceFile, '__VLS_components')
return getVariableType(ts, tsLs, env, sourceFile, '__VLS_components')
?.type
?.getProperties()
.map(c => c.name)
Expand Down Expand Up @@ -207,6 +211,7 @@ export function getElementAttrs(
function getVariableType(
ts: typeof import('typescript/lib/tsserverlibrary'),
tsLs: ts.LanguageService,
env: ServiceEnvironment,
sourceFile: embedded.VirtualFile,
name: string,
) {
Expand All @@ -215,16 +220,11 @@ function getVariableType(
return;
}

let file: embedded.VirtualFile | undefined;
let tsSourceFile: ts.SourceFile | undefined;
const file = sourceFile.mainTsFile;

embedded.forEachEmbeddedFile(sourceFile, embedded => {
if (embedded.fileName === sourceFile.mainScriptName) {
file = embedded;
}
});
let tsSourceFile: ts.SourceFile | undefined;

if (file && (tsSourceFile = tsLs.getProgram()?.getSourceFile(file.fileName))) {
if (file && (tsSourceFile = tsLs.getProgram()?.getSourceFile(env.uriToFileName(file.id)))) {

const node = searchVariableDeclarationNode(ts, tsSourceFile, name);
const checker = tsLs.getProgram()?.getTypeChecker();
Expand Down
2 changes: 1 addition & 1 deletion packages/language-service/src/ideFeatures/dragImport.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ export function getDragImportEdits(

const newName = capitalize(camelize(baseName));
const document = ctx!.getTextDocument(uri)!;
const [vueFile] = ctx!.documents.getVirtualFileByUri(document.uri) as [VueFile, any];
const [vueFile] = ctx!.project.fileProvider.getVirtualFile(document.uri) as [VueFile, any];
const { sfc } = vueFile;
const script = sfc.scriptSetup ?? sfc.script;

Expand Down
18 changes: 9 additions & 9 deletions packages/language-service/src/ideFeatures/nameCasing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export async function convertTagName(
vueCompilerOptions: VueCompilerOptions,
) {

const rootFile = context.documents.getSourceByUri(uri)?.root;
const rootFile = context.project.fileProvider.getSourceFile(uri)?.root;
if (!(rootFile instanceof VueFile))
return;

Expand All @@ -23,9 +23,9 @@ export async function convertTagName(

const languageService = context.inject('typescript/languageService');
const template = desc.template;
const document = context.documents.getDocumentByFileName(rootFile.snapshot, rootFile.fileName, rootFile.languageId);
const document = context.documents.getDocumentByUri(rootFile.id, rootFile.languageId, rootFile.snapshot);
const edits: vscode.TextEdit[] = [];
const components = getComponentNames(ts, languageService, rootFile, vueCompilerOptions);
const components = getComponentNames(ts, languageService, context.env, rootFile, vueCompilerOptions);
const tags = getTemplateTagsAndAttrs(rootFile);

for (const [tagName, { offsets }] of tags) {
Expand Down Expand Up @@ -56,7 +56,7 @@ export async function convertAttrName(
vueCompilerOptions: VueCompilerOptions,
) {

const rootFile = context.documents.getSourceByUri(uri)?.root;
const rootFile = context.project.fileProvider.getSourceFile(uri)?.root;
if (!(rootFile instanceof VueFile))
return;

Expand All @@ -66,15 +66,15 @@ export async function convertAttrName(

const languageService = context.inject('typescript/languageService');
const template = desc.template;
const document = context.documents.getDocumentByFileName(rootFile.snapshot, rootFile.fileName, rootFile.languageId);
const document = context.documents.getDocumentByUri(rootFile.id, rootFile.languageId, rootFile.snapshot);
const edits: vscode.TextEdit[] = [];
const components = getComponentNames(ts, languageService, rootFile, vueCompilerOptions);
const components = getComponentNames(ts, languageService, context.env, rootFile, vueCompilerOptions);
const tags = getTemplateTagsAndAttrs(rootFile);

for (const [tagName, { attrs }] of tags) {
const componentName = components.find(component => component === tagName || hyphenateTag(component) === tagName);
if (componentName) {
const props = getPropsByTag(ts, languageService, rootFile, componentName, vueCompilerOptions);
const props = getPropsByTag(ts, languageService, context.env, rootFile, componentName, vueCompilerOptions);
for (const [attrName, { offsets }] of attrs) {
const propName = props.find(prop => prop === attrName || hyphenateAttr(prop) === attrName);
if (propName) {
Expand Down Expand Up @@ -128,7 +128,7 @@ export function detect(
attr: AttrNameCasing[],
} {

const rootFile = context.documents.getSourceByUri(uri)?.root;
const rootFile = context.project.fileProvider.getSourceFile(uri)?.root;
if (!(rootFile instanceof VueFile)) {
return {
tag: [],
Expand Down Expand Up @@ -169,7 +169,7 @@ export function detect(
}
function getTagNameCase(file: VirtualFile): TagNameCasing[] {

const components = getComponentNames(ts, languageService, file, vueCompilerOptions);
const components = getComponentNames(ts, languageService, context.env, file, vueCompilerOptions);
const tagNames = getTemplateTagsAndAttrs(file);
const result: TagNameCasing[] = [];

Expand Down
39 changes: 23 additions & 16 deletions packages/language-service/src/languageService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -89,19 +89,26 @@ export function resolveServices(
// handle component auto-import patch
let casing: Awaited<ReturnType<typeof getNameCasing>> | undefined;

for (const [_, map] of ctx.documents.getMapsByVirtualFileUri(document.uri)) {
const virtualFile = ctx.documents.getSourceByUri(map.sourceFileDocument.uri)?.root;
if (virtualFile instanceof VueFile) {
const isAutoImport = !!map.toSourcePosition(position, data => typeof data.completion === 'object' && !!data.completion.autoImportOnly);
if (isAutoImport) {
const source = ctx.documents.getVirtualFileByUri(document.uri)[1];
for (const item of result.items) {
item.data.__isComponentAutoImport = true;
}
const [virtualFile, sourceFile] = ctx.project.fileProvider.getVirtualFile(document.uri);

if (virtualFile && sourceFile) {

for (const map of ctx.documents.getMapsByVirtualFile(virtualFile)) {

const sourceVirtualFile = ctx.project.fileProvider.getSourceFile(map.sourceFileDocument.uri)?.root;

if (sourceVirtualFile instanceof VueFile) {

const isAutoImport = !!map.toSourcePosition(position, data => typeof data.completion === 'object' && !!data.completion.autoImportOnly);
if (isAutoImport) {

for (const item of result.items) {
item.data.__isComponentAutoImport = true;
}

// fix #2458
casing ??= await getNameCasing(ts, ctx, sourceFile.id, vueCompilerOptions);

// fix #2458
if (source) {
casing ??= await getNameCasing(ts, ctx, ctx.env.fileNameToUri(source.fileName), vueCompilerOptions);
if (casing.tag === TagNameCasing.Kebab) {
for (const item of result.items) {
item.filterText = hyphenateTag(item.filterText ?? item.label);
Expand Down Expand Up @@ -151,9 +158,9 @@ export function resolveServices(
'import ' + newName + ' from ',
);
item.textEdit.newText = newName;
const source = ctx.documents.getVirtualFileByUri(itemData.uri)[1];
if (source) {
const casing = await getNameCasing(ts, ctx, ctx.env.fileNameToUri(source.fileName), vueCompilerOptions);
const [_, sourceFile] = ctx.project.fileProvider.getVirtualFile(itemData.uri);
if (sourceFile) {
const casing = await getNameCasing(ts, ctx, sourceFile.id, vueCompilerOptions);
if (casing.tag === TagNameCasing.Kebab) {
item.textEdit.newText = hyphenateTag(item.textEdit.newText);
}
Expand All @@ -176,7 +183,7 @@ export function resolveServices(
const componentName = newName ?? item.textEdit.newText;
const optionEdit = ExtractComponentService.createAddComponentToOptionEdit(ts, ast, componentName);
if (optionEdit) {
const textDoc = ctx.documents.getDocumentByFileName(virtualFile.snapshot, virtualFile.fileName, virtualFile.languageId);
const textDoc = ctx.documents.getDocumentByUri(virtualFile.id, virtualFile.languageId, virtualFile.snapshot);
item.additionalTextEdits.push({
range: {
start: textDoc.positionAt(optionEdit.range.start),
Expand Down
Loading

0 comments on commit 1c3a7b5

Please sign in to comment.