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

fix(tsc): remove fake global types holder #4196

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
10 changes: 6 additions & 4 deletions packages/language-core/lib/generators/globalTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@ import { getSlotsPropertyName } from '../utils/shared';
export function generateGlobalTypes(vueCompilerOptions: VueCompilerOptions) {
const fnPropsType = `(K extends { $props: infer Props } ? Props : any)${vueCompilerOptions.strictTemplates ? '' : ' & Record<string, unknown>'}`;
return `
; declare global {
; export const __VLS_globalTypesStart = {};
declare global {
// @ts-ignore
type __VLS_IntrinsicElements = __VLS_PickNotAny<import('vue/jsx-runtime').JSX.IntrinsicElements, __VLS_PickNotAny<JSX.IntrinsicElements, Record<string, any>>>;
type __VLS_IntrinsicElements = __VLS_PickNotAny<import('vue/jsx-runtime').JSX.IntrinsicElements, __VLS_PickNotAny<globalThis.JSX.IntrinsicElements, Record<string, any>>>;
// @ts-ignore
type __VLS_Element = __VLS_PickNotAny<import('vue/jsx-runtime').JSX.Element, JSX.Element>;
type __VLS_Element = __VLS_PickNotAny<import('vue/jsx-runtime').JSX.Element, globalThis.JSX.Element>;
// @ts-ignore
type __VLS_GlobalComponents = ${[
`__VLS_PickNotAny<import('vue').GlobalComponents, {}>`,
Expand Down Expand Up @@ -125,5 +126,6 @@ type __VLS_NormalizeEmits<T> = __VLS_PrettifyGlobal<
>
>;
type __VLS_PrettifyGlobal<T> = { [K in keyof T]: T[K]; } & {};
}`;
}
export const __VLS_globalTypesEnd = {};`;
};
61 changes: 26 additions & 35 deletions packages/tsc/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import { runTsc } from '@volar/typescript/lib/quickstart/runTsc';
import * as vue from '@vue/language-core';
import type * as ts from 'typescript';

const windowsPathReg = /\\/g;

Expand All @@ -17,15 +16,37 @@ export function run() {
const vueOptions = typeof configFilePath === 'string'
? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions
: vue.resolveVueCompilerOptions({});
const fakeGlobalTypesHolder = createFakeGlobalTypesHolder(options);
const writeFile = options.host!.writeFile.bind(options.host);
const getCanonicalFileName = options.host?.useCaseSensitiveFileNames?.()
? (fileName: string) => fileName
: (fileName: string) => fileName.toLowerCase();
const canonicalRootFileNames = new Set(
options.rootNames
.map(rootName => rootName.replace(windowsPathReg, '/'))
.map(getCanonicalFileName)
);
const canonicalGlobalTypesHolderFileNames = new Set<string>();
options.host!.writeFile = (fileName, contents, ...args) => {
if (
fileName.endsWith('.d.ts')
&& canonicalGlobalTypesHolderFileNames.has(getCanonicalFileName(fileName.replace(windowsPathReg, '/')).slice(0, -5))
) {
contents = removeEmitGlobalTypes(contents);
}
return writeFile(fileName, contents, ...args);
};
if (
runExtensions.length === vueOptions.extensions.length
&& runExtensions.every(ext => vueOptions.extensions.includes(ext))
) {
const vueLanguagePlugin = vue.createVueLanguagePlugin(
ts,
id => id,
fileName => fileName === fakeGlobalTypesHolder,
fileName => {
const canonicalFileName = getCanonicalFileName(fileName);
canonicalGlobalTypesHolderFileNames.add(canonicalFileName);
return canonicalRootFileNames.has(canonicalFileName);
},
options.options,
vueOptions,
false,
Expand Down Expand Up @@ -54,36 +75,6 @@ export function run() {
}
}

export function createFakeGlobalTypesHolder(options: ts.CreateProgramOptions) {
const firstVueFile = options.rootNames.find(fileName => fileName.endsWith('.vue'));
if (firstVueFile) {
const fakeFileName = firstVueFile + '__VLS_globalTypes.vue';

(options.rootNames as string[]).push(fakeFileName);

const fileExists = options.host!.fileExists.bind(options.host);
const readFile = options.host!.readFile.bind(options.host);
const writeFile = options.host!.writeFile.bind(options.host);

options.host!.fileExists = fileName => {
if (fileName.endsWith('__VLS_globalTypes.vue')) {
return true;
}
return fileExists(fileName);
};
options.host!.readFile = fileName => {
if (fileName.endsWith('__VLS_globalTypes.vue')) {
return '<script setup lang="ts"></script>';
}
return readFile(fileName);
};
options.host!.writeFile = (fileName, ...args) => {
if (fileName.endsWith('__VLS_globalTypes.vue.d.ts')) {
return;
}
return writeFile(fileName, ...args);
};

return fakeFileName.replace(windowsPathReg, '/');
}
export function removeEmitGlobalTypes(dts: string) {
return dts.replace(/[^\n]*__VLS_globalTypesStart[\w\W]*__VLS_globalTypesEnd[^\n]*\n/, '');
}
23 changes: 17 additions & 6 deletions packages/tsc/tests/dts.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as ts from 'typescript';
import { describe, expect, it } from 'vitest';
import { proxyCreateProgram } from '@volar/typescript';
import * as vue from '@vue/language-core';
import { createFakeGlobalTypesHolder } from '..';
import { removeEmitGlobalTypes } from '..';

const workspace = path.resolve(__dirname, '../../../test-workspace/component-meta');
const normalizePath = (filename: string) => filename.replace(/\\/g, '/');
Expand All @@ -24,7 +24,6 @@ describe('vue-tsc-dts', () => {
rootNames: readFilesRecursive(workspace),
options: compilerOptions
};
const fakeGlobalTypesHolder = createFakeGlobalTypesHolder(options);

let vueExts: string[] = [];
const createProgram = proxyCreateProgram(ts, ts.createProgram, (ts, options) => {
Expand All @@ -36,7 +35,21 @@ describe('vue-tsc-dts', () => {
const vueLanguagePlugin = vue.createVueLanguagePlugin(
ts,
id => id,
fileName => fileName === fakeGlobalTypesHolder,
fileName => {
const rootFileNames = options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/'));
if (options.host?.useCaseSensitiveFileNames?.()) {
return rootFileNames.includes(fileName);
}
else {
const lowerFileName = fileName.toLowerCase();
for (const rootFileName of rootFileNames) {
if (rootFileName.toLowerCase() === lowerFileName) {
return true;
}
}
return false;
}
},
options.options,
vueOptions,
false,
Expand All @@ -52,9 +65,6 @@ describe('vue-tsc-dts', () => {

for (const intputFile of options.rootNames) {

if (intputFile.endsWith('__VLS_globalTypes.vue'))
continue;

const expectedOutputFile = intputFile.endsWith('.ts')
? intputFile.slice(0, -'.ts'.length) + '.d.ts'
: intputFile.endsWith('.tsx')
Expand All @@ -67,6 +77,7 @@ describe('vue-tsc-dts', () => {
sourceFile,
(outputFile, text) => {
expect(outputFile.replace(windowsPathReg, '/')).toBe(expectedOutputFile.replace(windowsPathReg, '/'));
text = removeEmitGlobalTypes(text);
outputText = text;
},
undefined,
Expand Down