Skip to content

Commit 737e93c

Browse files
authored
fix: exclude a test dependency's declaration file from the package (#524)
1 parent d41e99f commit 737e93c

3 files changed

Lines changed: 96 additions & 5 deletions

File tree

lib/npm_ignore.test.ts

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,58 @@ Deno.test("should keep the src directory when the declaration maps need it", ()
170170
});
171171
});
172172

173+
Deno.test("should ignore a dependency's declaration file", () => {
174+
// a dependency that ships a declaration file (ex. a prebuilt package
175+
// published to JSR) is copied as-is rather than compiled to `.js` + `.d.ts`
176+
const depDts = "deps/jsr.io/@scope/dep/1.0.0/dep.d.ts";
177+
178+
function run(options: {
179+
declaration: "separate" | "inline" | false;
180+
declarationMap?: boolean;
181+
includeEsModule?: boolean;
182+
includeScriptModule?: boolean;
183+
}) {
184+
return getNpmIgnoreText({
185+
sourceMap: undefined,
186+
inlineSources: undefined,
187+
testFiles: [{ filePath: depDts, fileText: "" }],
188+
includeEsModule: options.includeEsModule ?? true,
189+
includeScriptModule: options.includeScriptModule ?? true,
190+
declaration: options.declaration,
191+
declarationMap: options.declarationMap,
192+
});
193+
}
194+
195+
// inline declarations are copied beside the emitted code
196+
assertEquals(
197+
run({ declaration: "inline" }),
198+
`/src/\n/esm/${depDts}\n/script/${depDts}\n` +
199+
"/test_runner.cjs\nyarn.lock\npnpm-lock.yaml\n",
200+
);
201+
// inline declarations with declaration maps (the maps reference `/src/`, so
202+
// the individual source files are ignored instead of the whole directory)
203+
assertEquals(
204+
run({ declaration: "inline", declarationMap: true }),
205+
`/src/${depDts}\n/esm/${depDts}\n/esm/${depDts}.map\n/script/${depDts}\n` +
206+
`/script/${depDts}.map\n/test_runner.cjs\nyarn.lock\npnpm-lock.yaml\n`,
207+
);
208+
// separate declarations only end up in the types directory
209+
assertEquals(
210+
run({ declaration: "separate" }),
211+
`/src/\n/types/${depDts}\n/test_runner.cjs\nyarn.lock\npnpm-lock.yaml\n`,
212+
);
213+
// no declarations means the file is never emitted
214+
assertEquals(
215+
run({ declaration: false }),
216+
`/src/\n/test_runner.cjs\nyarn.lock\npnpm-lock.yaml\n`,
217+
);
218+
// only the esm output is emitted
219+
assertEquals(
220+
run({ declaration: "inline", includeScriptModule: false }),
221+
`/src/\n/esm/${depDts}\n/test_runner.cjs\nyarn.lock\npnpm-lock.yaml\n`,
222+
);
223+
});
224+
173225
function runTest(options: {
174226
sourceMaps: SourceMapOptions | undefined;
175227
inlineSources: boolean | undefined;

lib/npm_ignore.ts

Lines changed: 38 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
import type { OutputFile } from "../transform.ts";
44
import type { SourceMapOptions } from "./compiler.ts";
5-
import { toDtsFilePath, toJsFilePath } from "./utils.ts";
5+
import { isDeclarationFilePath, toDtsFilePath, toJsFilePath } from "./utils.ts";
66

77
export function getNpmIgnoreText(options: {
88
sourceMap?: SourceMapOptions;
@@ -27,14 +27,22 @@ export function getNpmIgnoreText(options: {
2727

2828
function* getTestFileNames() {
2929
for (const file of options.testFiles) {
30-
const filePath = toJsFilePath(file.filePath);
31-
const dtsFilePath = toDtsFilePath(file.filePath);
3230
// the whole directory is excluded above when it's not published
3331
if (isReferencingSrcDir()) {
3432
yield `/src/${file.filePath}`;
3533
}
34+
// A dependency can ship a declaration file directly (ex. a prebuilt
35+
// package published to JSR). The compiler copies it as-is beside the
36+
// emitted code rather than turning it into a `.js` + `.d.ts` pair, so it
37+
// has different output paths than a regular source file.
38+
if (isDeclarationFilePath(file.filePath)) {
39+
yield* getDeclarationTestFileNames(file.filePath);
40+
continue;
41+
}
42+
const jsFilePath = toJsFilePath(file.filePath);
43+
const dtsFilePath = toDtsFilePath(file.filePath);
3644
if (options.includeEsModule) {
37-
const esmFilePath = `/esm/${filePath}`;
45+
const esmFilePath = `/esm/${jsFilePath}`;
3846
yield esmFilePath;
3947
if (options.sourceMap === true) {
4048
yield `${esmFilePath}.map`;
@@ -47,7 +55,7 @@ export function getNpmIgnoreText(options: {
4755
}
4856
}
4957
if (options.includeScriptModule) {
50-
const scriptFilePath = `/script/${filePath}`;
58+
const scriptFilePath = `/script/${jsFilePath}`;
5159
yield scriptFilePath;
5260
if (options.sourceMap === true) {
5361
yield `${scriptFilePath}.map`;
@@ -69,6 +77,31 @@ export function getNpmIgnoreText(options: {
6977
yield "/test_runner.cjs";
7078
}
7179

80+
/** A declaration file emits no `.js`, so the compiler only copies it where
81+
* declarations are output: beside the code when they're inlined, or the
82+
* `types` directory when they're kept separate. */
83+
function* getDeclarationTestFileNames(dtsFilePath: string) {
84+
if (options.declaration === "inline") {
85+
if (options.includeEsModule) {
86+
yield `/esm/${dtsFilePath}`;
87+
if (options.declarationMap) {
88+
yield `/esm/${dtsFilePath}.map`;
89+
}
90+
}
91+
if (options.includeScriptModule) {
92+
yield `/script/${dtsFilePath}`;
93+
if (options.declarationMap) {
94+
yield `/script/${dtsFilePath}.map`;
95+
}
96+
}
97+
} else if (options.declaration === "separate") {
98+
yield `/types/${dtsFilePath}`;
99+
if (options.declarationMap) {
100+
yield `/types/${dtsFilePath}.map`;
101+
}
102+
}
103+
}
104+
72105
/** Whether any emitted map points back at the files in `/src/`, in which
73106
* case the directory needs to be published for the map to resolve. */
74107
function isReferencingSrcDir() {

lib/utils.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@ export function toDtsFilePath(filePath: string): string {
1919
// emits as `.js` files (the transform already outputs `.mts` and `.mjs` as `.js`)
2020
const COMPILED_EXT_RE = /\.(?:ts|tsx|jsx)$/i;
2121

22+
/** Whether the provided output file path is a declaration file, which the
23+
* TypeScript compiler copies as-is instead of compiling to a `.js` file. */
24+
export function isDeclarationFilePath(filePath: string): boolean {
25+
return /\.d\.[cm]?ts$/i.test(filePath);
26+
}
27+
2228
/**
2329
* Gets the files found in the provided root dir path based on the glob.
2430
*

0 commit comments

Comments
 (0)