Skip to content

Commit 216774f

Browse files
committed
Add support for import maps.
Fixes #4 . Note that some newer supported Node.js versions have a regression where `deepStrictEquals` fails to compare the URL HREF, but a fix has recently been merged: - nodejs/node#50836 - nodejs/node#50853 (comment) Until the fix has been published in new Node.js releases, we can rely on the GitHub Actions CI workflow testing with Node.js v18 which doesn’t have the regression.
1 parent 2f357d8 commit 216774f

14 files changed

+312
-81
lines changed

changelog.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,12 @@
22

33
## Next
44

5+
### Minor
6+
7+
- Added support for [import maps](https://github.com/WICG/import-maps), fixing [#4](https://github.com/jaydenseric/find-unused-exports/issues/4):
8+
- Added the CLI command `find-unused-exports` argument `--import-map`.
9+
- Added the function `findUnusedExports` option `importMap`.
10+
511
### Patch
612

713
- Updated dependencies.

directoryPathToFileURL.mjs

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// @ts-check
2+
3+
import { pathToFileURL } from "node:url";
4+
5+
/**
6+
* Converts a directory path to a file URL that always ends with `/` so it can
7+
* be safely used as a base URL for constructing file URLs with relative paths.
8+
* @param {string} directoryPath Directory path to convert.
9+
* @returns {URL} Directory file URL.
10+
*/
11+
export default function directoryPathToFileURL(directoryPath) {
12+
if (typeof directoryPath !== "string")
13+
throw new TypeError("Argument 1 `directoryPath` must be a string.");
14+
15+
// @ts-ignore https://github.com/microsoft/TypeScript/issues/59996
16+
return pathToFileURL(
17+
directoryPath.endsWith("/") ? directoryPath : `${directoryPath}/`,
18+
);
19+
}

directoryPathToFileURL.test.mjs

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
// @ts-check
2+
3+
import { deepStrictEqual, throws } from "node:assert";
4+
import { describe, it } from "node:test";
5+
6+
import directoryPathToFileURL from "./directoryPathToFileURL.mjs";
7+
8+
describe("Function `directoryPathToFileURL`.", { concurrency: true }, () => {
9+
it("Argument 1 `directoryPath` not a string.", () => {
10+
throws(() => {
11+
directoryPathToFileURL(
12+
// @ts-expect-error Testing invalid.
13+
true,
14+
);
15+
}, new TypeError("Argument 1 `directoryPath` must be a string."));
16+
});
17+
18+
it("Directory path ends with `/`.", () => {
19+
const directoryPath = "/a/b/c/";
20+
21+
deepStrictEqual(
22+
directoryPathToFileURL(directoryPath),
23+
new URL(`file://${directoryPath}`),
24+
);
25+
});
26+
27+
it("Directory path doesn’t end with `/`.", () => {
28+
const directoryPath = "/a/b/c";
29+
30+
deepStrictEqual(
31+
directoryPathToFileURL(directoryPath),
32+
new URL(`file://${directoryPath}/`),
33+
);
34+
});
35+
});

find-unused-exports.mjs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
#!/usr/bin/env node
22
// @ts-check
33

4+
/** @import { ImportMap } from "@import-maps/resolve" */
5+
46
import { relative } from "node:path";
57

68
import arg from "arg";
@@ -18,21 +20,35 @@ import reportCliError from "./reportCliError.mjs";
1820
async function findUnusedExportsCli() {
1921
try {
2022
const {
23+
"--import-map": importMapJson,
2124
"--module-glob": moduleGlob,
2225
"--resolve-file-extensions": resolveFileExtensionsList,
2326
"--resolve-index-files": resolveIndexFiles,
2427
} = arg({
28+
"--import-map": String,
2529
"--module-glob": String,
2630
"--resolve-file-extensions": String,
2731
"--resolve-index-files": Boolean,
2832
});
2933

34+
/** @type {ImportMap | undefined} */
35+
let importMap;
36+
37+
if (importMapJson) {
38+
try {
39+
importMap = JSON.parse(importMapJson);
40+
} catch {
41+
throw new CliError(`The \`--import-map\` argument must be JSON.`);
42+
}
43+
}
44+
3045
if (resolveIndexFiles && !resolveFileExtensionsList)
3146
throw new CliError(
3247
"The `--resolve-index-files` flag can only be used with the `--resolve-file-extensions` argument.",
3348
);
3449

3550
const unusedExports = await findUnusedExports({
51+
importMap,
3652
moduleGlob,
3753
resolveFileExtensions: resolveFileExtensionsList
3854
? resolveFileExtensionsList.split(",")

find-unused-exports.test.mjs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,65 @@ describe("CLI command `find-unused-exports`.", { concurrency: true }, () => {
9191
strictEqual(status, 1);
9292
});
9393

94+
describe("Arg `--import-map`.", { concurrency: true }, () => {
95+
it("Invalid.", async () => {
96+
const { stdout, stderr, status, error } = spawnSync(
97+
"node",
98+
[FIND_UNUSED_EXPORTS_CLI_PATH, "--import-map", "_"],
99+
{
100+
cwd: new URL("./test/fixtures/import-map", import.meta.url),
101+
env: {
102+
...process.env,
103+
FORCE_COLOR: "1",
104+
},
105+
},
106+
);
107+
108+
if (error) throw error;
109+
110+
strictEqual(stdout.toString(), "");
111+
await assertSnapshot(
112+
stderr.toString(),
113+
new URL(
114+
"./test/snapshots/find-unused-exports/import-map-invalid-stderr.ans",
115+
import.meta.url,
116+
),
117+
);
118+
strictEqual(status, 1);
119+
});
120+
121+
it("Valid.", async () => {
122+
const { stdout, stderr, status, error } = spawnSync(
123+
"node",
124+
[
125+
FIND_UNUSED_EXPORTS_CLI_PATH,
126+
"--import-map",
127+
'"$(cat import-map.json)"',
128+
],
129+
{
130+
cwd: new URL("./test/fixtures/import-map", import.meta.url),
131+
env: {
132+
...process.env,
133+
FORCE_COLOR: "1",
134+
},
135+
shell: true,
136+
},
137+
);
138+
139+
if (error) throw error;
140+
141+
strictEqual(stdout.toString(), "");
142+
await assertSnapshot(
143+
stderr.toString(),
144+
new URL(
145+
"./test/snapshots/find-unused-exports/import-map-valid-stderr.ans",
146+
import.meta.url,
147+
),
148+
);
149+
strictEqual(status, 1);
150+
});
151+
});
152+
94153
it("Arg `--module-glob`.", async () => {
95154
const { stdout, stderr, status, error } = spawnSync(
96155
"node",

0 commit comments

Comments
 (0)