Skip to content

Commit 4b4c246

Browse files
authored
fix(dts): clean correct tsbuildinfo file (#1138)
1 parent 6b7cade commit 4b4c246

File tree

2 files changed

+210
-99
lines changed

2 files changed

+210
-99
lines changed

packages/plugin-dts/src/utils.ts

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -582,19 +582,27 @@ export async function cleanTsBuildInfoFile(
582582
): Promise<void> {
583583
const tsconfigDir = dirname(tsconfigPath);
584584
const { outDir, rootDir, tsBuildInfoFile } = compilerOptions;
585-
let tsbuildInfoFilePath = `${basename(
586-
tsconfigPath,
587-
'.json',
588-
)}${tsBuildInfoFile ?? '.tsbuildinfo'}`;
589-
if (outDir) {
590-
if (rootDir) {
591-
tsbuildInfoFilePath = join(
592-
outDir,
593-
relative(resolve(tsconfigDir, rootDir), tsconfigDir),
594-
tsbuildInfoFilePath,
595-
);
585+
let tsbuildInfoFilePath: string;
586+
587+
if (tsBuildInfoFile && isAbsolute(tsBuildInfoFile)) {
588+
tsbuildInfoFilePath = tsBuildInfoFile;
589+
} else {
590+
const defaultFileName = `${basename(
591+
tsconfigPath,
592+
'.json',
593+
)}${tsBuildInfoFile ?? '.tsbuildinfo'}`;
594+
if (outDir) {
595+
if (rootDir) {
596+
tsbuildInfoFilePath = join(
597+
outDir,
598+
relative(resolve(tsconfigDir, rootDir), tsconfigDir),
599+
defaultFileName,
600+
);
601+
} else {
602+
tsbuildInfoFilePath = join(outDir, defaultFileName);
603+
}
596604
} else {
597-
tsbuildInfoFilePath = join(outDir, tsbuildInfoFilePath);
605+
tsbuildInfoFilePath = join(tsconfigDir, defaultFileName);
598606
}
599607
}
600608

Lines changed: 190 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,101 +1,204 @@
1-
import { expect, test } from '@rstest/core';
2-
import { mergeAliasWithTsConfigPaths, prettyTime } from '../src/utils';
3-
4-
test('should pretty time correctly', () => {
5-
expect(prettyTime(0.0012)).toEqual('0.001 s');
6-
expect(prettyTime(0.0123)).toEqual('0.01 s');
7-
expect(prettyTime(0.1234)).toEqual('0.12 s');
8-
expect(prettyTime(1.234)).toEqual('1.23 s');
9-
expect(prettyTime(12.34)).toEqual('12.3 s');
10-
expect(prettyTime(120)).toEqual('2 m');
11-
expect(prettyTime(123.4)).toEqual('2 m 3.4 s');
12-
expect(prettyTime(1234)).toEqual('20 m 34 s');
13-
expect(prettyTime(1234.5)).toEqual('20 m 34.5 s');
14-
});
1+
// import { execSync } from 'node:child_process';
2+
import fs from 'node:fs/promises';
3+
import path from 'node:path';
4+
import { describe, expect, test } from '@rstest/core';
5+
import {
6+
cleanTsBuildInfoFile,
7+
loadTsconfig,
8+
mergeAliasWithTsConfigPaths,
9+
prettyTime,
10+
} from '../src/utils';
1511

16-
test('mergeAliasWithTsConfigPaths should handle empty inputs', () => {
17-
// Both undefined
18-
expect(
19-
mergeAliasWithTsConfigPaths(undefined, undefined),
20-
).toMatchInlineSnapshot({}, '{}');
21-
22-
// Empty objects
23-
expect(mergeAliasWithTsConfigPaths({}, {})).toMatchInlineSnapshot({}, '{}');
24-
25-
// One empty, one undefined
26-
expect(mergeAliasWithTsConfigPaths({}, undefined)).toMatchInlineSnapshot(
27-
{},
28-
'{}',
29-
);
30-
expect(mergeAliasWithTsConfigPaths(undefined, {})).toMatchInlineSnapshot(
31-
{},
32-
'{}',
33-
);
12+
describe('prettyTime', () => {
13+
test('should pretty time correctly', () => {
14+
expect(prettyTime(0.0012)).toEqual('0.001 s');
15+
expect(prettyTime(0.0123)).toEqual('0.01 s');
16+
expect(prettyTime(0.1234)).toEqual('0.12 s');
17+
expect(prettyTime(1.234)).toEqual('1.23 s');
18+
expect(prettyTime(12.34)).toEqual('12.3 s');
19+
expect(prettyTime(120)).toEqual('2 m');
20+
expect(prettyTime(123.4)).toEqual('2 m 3.4 s');
21+
expect(prettyTime(1234)).toEqual('20 m 34 s');
22+
expect(prettyTime(1234.5)).toEqual('20 m 34.5 s');
23+
});
3424
});
3525

36-
test('mergeAliasWithTsConfigPaths should handle paths only', () => {
37-
const paths = {
38-
'@/*': ['./src/*'],
39-
};
26+
describe('mergeAliasWithTsConfigPaths', () => {
27+
test('mergeAliasWithTsConfigPaths should handle empty inputs', () => {
28+
// Both undefined
29+
expect(
30+
mergeAliasWithTsConfigPaths(undefined, undefined),
31+
).toMatchInlineSnapshot({}, '{}');
4032

41-
const result = mergeAliasWithTsConfigPaths(paths, undefined);
33+
// Empty objects
34+
expect(mergeAliasWithTsConfigPaths({}, {})).toMatchInlineSnapshot({}, '{}');
4235

43-
expect(result).toMatchInlineSnapshot(`
44-
{
45-
"@/*": [
46-
"./src/*",
47-
],
48-
}
49-
`);
50-
});
36+
// One empty, one undefined
37+
expect(mergeAliasWithTsConfigPaths({}, undefined)).toMatchInlineSnapshot(
38+
{},
39+
'{}',
40+
);
41+
expect(mergeAliasWithTsConfigPaths(undefined, {})).toMatchInlineSnapshot(
42+
{},
43+
'{}',
44+
);
45+
});
5146

52-
test('mergeAliasWithTsConfigPaths should handle alias only', () => {
53-
const alias = {
54-
'@': './src',
55-
};
47+
test('mergeAliasWithTsConfigPaths should handle paths only', () => {
48+
const paths = {
49+
'@/*': ['./src/*'],
50+
};
5651

57-
const result = mergeAliasWithTsConfigPaths(undefined, alias);
52+
const result = mergeAliasWithTsConfigPaths(paths, undefined);
5853

59-
expect(result).toMatchInlineSnapshot(`
60-
{
61-
"@": [
62-
"./src",
63-
],
64-
}
65-
`);
66-
});
54+
expect(result).toMatchInlineSnapshot(`
55+
{
56+
"@/*": [
57+
"./src/*",
58+
],
59+
}
60+
`);
61+
});
6762

68-
test('mergeAliasWithTsConfigPaths should handle alias overriding paths', () => {
69-
const paths = {
70-
'@utils/*': ['./lib/utils/*'],
71-
'@/*': ['./src/*'],
72-
};
63+
test('mergeAliasWithTsConfigPaths should handle alias only', () => {
64+
const alias = {
65+
'@': './src',
66+
};
7367

74-
const alias = {
75-
'@utils/*': './src/utils',
76-
'@components': './src/components',
77-
};
68+
const result = mergeAliasWithTsConfigPaths(undefined, alias);
7869

79-
const result = mergeAliasWithTsConfigPaths(paths, alias);
80-
81-
expect(Object.keys(result)).toMatchInlineSnapshot(`
82-
[
83-
"@utils/*",
84-
"@components",
85-
"@/*",
86-
]
87-
`);
88-
expect(Object.values(result)).toMatchInlineSnapshot(`
89-
[
90-
[
91-
"./src/utils",
92-
],
70+
expect(result).toMatchInlineSnapshot(`
71+
{
72+
"@": [
73+
"./src",
74+
],
75+
}
76+
`);
77+
});
78+
79+
test('mergeAliasWithTsConfigPaths should handle alias overriding paths', () => {
80+
const paths = {
81+
'@utils/*': ['./lib/utils/*'],
82+
'@/*': ['./src/*'],
83+
};
84+
85+
const alias = {
86+
'@utils/*': './src/utils',
87+
'@components': './src/components',
88+
};
89+
90+
const result = mergeAliasWithTsConfigPaths(paths, alias);
91+
92+
expect(Object.keys(result)).toMatchInlineSnapshot(`
9393
[
94-
"./src/components",
95-
],
94+
"@utils/*",
95+
"@components",
96+
"@/*",
97+
]
98+
`);
99+
expect(Object.values(result)).toMatchInlineSnapshot(`
96100
[
97-
"./src/*",
98-
],
99-
]
100-
`);
101+
[
102+
"./src/utils",
103+
],
104+
[
105+
"./src/components",
106+
],
107+
[
108+
"./src/*",
109+
],
110+
]
111+
`);
112+
});
113+
});
114+
115+
describe('cleanTsBuildInfoFile', () => {
116+
const fileExists = async (filePath: string): Promise<boolean> => {
117+
try {
118+
await fs.access(filePath);
119+
return true;
120+
} catch {
121+
return false;
122+
}
123+
};
124+
125+
const testCases = [
126+
{
127+
name: 'default config without custom tsBuildInfoFile',
128+
config: { composite: true },
129+
expectedPath: 'tsconfig.case1.tsbuildinfo',
130+
},
131+
{
132+
name: 'custom tsBuildInfoFile path',
133+
config: {
134+
composite: true,
135+
tsBuildInfoFile: 'node_modules/.cache/tsconfig.case2.tsbuildinfo',
136+
},
137+
expectedPath: 'node_modules/.cache/tsconfig.case2.tsbuildinfo',
138+
},
139+
{
140+
name: 'outDir without rootDir',
141+
config: { composite: true, outDir: 'dist3' },
142+
expectedPath: 'dist3/tsconfig.case3.tsbuildinfo',
143+
},
144+
{
145+
name: 'outDir with rootDir',
146+
config: { composite: true, outDir: 'dist4', rootDir: 'src' },
147+
expectedPath: 'tsconfig.case4.tsbuildinfo',
148+
},
149+
{
150+
name: 'nested outDir with rootDir',
151+
config: { composite: true, outDir: 'dist/5', rootDir: 'src' },
152+
expectedPath: 'dist/tsconfig.case5.tsbuildinfo',
153+
},
154+
];
155+
156+
test('should clean tsBuildInfo files for various tsconfig configurations', async () => {
157+
delete process.env.NO_COLOR;
158+
const tempDir = await fs.mkdtemp(path.join(__dirname, 'temp-test-'));
159+
160+
const srcPath = path.join(tempDir, 'src/index.ts');
161+
await fs.mkdir(path.dirname(srcPath), { recursive: true });
162+
await fs.writeFile(srcPath, 'export {}');
163+
164+
try {
165+
await Promise.all(
166+
testCases.map(async (testCase, index) => {
167+
const caseNumber = index + 1;
168+
const tsconfigPath = path.join(
169+
tempDir,
170+
`tsconfig.case${caseNumber}.json`,
171+
);
172+
const expectedBuildInfoPath = path.join(
173+
tempDir,
174+
testCase.expectedPath,
175+
);
176+
177+
await fs.writeFile(
178+
tsconfigPath,
179+
JSON.stringify({ compilerOptions: testCase.config }, null, 2),
180+
);
181+
182+
// execSync(`npx tsc --p ${tsconfigPath}`, { cwd: tempDir });
183+
// tsc is too slow, so we directly create the file
184+
await fs.mkdir(path.dirname(expectedBuildInfoPath), {
185+
recursive: true,
186+
});
187+
await fs.writeFile(
188+
path.join(tempDir, testCase.expectedPath),
189+
'Generated tsBuildInfo content',
190+
);
191+
192+
expect(await fileExists(expectedBuildInfoPath)).toBe(true);
193+
194+
const tsconfig = loadTsconfig(tsconfigPath);
195+
await cleanTsBuildInfoFile(tsconfigPath, tsconfig.options);
196+
197+
expect(await fileExists(expectedBuildInfoPath)).toBe(false);
198+
}),
199+
);
200+
} finally {
201+
await fs.rm(tempDir, { recursive: true, force: true });
202+
}
203+
});
101204
});

0 commit comments

Comments
 (0)