Skip to content

Commit 3ca2866

Browse files
committed
Fix bug in Named Exports rule that could cause false positives for re-exported values
1 parent d1272e8 commit 3ca2866

File tree

7 files changed

+1479
-19
lines changed

7 files changed

+1479
-19
lines changed

.changeset/silly-rings-brake.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@arethetypeswrong/core": patch
3+
---
4+
5+
Fix bug in Named Exports rule that could cause false positives for re-exported values

packages/cli/test/snapshots.test.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ const tests = [
4242
],
4343

4444
["eslint-module-utils@2.8.1.tgz", "--entrypoints-legacy --ignore-rules=cjs-only-exports-default"],
45+
["@cerbos__core@0.18.1.tgz"],
4546
];
4647

4748
const defaultOpts = "-f table-flipped";
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
# @cerbos__core@0.18.1.tgz
2+
3+
```
4+
$ attw @cerbos__core@0.18.1.tgz -f table-flipped
5+
6+
7+
@cerbos/core v0.18.1
8+
9+
No problems found 🌟
10+
11+
12+
┌────────────────┬────────┬───────────────────┬───────────────────┬─────────┐
13+
│ │ node10 │ node16 (from CJS) │ node16 (from ESM) │ bundler │
14+
├────────────────┼────────┼───────────────────┼───────────────────┼─────────┤
15+
│ "@cerbos/core" │ 🟢 │ 🟢 (CJS) │ 🟢 (CJS) │ 🟢 │
16+
└────────────────┴────────┴───────────────────┴───────────────────┴─────────┘
17+
18+
19+
```
20+
21+
Exit code: 0

packages/core/src/internal/esm/cjsNamespace.ts

Lines changed: 15 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -2,30 +2,27 @@ import { Package } from "../../createPackage.js";
22
import { getCjsModuleBindings } from "./cjsBindings.js";
33
import { cjsResolve } from "./cjsResolve.js";
44

5-
export function getCjsModuleNamespace(fs: Package, file: URL, seen = new Set<string>()) {
5+
export function getCjsModuleNamespace(fs: Package, file: URL, seen = new Set<string>()): Set<string> {
66
seen.add(file.pathname);
7-
const { exports, reexports } = getCjsModuleBindings(fs.readFile(file.pathname));
7+
const exports = new Set<string>();
8+
const bindings = getCjsModuleBindings(fs.readFile(file.pathname));
9+
bindings.exports.forEach((name) => exports.add(name));
810

911
// CJS always exports `default`
10-
if (!exports.includes("default")) {
11-
exports.push("default");
12+
if (!exports.has("default")) {
13+
exports.add("default");
1214
}
1315

1416
// Additionally, resolve facade reexports
15-
const lastResolvableReexport = (() => {
16-
for (const source of reexports.reverse()) {
17-
try {
18-
return cjsResolve(fs, source, file);
19-
} catch {}
20-
}
21-
})();
22-
if (
23-
lastResolvableReexport &&
24-
lastResolvableReexport.format === "commonjs" &&
25-
!seen.has(lastResolvableReexport.resolved.pathname)
26-
) {
27-
const extra = getCjsModuleNamespace(fs, lastResolvableReexport.resolved, seen);
28-
exports.push(...extra.filter((name) => !exports.includes(name)));
17+
18+
for (const source of bindings.reexports.reverse()) {
19+
try {
20+
const { format, resolved } = cjsResolve(fs, source, file);
21+
if (format === "commonjs" && !seen.has(resolved.pathname)) {
22+
const reexported = getCjsModuleNamespace(fs, resolved, seen);
23+
reexported.forEach((name) => exports.add(name));
24+
}
25+
} catch {}
2926
}
3027

3128
return exports;

packages/core/src/internal/esm/esmNamespace.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ export function getEsmModuleNamespace(
2222
seen.add(resolved.pathname);
2323

2424
if (format === "commonjs") {
25-
return getCjsModuleNamespace(fs, resolved);
25+
return [...getCjsModuleNamespace(fs, resolved)];
2626
}
2727

2828
// Parse module bindings
Binary file not shown.

0 commit comments

Comments
 (0)