Skip to content

Commit 1fea10d

Browse files
authored
fix(dts): check for existence of target path when redirect extension (#1374)
1 parent c2df99c commit 1fea10d

File tree

11 files changed

+101
-29
lines changed

11 files changed

+101
-29
lines changed

packages/plugin-dts/src/utils.ts

Lines changed: 32 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -237,26 +237,40 @@ async function addExtension(
237237
redirect: DtsRedirect,
238238
dtsFile: string,
239239
path: string,
240-
extension: string,
240+
jsExtension: string,
241+
dtsExtension: string,
241242
): Promise<string> {
242243
if (!redirect.extension) {
243244
return path;
244245
}
245246

246-
let redirectPath = path;
247-
248-
// Only add extension if redirectPath is an absolute or relative path
249-
if (!isAbsolute(redirectPath) && !redirectPath.startsWith('.')) {
250-
return redirectPath;
247+
// Only add extension if path is an absolute or relative path
248+
if (!isAbsolute(path) && !path.startsWith('.')) {
249+
return path;
251250
}
252251

252+
const candidatePaths = [];
253+
253254
// If the import path refers to a directory, it most likely actually refers to a `index.*` file due to Node's module resolution
254-
if (await isDirectory(join(dirname(dtsFile), redirectPath))) {
255+
if (await isDirectory(join(dirname(dtsFile), path))) {
255256
// This uses `/` instead of `path.join` here because `join` removes potential "./" prefixes
256-
redirectPath = `${redirectPath.replace(/\/+$/, '')}/index`;
257+
candidatePaths.push(`${path.replace(/\/+$/, '')}/index`);
258+
}
259+
260+
candidatePaths.push(path);
261+
262+
// make sure the candidatePath exists, otherwise we may break the import, e.g. import 'foo.svg', import '../foo/index'
263+
for (const candidatePath of candidatePaths) {
264+
if (
265+
await pathExists(
266+
join(dirname(dtsFile), `${candidatePath}${dtsExtension}`),
267+
)
268+
) {
269+
return `${candidatePath}${jsExtension}`;
270+
}
257271
}
258272

259-
return `${redirectPath}${extension}`;
273+
return path;
260274
}
261275

262276
export async function redirectDtsImports(
@@ -334,7 +348,7 @@ export async function redirectDtsImports(
334348
e: matchNode.range().end.index,
335349
};
336350
});
337-
const extension = dtsExtension
351+
const jsExtension = dtsExtension
338352
.replace(/\.d\.ts$/, '.js')
339353
.replace(/\.d\.cts$/, '.cjs')
340354
.replace(/\.d\.mts$/, '.mjs');
@@ -393,28 +407,18 @@ export async function redirectDtsImports(
393407
if (redirect.extension) {
394408
redirectImportPath = redirectImportPath.replace(
395409
/\.[^.]+$/,
396-
extension,
410+
jsExtension,
397411
);
398412
}
399413
} else {
400414
// handle the case importPath is like './foo.bar', we need to check if './foo.bar.d.ts' exists
401-
const candidatePath = await addExtension(
415+
redirectImportPath = await addExtension(
402416
redirect,
403417
dtsFile,
404418
redirectImportPath,
405-
extension,
419+
jsExtension,
420+
dtsExtension,
406421
);
407-
// make sure the candidatePath exists, otherwise we may break the import, e.g. import 'foo.svg'
408-
if (
409-
await pathExists(
410-
path.join(
411-
dirname(dtsFile),
412-
candidatePath.replace(/\.[^.]+$/, dtsExtension),
413-
),
414-
)
415-
) {
416-
redirectImportPath = candidatePath;
417-
}
418422
}
419423
} else {
420424
if (
@@ -425,7 +429,8 @@ export async function redirectDtsImports(
425429
redirect,
426430
dtsFile,
427431
redirectImportPath,
428-
extension,
432+
jsExtension,
433+
dtsExtension,
429434
);
430435
}
431436

@@ -434,7 +439,8 @@ export async function redirectDtsImports(
434439
redirect,
435440
dtsFile,
436441
redirectImportPath,
437-
extension,
442+
jsExtension,
443+
dtsExtension,
438444
);
439445
}
440446
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './config/load';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const loadConfig = () => {};

tests/integration/redirect/dts-tsgo/src/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,12 +18,13 @@ export {
1818
export * from '@src/foo';
1919
export * from '@src/logger';
2020
export type { Foo } from '@src/types';
21-
// export { Router } from 'express';
2221
export * from 'prebundle-pkg';
22+
// export { Router } from 'express';
2323
export type { Bar } from 'types';
2424
export * from './.hidden';
2525
export * from './.hidden-folder';
2626
export * from './a.b';
2727
export * from './bar.baz';
28+
export * from './config';
2829
export * from './foo';
2930
export * from './types';

tests/integration/redirect/dts.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@ test('redirect.dts.path: true with redirect.dts.extension: false - default', asy
1919
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/a.b/index.d.ts": "export declare const ab = "a.b";
2020
",
2121
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
22+
",
23+
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/config.d.ts": "export * from './config/load';
24+
",
25+
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/config/load.d.ts": "export declare const loadConfig: () => void;
2226
",
2327
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/foo/foo.d.ts": "import { logRequest } from '../logger';
2428
import { logger } from '../../../../compile/prebundle-pkg';
@@ -44,6 +48,7 @@ test('redirect.dts.path: true with redirect.dts.extension: false - default', asy
4448
export * from './.hidden-folder';
4549
export * from './a.b';
4650
export * from './bar.baz';
51+
export * from './config';
4752
export * from './foo';
4853
export * from './types';
4954
",
@@ -80,6 +85,10 @@ test('redirect.dts.path: false with redirect.dts.extension: false', async () =>
8085
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/a.b/index.d.ts": "export declare const ab = "a.b";
8186
",
8287
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
88+
",
89+
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/config.d.ts": "export * from './config/load';
90+
",
91+
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/config/load.d.ts": "export declare const loadConfig: () => void;
8392
",
8493
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
8594
import { logger } from 'prebundle-pkg';
@@ -105,6 +114,7 @@ test('redirect.dts.path: false with redirect.dts.extension: false', async () =>
105114
export * from './.hidden-folder';
106115
export * from './a.b';
107116
export * from './bar.baz';
117+
export * from './config';
108118
export * from './foo';
109119
export * from './types';
110120
",
@@ -141,6 +151,10 @@ test('redirect.dts.path: true with redirect.dts.extension: true', async () => {
141151
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/a.b/index.d.ts": "export declare const ab = "a.b";
142152
",
143153
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
154+
",
155+
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/config.d.ts": "export * from './config/load.js';
156+
",
157+
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/config/load.d.ts": "export declare const loadConfig: () => void;
144158
",
145159
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/foo/foo.d.ts": "import { logRequest } from '../logger.js';
146160
import { logger } from '../../../../compile/prebundle-pkg';
@@ -166,6 +180,7 @@ test('redirect.dts.path: true with redirect.dts.extension: true', async () => {
166180
export * from './.hidden-folder/index.js';
167181
export * from './a.b/index.js';
168182
export * from './bar.baz.js';
183+
export * from './config.js';
169184
export * from './foo/index.js';
170185
export * from './types.js';
171186
",
@@ -202,6 +217,10 @@ test('redirect.dts.path: false with dts.redirect.extension: true', async () => {
202217
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/a.b/index.d.ts": "export declare const ab = "a.b";
203218
",
204219
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
220+
",
221+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/config.d.ts": "export * from './config/load.js';
222+
",
223+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/config/load.d.ts": "export declare const loadConfig: () => void;
205224
",
206225
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
207226
import { logger } from 'prebundle-pkg';
@@ -227,6 +246,7 @@ test('redirect.dts.path: false with dts.redirect.extension: true', async () => {
227246
export * from './.hidden-folder/index.js';
228247
export * from './a.b/index.js';
229248
export * from './bar.baz.js';
249+
export * from './config.js';
230250
export * from './foo/index.js';
231251
export * from './types.js';
232252
",
@@ -271,6 +291,14 @@ test('redirect.dts.extension: true with dts.autoExtension: true', async () => {
271291
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/bar.baz.d.mts": "export declare const bar = "bar-baz";
272292
",
273293
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/bar.baz.d.ts": "export declare const bar = "bar-baz";
294+
",
295+
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/config.d.mts": "export * from './config/load.mjs';
296+
",
297+
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/config.d.ts": "export * from './config/load.js';
298+
",
299+
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/config/load.d.mts": "export declare const loadConfig: () => void;
300+
",
301+
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/config/load.d.ts": "export declare const loadConfig: () => void;
274302
",
275303
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/foo/foo.d.mts": "import { logRequest } from '../logger.mjs';
276304
import { logger } from '../../../compile/prebundle-pkg';
@@ -303,6 +331,7 @@ test('redirect.dts.extension: true with dts.autoExtension: true', async () => {
303331
export * from './.hidden-folder/index.mjs';
304332
export * from './a.b/index.mjs';
305333
export * from './bar.baz.mjs';
334+
export * from './config.mjs';
306335
export * from './foo/index.mjs';
307336
export * from './types.mjs';
308337
",
@@ -323,6 +352,7 @@ test('redirect.dts.extension: true with dts.autoExtension: true', async () => {
323352
export * from './.hidden-folder/index.js';
324353
export * from './a.b/index.js';
325354
export * from './bar.baz.js';
355+
export * from './config.js';
326356
export * from './foo/index.js';
327357
export * from './types.js';
328358
",
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from './config/load';
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const loadConfig = () => {};

tests/integration/redirect/dts/src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ export * from './.hidden';
2525
export * from './.hidden-folder';
2626
export * from './a.b';
2727
export * from './bar.baz';
28+
export * from './config';
2829
export * from './foo';
2930
export * from './types';

tests/integration/redirect/dtsTsgo.test.ts

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,10 @@ describe.skipIf(process.version.startsWith('v18'))(
2323
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/default/esm/a.b/index.d.ts": "export declare const ab = "a.b";
2424
",
2525
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/default/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
26+
",
27+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/default/esm/config.d.ts": "export * from './config/load';
28+
",
29+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/default/esm/config/load.d.ts": "export declare const loadConfig: () => void;
2630
",
2731
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/default/esm/foo/foo.d.ts": "import { logRequest } from '../logger';
2832
import { logger } from '../../../../compile/prebundle-pkg';
@@ -47,6 +51,7 @@ describe.skipIf(process.version.startsWith('v18'))(
4751
export * from './.hidden-folder';
4852
export * from './a.b';
4953
export * from './bar.baz';
54+
export * from './config';
5055
export * from './foo';
5156
export * from './types';
5257
",
@@ -82,6 +87,10 @@ describe.skipIf(process.version.startsWith('v18'))(
8287
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false/esm/a.b/index.d.ts": "export declare const ab = "a.b";
8388
",
8489
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
90+
",
91+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false/esm/config.d.ts": "export * from './config/load';
92+
",
93+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false/esm/config/load.d.ts": "export declare const loadConfig: () => void;
8594
",
8695
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
8796
import { logger } from 'prebundle-pkg';
@@ -106,6 +115,7 @@ describe.skipIf(process.version.startsWith('v18'))(
106115
export * from './.hidden-folder';
107116
export * from './a.b';
108117
export * from './bar.baz';
118+
export * from './config';
109119
export * from './foo';
110120
export * from './types';
111121
",
@@ -141,6 +151,10 @@ describe.skipIf(process.version.startsWith('v18'))(
141151
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/extension-true/esm/a.b/index.d.ts": "export declare const ab = "a.b";
142152
",
143153
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/extension-true/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
154+
",
155+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/extension-true/esm/config.d.ts": "export * from './config/load.js';
156+
",
157+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/extension-true/esm/config/load.d.ts": "export declare const loadConfig: () => void;
144158
",
145159
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/extension-true/esm/foo/foo.d.ts": "import { logRequest } from '../logger.js';
146160
import { logger } from '../../../../compile/prebundle-pkg';
@@ -165,6 +179,7 @@ describe.skipIf(process.version.startsWith('v18'))(
165179
export * from './.hidden-folder/index.js';
166180
export * from './a.b/index.js';
167181
export * from './bar.baz.js';
182+
export * from './config.js';
168183
export * from './foo/index.js';
169184
export * from './types.js';
170185
",
@@ -200,6 +215,10 @@ describe.skipIf(process.version.startsWith('v18'))(
200215
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false-extension-true/esm/a.b/index.d.ts": "export declare const ab = "a.b";
201216
",
202217
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false-extension-true/esm/bar.baz.d.ts": "export declare const bar = "bar-baz";
218+
",
219+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false-extension-true/esm/config.d.ts": "export * from './config/load.js';
220+
",
221+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false-extension-true/esm/config/load.d.ts": "export declare const loadConfig: () => void;
203222
",
204223
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/path-false-extension-true/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
205224
import { logger } from 'prebundle-pkg';
@@ -224,6 +243,7 @@ describe.skipIf(process.version.startsWith('v18'))(
224243
export * from './.hidden-folder/index.js';
225244
export * from './a.b/index.js';
226245
export * from './bar.baz.js';
246+
export * from './config.js';
227247
export * from './foo/index.js';
228248
export * from './types.js';
229249
",
@@ -259,6 +279,10 @@ describe.skipIf(process.version.startsWith('v18'))(
259279
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/esm/a.b/index.d.mts": "export declare const ab = "a.b";
260280
",
261281
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/esm/bar.baz.d.mts": "export declare const bar = "bar-baz";
282+
",
283+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/esm/config.d.mts": "export * from './config/load.mjs';
284+
",
285+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/esm/config/load.d.mts": "export declare const loadConfig: () => void;
262286
",
263287
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/esm/foo/foo.d.mts": "import { logRequest } from '../logger.mjs';
264288
import { logger } from '../../../../compile/prebundle-pkg';
@@ -283,6 +307,7 @@ describe.skipIf(process.version.startsWith('v18'))(
283307
export * from './.hidden-folder/index.mjs';
284308
export * from './a.b/index.mjs';
285309
export * from './bar.baz.mjs';
310+
export * from './config.mjs';
286311
export * from './foo/index.mjs';
287312
export * from './types.mjs';
288313
",
@@ -315,6 +340,10 @@ describe.skipIf(process.version.startsWith('v18'))(
315340
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/cjs/a.b/index.d.ts": "export declare const ab = "a.b";
316341
",
317342
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/cjs/bar.baz.d.ts": "export declare const bar = "bar-baz";
343+
",
344+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/cjs/config.d.ts": "export * from './config/load.js';
345+
",
346+
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/cjs/config/load.d.ts": "export declare const loadConfig: () => void;
318347
",
319348
"<ROOT>/tests/integration/redirect/dts-tsgo/dist/auto-extension-true/cjs/foo/foo.d.ts": "import { logRequest } from '../logger.js';
320349
import { logger } from '../../../../compile/prebundle-pkg';
@@ -339,6 +368,7 @@ describe.skipIf(process.version.startsWith('v18'))(
339368
export * from './.hidden-folder/index.js';
340369
export * from './a.b/index.js';
341370
export * from './bar.baz.js';
371+
export * from './config.js';
342372
export * from './foo/index.js';
343373
export * from './types.js';
344374
",

website/docs/en/config/lib/experiments.mdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ Controls whether to enable Rspack experimental ESM output. When enabled, it emit
1313
Currently this option only takes effect in bundle mode when format is `'esm'`.
1414
:::
1515

16-
```js title="rslib.config.js"
16+
```js title="rslib.config.ts"
1717
export default {
1818
lib: [
1919
{

0 commit comments

Comments
 (0)