Skip to content

Commit

Permalink
fix(tsc): remove fake global types holder (#4196)
Browse files Browse the repository at this point in the history
remove fake global types holder, instead extracting global types when
writing `.d.ts`. This allows composite projects to rebuild without
detecting changes which adjusting `options.rootNames` was causing

Co-authored-by: Johnson Chu <johnsoncodehk@gmail.com>
  • Loading branch information
blake-newman and johnsoncodehk authored Apr 3, 2024
1 parent 5e521f2 commit bd1d954
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 45 deletions.
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

0 comments on commit bd1d954

Please sign in to comment.