Skip to content

Commit 6a5574d

Browse files
authored
fix: dts redirect extension should add correctly (#940)
1 parent 8227a31 commit 6a5574d

File tree

6 files changed

+123
-20
lines changed

6 files changed

+123
-20
lines changed

packages/plugin-dts/src/utils.ts

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import path, {
55
basename,
66
dirname,
77
extname,
8+
isAbsolute,
89
join,
910
normalize,
1011
relative,
@@ -185,10 +186,15 @@ async function addExtension(
185186

186187
let redirectPath = path;
187188

189+
// Only add extension if redirectPath is an absolute or relative path
190+
if (!isAbsolute(redirectPath) && !redirectPath.startsWith('.')) {
191+
return redirectPath;
192+
}
193+
188194
// If the import path refers to a directory, it most likely actually refers to a `index.*` file due to Node's module resolution
189195
if (await isDirectory(join(dirname(dtsFile), redirectPath))) {
190196
// This uses `/` instead of `path.join` here because `join` removes potential "./" prefixes
191-
redirectPath = `${redirectPath}/index`;
197+
redirectPath = `${redirectPath.replace(/\/+$/, '')}/index`;
192198
}
193199

194200
return `${redirectPath}${extension}`;
@@ -277,9 +283,12 @@ export async function redirectDtsImports(
277283
let redirectImportPath = importPath;
278284

279285
if (absoluteImportPath && redirect.path) {
280-
const isOutsideRootdir = !normalize(absoluteImportPath).startsWith(
281-
normalize(rootDir) + path.sep,
286+
const relativeRootDir = path.relative(
287+
normalize(rootDir),
288+
normalize(absoluteImportPath),
282289
);
290+
const isOutsideRootdir =
291+
relativeRootDir.startsWith('..') || path.isAbsolute(relativeRootDir);
283292

284293
if (isOutsideRootdir) {
285294
const relativePath = relative(dirname(dtsFile), absoluteImportPath);

tests/integration/redirect/dts.test.ts

Lines changed: 77 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ let contents: Awaited<ReturnType<typeof buildAndGetResults>>['contents'];
77
beforeAll(async () => {
88
const fixturePath = path.resolve(__dirname, './dts');
99
contents = (await buildAndGetResults({ fixturePath, type: 'dts' })).contents;
10-
});
10+
}, 15000);
1111

12-
test('redirect.dts default', async () => {
12+
test('redirect.dts.path: true with redirect.dts.extension: false - default', async () => {
1313
expect(contents.esm0).toMatchInlineSnapshot(`
1414
{
1515
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/foo/foo.d.ts": "import { logRequest } from '../logger';
@@ -21,9 +21,10 @@ test('redirect.dts default', async () => {
2121
",
2222
"<ROOT>/tests/integration/redirect/dts/dist/default/esm/index.d.ts": "import { logRequest } from './logger';
2323
import { logger } from '../../../compile/rslog';
24+
import type { Baz } from './';
2425
import type { LoggerOptions } from './types';
2526
import { defaultOptions } from './types.js';
26-
export { logRequest, logger, type LoggerOptions, defaultOptions };
27+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
2728
export type { Foo } from './types';
2829
export type { Bar } from './types';
2930
export * from './foo';
@@ -47,12 +48,15 @@ test('redirect.dts default', async () => {
4748
export interface Bar {
4849
bar: string;
4950
}
51+
export interface Baz {
52+
baz: string;
53+
}
5054
",
5155
}
5256
`);
5357
});
5458

55-
test('redirect.dts.path false', async () => {
59+
test('redirect.dts.path: false with redirect.dts.extension: false', async () => {
5660
expect(contents.esm1).toMatchInlineSnapshot(`
5761
{
5862
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
@@ -64,9 +68,10 @@ test('redirect.dts.path false', async () => {
6468
",
6569
"<ROOT>/tests/integration/redirect/dts/dist/path-false/esm/index.d.ts": "import { logRequest } from '@src/logger';
6670
import { logger } from 'rslog';
71+
import type { Baz } from 'self-entry';
6772
import type { LoggerOptions } from './types';
6873
import { defaultOptions } from './types.js';
69-
export { logRequest, logger, type LoggerOptions, defaultOptions };
74+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
7075
export type { Foo } from '@src/types';
7176
export type { Bar } from 'types';
7277
export * from './foo';
@@ -90,12 +95,15 @@ test('redirect.dts.path false', async () => {
9095
export interface Bar {
9196
bar: string;
9297
}
98+
export interface Baz {
99+
baz: string;
100+
}
93101
",
94102
}
95103
`);
96104
});
97105

98-
test('redirect.dts.extension true', async () => {
106+
test('redirect.dts.path: true with redirect.dts.extension: true', async () => {
99107
expect(contents.esm2).toMatchInlineSnapshot(`
100108
{
101109
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/foo/foo.d.ts": "import { logRequest } from '../logger.js';
@@ -107,9 +115,10 @@ test('redirect.dts.extension true', async () => {
107115
",
108116
"<ROOT>/tests/integration/redirect/dts/dist/extension-true/esm/index.d.ts": "import { logRequest } from './logger.js';
109117
import { logger } from '../../../compile/rslog';
118+
import type { Baz } from './index.js';
110119
import type { LoggerOptions } from './types.js';
111120
import { defaultOptions } from './types.js';
112-
export { logRequest, logger, type LoggerOptions, defaultOptions };
121+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
113122
export type { Foo } from './types.js';
114123
export type { Bar } from './types.js';
115124
export * from './foo/index.js';
@@ -133,13 +142,63 @@ test('redirect.dts.extension true', async () => {
133142
export interface Bar {
134143
bar: string;
135144
}
145+
export interface Baz {
146+
baz: string;
147+
}
136148
",
137149
}
138150
`);
139151
});
140152

141-
test('redirect.dts.extension true with dts.autoExtension true', async () => {
153+
test('redirect.dts.path: false with dts.redirect.extension: true', async () => {
142154
expect(contents.esm3).toMatchInlineSnapshot(`
155+
{
156+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/foo/foo.d.ts": "import { logRequest } from '@src/logger';
157+
import { logger } from 'rslog';
158+
import { logRequest as logRequest2 } from '../logger.js';
159+
export { logRequest, logRequest2, logger };
160+
",
161+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/foo/index.d.ts": "export type Barrel = string;
162+
",
163+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/index.d.ts": "import { logRequest } from '@src/logger';
164+
import { logger } from 'rslog';
165+
import type { Baz } from 'self-entry';
166+
import type { LoggerOptions } from './types.js';
167+
import { defaultOptions } from './types.js';
168+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
169+
export type { Foo } from '@src/types';
170+
export type { Bar } from 'types';
171+
export * from './foo/index.js';
172+
export * from '@src/foo';
173+
export * from './types.js';
174+
export * from 'rslog';
175+
export * from '@src/logger';
176+
",
177+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/logger.d.ts": "import type { Request } from 'express';
178+
import type { LoggerOptions } from './types.js';
179+
export declare function logRequest(req: Request, options: LoggerOptions): void;
180+
",
181+
"<ROOT>/tests/integration/redirect/dts/dist/path-false-extension-true/esm/types.d.ts": "export interface LoggerOptions {
182+
logLevel: 'info' | 'debug' | 'warn' | 'error';
183+
logBody: boolean;
184+
}
185+
export declare const defaultOptions: LoggerOptions;
186+
export interface Foo {
187+
foo: string;
188+
}
189+
export interface Bar {
190+
bar: string;
191+
}
192+
export interface Baz {
193+
baz: string;
194+
}
195+
",
196+
}
197+
`);
198+
});
199+
200+
test('redirect.dts.extension: true with dts.autoExtension: true', async () => {
201+
expect(contents.esm4).toMatchInlineSnapshot(`
143202
{
144203
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/foo/foo.d.mts": "import { logRequest } from '../logger.mjs';
145204
import { logger } from '../../../compile/rslog';
@@ -157,9 +216,10 @@ test('redirect.dts.extension true with dts.autoExtension true', async () => {
157216
",
158217
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/index.d.mts": "import { logRequest } from './logger.mjs';
159218
import { logger } from '../../compile/rslog';
219+
import type { Baz } from './index.mjs';
160220
import type { LoggerOptions } from './types.mjs';
161221
import { defaultOptions } from './types.mjs';
162-
export { logRequest, logger, type LoggerOptions, defaultOptions };
222+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
163223
export type { Foo } from './types.mjs';
164224
export type { Bar } from './types.mjs';
165225
export * from './foo/index.mjs';
@@ -170,9 +230,10 @@ test('redirect.dts.extension true with dts.autoExtension true', async () => {
170230
",
171231
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/index.d.ts": "import { logRequest } from './logger.js';
172232
import { logger } from '../../compile/rslog';
233+
import type { Baz } from './index.js';
173234
import type { LoggerOptions } from './types.js';
174235
import { defaultOptions } from './types.js';
175-
export { logRequest, logger, type LoggerOptions, defaultOptions };
236+
export { type Baz as self, logRequest, logger, type LoggerOptions, defaultOptions, };
176237
export type { Foo } from './types.js';
177238
export type { Bar } from './types.js';
178239
export * from './foo/index.js';
@@ -200,6 +261,9 @@ test('redirect.dts.extension true with dts.autoExtension true', async () => {
200261
export interface Bar {
201262
bar: string;
202263
}
264+
export interface Baz {
265+
baz: string;
266+
}
203267
",
204268
"<ROOT>/tests/integration/redirect/dts/dist/auto-extension-true/types.d.ts": "export interface LoggerOptions {
205269
logLevel: 'info' | 'debug' | 'warn' | 'error';
@@ -212,6 +276,9 @@ test('redirect.dts.extension true with dts.autoExtension true', async () => {
212276
export interface Bar {
213277
bar: string;
214278
}
279+
export interface Baz {
280+
baz: string;
281+
}
215282
",
216283
}
217284
`);

tests/integration/redirect/dts/rslib.config.ts

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import { generateBundleCjsConfig, generateBundleEsmConfig } from 'test-helper';
33

44
export default defineConfig({
55
lib: [
6-
// 0 - default
6+
// 0 - default - path: true extension: false
77
generateBundleEsmConfig({
88
dts: true,
99
output: {
@@ -12,7 +12,7 @@ export default defineConfig({
1212
},
1313
},
1414
}),
15-
// 1 - path: false
15+
// 1 - path: false extension: false
1616
generateBundleEsmConfig({
1717
dts: true,
1818
output: {
@@ -26,7 +26,7 @@ export default defineConfig({
2626
},
2727
},
2828
}),
29-
// 2 - extension: true
29+
// 2 - path: true extension: true
3030
generateBundleEsmConfig({
3131
dts: true,
3232
output: {
@@ -40,7 +40,22 @@ export default defineConfig({
4040
},
4141
},
4242
}),
43-
// 3 - extension: true with dts.autoExtension true
43+
// 3 - path: false extension: true
44+
generateBundleEsmConfig({
45+
dts: true,
46+
output: {
47+
distPath: {
48+
root: './dist/path-false-extension-true/esm',
49+
},
50+
},
51+
redirect: {
52+
dts: {
53+
path: false,
54+
extension: true,
55+
},
56+
},
57+
}),
58+
// 4 - extension: true with dts.autoExtension true
4459
generateBundleEsmConfig({
4560
dts: {
4661
autoExtension: true,
@@ -56,7 +71,7 @@ export default defineConfig({
5671
},
5772
},
5873
}),
59-
// 4 - extension: true with dts.autoExtension true
74+
// 5 - extension: true with dts.autoExtension true
6075
generateBundleCjsConfig({
6176
dts: {
6277
autoExtension: true,

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

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
11
import { logRequest } from '@src/logger';
22
import { logger } from 'rslog';
3+
import type { Baz } from 'self-entry';
34
import type { LoggerOptions } from './types';
45
import { defaultOptions } from './types.js';
56

6-
export { logRequest, logger, type LoggerOptions, defaultOptions };
7+
export {
8+
type Baz as self,
9+
logRequest,
10+
logger,
11+
type LoggerOptions,
12+
defaultOptions,
13+
};
714

815
export type { Foo } from '@src/types';
916
export type { Bar } from 'types';

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,3 +15,7 @@ export interface Foo {
1515
export interface Bar {
1616
bar: string;
1717
}
18+
19+
export interface Baz {
20+
baz: string;
21+
}

tests/integration/redirect/dts/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"paths": {
66
"*": ["./src/*"],
77
"@src/*": ["./src/*"],
8-
"rslog": ["./compile/rslog"]
8+
"rslog": ["./compile/rslog"],
9+
"self-entry": ["./src"]
910
}
1011
},
1112
"include": ["src/**/*"]

0 commit comments

Comments
 (0)