Skip to content

Commit c8d54a5

Browse files
authored
Merge pull request #59 from arethetypeswrong/customize-entrypoints
Support customizable entrypoints
2 parents 445b1f2 + 880d013 commit c8d54a5

30 files changed

+1081
-461
lines changed

.changeset/forty-islands-walk.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@arethetypeswrong/core": minor
3+
---
4+
5+
Add `options` parameter to `checkPackage` with support for customizing which entrypoints get analyzed.

.changeset/thick-cycles-knock.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@arethetypeswrong/cli": minor
3+
---
4+
5+
Add `--entrypoints`, `--include-entrypoints`, and `--exclude-entrypoints` options to customize which entrypoints get analyzed.

packages/cli/README.md

Lines changed: 42 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -18,21 +18,31 @@ npm i -g @arethetypeswrong/cli
1818

1919
The `attw` command acts very similarly to [arethetypeswrong.github.io](https://arethetypeswrong.github.io/), with some additional features that are useful for command line usage.
2020

21-
The usage is:
21+
The CLI can check an `npm pack`ed tarball:
2222

2323
```shell
2424
npm pack
25-
attw [options] <file-name>
25+
attw cool-package-1.0.0.tgz
26+
# or
27+
attw $(npm pack)
2628
```
2729

28-
Where `<file-name>` is a required positional argument (the path to a local `.tar.gz` file from `npm pack`).
30+
or pack one in-place by specifying `--pack` and a directory:
31+
32+
```shell
33+
attw --pack .
34+
```
35+
36+
or check a package from npm:
37+
38+
```shell
39+
attw --from-npm @arethetypeswrong/cli
40+
```
2941

3042
## Configuration
3143

3244
`attw` supports a JSON config file (by default named `.attw.json`) which allows you to pre-set the command line arguments. The options are a one-to-one mapping of the command line flags, changed to camelCase, and are all documented in their relevant `Options` section below.
3345

34-
Note that the `--config-path` option cannot be set from the config file :upside_down_face:
35-
3646
### Options
3747

3848
#### Help
@@ -55,11 +65,32 @@ In the CLI: `--version`, `-v`
5565
attw --version
5666
```
5767

68+
### Pack
69+
70+
Specify a directory to run `npm pack` in (instead of specifying a tarball filename), analyze the resulting tarball, and delete it afterwards.
71+
72+
```shell
73+
attw --pack .
74+
```
75+
76+
#### From NPM
77+
78+
Specify the name (and, optionally, version range) of a package from the NPM registry instead of a local tarball filename.
79+
80+
In the CLI: `--from-npm`, `-p`
81+
82+
```shell
83+
attw --from-npm <package-name>
84+
```
85+
86+
In the config file, `fromNpm` can be a boolean value.
87+
5888
#### Format
5989

6090
The format to print the output in. Defaults to `table`.
6191

6292
The available values are:
93+
6394
- `table`
6495
- `table-flipped`, where the resolution kinds are the table's head, and the entry points label the table's rows
6596
- `ascii`, for large tables where the output is clunky
@@ -73,23 +104,22 @@ attw --format <format> <file-name>
73104

74105
In the config file, `format` can be a string value.
75106

76-
#### From NPM
77-
78-
Treat `<file-name>` as the name (and, optionally, version) of a package from the NPM registry.
107+
#### Entrypoints
79108

80-
In the CLI: `--from-npm`, `-p`
109+
`attw` automatically discovers package entrypoints by looking at package.json `exports` and subdirectories with additional package.json files. This automatic discovery process can be overridden with the `--entrypoints` option, or altered with the `--include-entrypoints` and `--exclude-entrypoints` options:
81110

82111
```shell
83-
attw --from-npm <package-name>
112+
attw --pack . --entrypoints . one two three # Just ".", "./one", "./two", "./three"
113+
attw --pack . --include-entrypoints added # Auto-discovered entyrpoints plus "./added"
114+
attw --pack . --exclude-entrypoints styles.css # Auto-discovered entrypoints except "./styles.css"
84115
```
85116

86-
In the config file, `fromNpm` can be a boolean value.
87-
88117
#### Ignore Rules
89118

90119
Specifies rules/problems to ignore (i.e. not raise an error for).
91120

92121
The available values are:
122+
93123
- `wildcard`
94124
- `no-resolution`
95125
- `untyped-resolution`
@@ -171,4 +201,3 @@ attw --config-path <path> <file-name>
171201
```
172202

173203
Cannot be set from within the config file itself.
174-

packages/cli/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
"directory": "packages/cli"
2121
},
2222
"files": [
23-
"dist"
23+
"dist/**/*.js"
2424
],
2525
"bin": {
2626
"attw": "./dist/index.js"

packages/cli/src/index.ts

Lines changed: 35 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,10 @@ export interface Opts {
3232
configPath?: string;
3333
ignoreRules?: string[];
3434
format: Format;
35+
36+
entrypoints?: string[];
37+
includeEntrypoints?: string[];
38+
excludeEntrypoints?: string[];
3539
}
3640

3741
program
@@ -49,17 +53,28 @@ particularly ESM-related module resolution issues.`
4953
"[file-directory-or-package-spec]",
5054
"the packed .tgz, or directory containing package.json with --pack, or package spec with --from-npm"
5155
)
52-
.option("-P, --pack", "run `npm pack` in the specified directory and delete the resulting .tgz file afterwards")
53-
.option("-p, --from-npm", "read from the npm registry instead of a local file")
54-
.addOption(new Option("-f, --format <format>", "specify the print format").choices(formats).default("table"))
55-
.option("-q, --quiet", "don't print anything to STDOUT (overrides all other options)")
56+
.option("-P, --pack", "Run `npm pack` in the specified directory and delete the resulting .tgz file afterwards")
57+
.option("-p, --from-npm", "Read from the npm registry instead of a local file")
58+
.addOption(new Option("-f, --format <format>", "Specify the print format").choices(formats).default("table"))
59+
.option("-q, --quiet", "Don't print anything to STDOUT (overrides all other options)")
60+
.option(
61+
"--entrypoints <entrypoints...>",
62+
"Specify an exhaustive list of entrypoints to check. " +
63+
'The package root is `"." Specifying this option disables automatic entrypoint discovery, ' +
64+
"and overrides the `--include-entrypoints` and `--exclude-entrypoints` options."
65+
)
66+
.option(
67+
"--include-entrypoints <entrypoints...>",
68+
"Specify entrypoints to check in addition to automatically discovered ones."
69+
)
70+
.option("--exclude-entrypoints <entrypoints...>", "Specify entrypoints to exclude from checking.")
5671
.addOption(
57-
new Option("--ignore-rules <rules...>", "specify rules to ignore").choices(Object.values(problemFlags)).default([])
72+
new Option("--ignore-rules <rules...>", "Specify rules to ignore").choices(Object.values(problemFlags)).default([])
5873
)
59-
.option("--summary, --no-summary", "whether to print summary information about the different errors")
60-
.option("--emoji, --no-emoji", "whether to use any emojis")
61-
.option("--color, --no-color", "whether to use any colors (the FORCE_COLOR env variable is also available)")
62-
.option("--config-path <path>", "path to config file (default: ./.attw.json)")
74+
.option("--summary, --no-summary", "Whether to print summary information about the different errors")
75+
.option("--emoji, --no-emoji", "Whether to use any emojis")
76+
.option("--color, --no-color", "Whether to use any colors (the FORCE_COLOR env variable is also available)")
77+
.option("--config-path <path>", "Path to config file (default: ./.attw.json)")
6378
.action(async (fileOrDirectory = ".") => {
6479
const opts = program.opts<Opts>();
6580
await readConfig(program, opts.configPath);
@@ -87,7 +102,12 @@ particularly ESM-related module resolution issues.`
87102
program.error(result.error);
88103
} else {
89104
analysis = await core.checkPackage(
90-
await core.createPackageFromNpm(`${result.data.name}@${result.data.version}`)
105+
await core.createPackageFromNpm(`${result.data.name}@${result.data.version}`),
106+
{
107+
entrypoints: opts.entrypoints,
108+
includeEntrypoints: opts.includeEntrypoints,
109+
excludeEntrypoints: opts.excludeEntrypoints,
110+
}
91111
);
92112
}
93113
} catch (error) {
@@ -136,7 +156,11 @@ particularly ESM-related module resolution issues.`
136156
}
137157
const file = await readFile(fileName);
138158
const data = new Uint8Array(file);
139-
analysis = await core.checkPackage(await core.createPackageFromTarballData(data));
159+
analysis = await core.checkPackage(await core.createPackageFromTarballData(data), {
160+
entrypoints: opts.entrypoints,
161+
includeEntrypoints: opts.includeEntrypoints,
162+
excludeEntrypoints: opts.excludeEntrypoints,
163+
});
140164
} catch (error) {
141165
handleError(error, "checking file");
142166
}

packages/cli/test/snapshots.test.ts

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import fs from "fs";
21
import { access, readFile, writeFile } from "fs/promises";
32
import { execSync, type SpawnSyncReturns } from "child_process";
43
import assert from "node:assert";
@@ -7,6 +6,32 @@ import { after, describe, test } from "node:test";
76
const attw = `node ${new URL("../../dist/index.js", import.meta.url).pathname}`;
87
const updateSnapshots = process.env.UPDATE_SNAPSHOTS;
98

9+
const tests = [
10+
["@apollo__client-3.7.16.tgz"],
11+
12+
13+
14+
15+
16+
17+
["[email protected]", "-f table"],
18+
19+
20+
["[email protected]", "-f ascii"],
21+
22+
23+
24+
25+
26+
27+
["[email protected]", "--entrypoints vue"],
28+
["[email protected]", "--entrypoints . jsx-runtime"],
29+
["[email protected]", "--exclude-entrypoints macros -f ascii"],
30+
["[email protected]", "--include-entrypoints ./foo -f ascii"],
31+
];
32+
33+
const defaultOpts = "-f table-flipped";
34+
1035
describe("snapshots", async () => {
1136
const snapshotsWritten: URL[] = [];
1237

@@ -22,27 +47,28 @@ describe("snapshots", async () => {
2247
}
2348
});
2449

25-
for (const fixture of fs.readdirSync(new URL("../../../core/test/fixtures", import.meta.url))) {
26-
if (fixture === ".DS_Store") {
27-
continue;
28-
}
50+
for (const [tarball, options] of tests) {
51+
const fixture = tarball + (options ? ` ${options}` : "");
2952
test(fixture, async () => {
30-
const tarballPath = new URL(`../../../core/test/fixtures/${fixture}`, import.meta.url).pathname;
53+
const tarballPath = new URL(`../../../core/test/fixtures/${tarball}`, import.meta.url).pathname;
3154
let stdout;
3255
let exitCode = 0;
3356
try {
34-
stdout = execSync(`${attw} ${tarballPath}`, { encoding: "utf8", env: { ...process.env, FORCE_COLOR: "0" } });
57+
stdout = execSync(`${attw} ${tarballPath} ${options ?? defaultOpts}`, {
58+
encoding: "utf8",
59+
env: { ...process.env, FORCE_COLOR: "0" },
60+
});
3561
} catch (error) {
3662
stdout = (error as SpawnSyncReturns<string>).stdout;
3763
exitCode = (error as SpawnSyncReturns<string>).status ?? 1;
3864
}
39-
const snapshotURL = new URL(`../snapshots/${fixture}.md`, import.meta.url);
65+
const snapshotURL = new URL(`../snapshots/${fixture.replace(/\//g, "")}.md`, import.meta.url);
4066
// prettier-ignore
4167
const expectedSnapshot = [
4268
`# ${fixture}`,
4369
"",
4470
"```",
45-
`$ attw ${fixture}`,
71+
`$ attw ${tarball} ${options ?? defaultOpts}`,
4672
"",
4773
stdout,
4874
"",

0 commit comments

Comments
 (0)