Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use exit code 3 for errors, 1 for failures #115

Merged
merged 2 commits into from
Nov 3, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/angry-timers-shave.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@arethetypeswrong/cli": patch
---

Use exit code 127 for errors, 1 for failures
33 changes: 19 additions & 14 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,13 +46,13 @@ program
.name("attw")
.description(
`${chalk.bold.blue(
"Are the Types Wrong?"
"Are the Types Wrong?",
)} attempts to analyze npm package contents for issues with their TypeScript types,
particularly ESM-related module resolution issues.`
particularly ESM-related module resolution issues.`,
)
.argument(
"[file-directory-or-package-spec]",
"the packed .tgz, or directory containing package.json with --pack, or package spec with --from-npm"
"the packed .tgz, or directory containing package.json with --pack, or package spec with --from-npm",
)
.option("-P, --pack", "Run `npm pack` in the specified directory and delete the resulting .tgz file afterwards")
.option("-p, --from-npm", "Read from the npm registry instead of a local file")
Expand All @@ -64,15 +64,15 @@ particularly ESM-related module resolution issues.`
"--entrypoints <entrypoints...>",
"Specify an exhaustive list of entrypoints to check. " +
'The package root is `"." Specifying this option disables automatic entrypoint discovery, ' +
"and overrides the `--include-entrypoints` and `--exclude-entrypoints` options."
"and overrides the `--include-entrypoints` and `--exclude-entrypoints` options.",
)
.option(
"--include-entrypoints <entrypoints...>",
"Specify entrypoints to check in addition to automatically discovered ones."
"Specify entrypoints to check in addition to automatically discovered ones.",
)
.option("--exclude-entrypoints <entrypoints...>", "Specify entrypoints to exclude from checking.")
.addOption(
new Option("--ignore-rules <rules...>", "Specify rules to ignore").choices(Object.values(problemFlags)).default([])
new Option("--ignore-rules <rules...>", "Specify rules to ignore").choices(Object.values(problemFlags)).default([]),
)
.option("--summary, --no-summary", "Whether to print summary information about the different errors")
.option("--emoji, --no-emoji", "Whether to use any emojis")
Expand All @@ -82,7 +82,7 @@ particularly ESM-related module resolution issues.`
const opts = program.opts<Opts>();
await readConfig(program, opts.configPath);
opts.ignoreRules = opts.ignoreRules?.map(
(value) => Object.keys(problemFlags).find((key) => problemFlags[key as core.ProblemKind] === value) as string
(value) => Object.keys(problemFlags).find((key) => problemFlags[key as core.ProblemKind] === value) as string,
);

if (opts.quiet) {
Expand Down Expand Up @@ -114,7 +114,7 @@ particularly ESM-related module resolution issues.`
let pkg;
if (dtIsPath) {
const dtPackage = core.createPackageFromTarballData(
new Uint8Array(await readFile(opts.definitelyTyped as string))
new Uint8Array(await readFile(opts.definitelyTyped as string)),
);
const pkgVersion =
result.data.versionKind === "none"
Expand Down Expand Up @@ -150,15 +150,15 @@ particularly ESM-related module resolution issues.`
if (!(await stat(path.join(fileOrDirectory, "package.json")).catch(() => false))) {
program.error(
`Specified directory must contain a package.json. No package.json found in ${path.resolve(
fileOrDirectory
)}.`
fileOrDirectory,
)}.`,
);
}

if (!opts.pack) {
if (!process.stdout.isTTY) {
program.error(
"Specifying a directory requires the --pack option to confirm that running `npm pack` is ok."
"Specifying a directory requires the --pack option to confirm that running `npm pack` is ok.",
);
}
const rl = readline.createInterface(process.stdin, process.stdout);
Expand All @@ -173,7 +173,7 @@ particularly ESM-related module resolution issues.`

fileName = deleteTgz = path.resolve(
fileOrDirectory,
execSync("npm pack", { cwd: fileOrDirectory, encoding: "utf8", stdio: "pipe" }).trim()
execSync("npm pack", { cwd: fileOrDirectory, encoding: "utf8", stdio: "pipe" }).trim(),
);
}
const file = await readFile(fileName);
Expand All @@ -182,7 +182,7 @@ particularly ESM-related module resolution issues.`
? core
.createPackageFromTarballData(data)
.mergedWithTypes(
core.createPackageFromTarballData(new Uint8Array(await readFile(opts.definitelyTyped as string)))
core.createPackageFromTarballData(new Uint8Array(await readFile(opts.definitelyTyped as string))),
)
: core.createPackageFromTarballData(data);
analysis = await core.checkPackage(pkg, {
Expand Down Expand Up @@ -234,9 +234,14 @@ program.parse(process.argv);
function handleError(error: unknown, title: string): never {
if (error && typeof error === "object" && "message" in error) {
program.error(`error while ${title}:\n${error.message}`, {
exitCode: 127,
code: "code" in error && typeof error.code === "string" ? error.code : "UNKNOWN",
});
}

program.error(`unknown error while ${title}`, { code: "UNKNOWN" });
program.error(`unknown error while ${title}`, { code: "UNKNOWN", exitCode: 127 });
}

process.on("unhandledRejection", (error) => {
handleError(error, "checking package");
});
6 changes: 5 additions & 1 deletion packages/cli/test/snapshots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ const tests = [
["[email protected]"],
["[email protected]"],
["[email protected]"],
["[email protected]"],
["[email protected]"],

["[email protected]", "--entrypoints vue"],
["[email protected]", "--entrypoints . jsx-runtime"],
Expand Down Expand Up @@ -61,6 +63,7 @@ describe("snapshots", async () => {
test(fixture, async () => {
const tarballPath = new URL(`../../../core/test/fixtures/${tarball}`, import.meta.url).pathname;
let stdout;
let stderr = "";
let exitCode = 0;
try {
stdout = execSync(`${attw} ${tarballPath} ${options ?? defaultOpts}`, {
Expand All @@ -69,6 +72,7 @@ describe("snapshots", async () => {
});
} catch (error) {
stdout = (error as SpawnSyncReturns<string>).stdout;
stderr = (error as SpawnSyncReturns<string>).stderr;
exitCode = (error as SpawnSyncReturns<string>).status ?? 1;
}
const snapshotURL = new URL(`../snapshots/${fixture.replace(/\//g, "")}.md`, import.meta.url);
Expand All @@ -79,7 +83,7 @@ describe("snapshots", async () => {
"```",
`$ attw ${tarball} ${options ?? defaultOpts}`,
"",
stdout,
[stdout, stderr].filter(Boolean).join("\n"),
"",
"```",
"",
Expand Down
12 changes: 12 additions & 0 deletions packages/cli/test/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# [email protected]

```
$ attw [email protected] -f table-flipped

error while checking file:
Expected double-quoted property name in JSON at position 450


```

Exit code: 127
25 changes: 25 additions & 0 deletions packages/cli/test/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# [email protected]

```
$ attw [email protected] -f table-flipped


moment v2.29.1

Build tools:
- typescript@^1.8.10
- [email protected]

No problems found 🌟


┌──────────┬────────┬───────────────────┬───────────────────┬─────────┐
│ │ node10 │ node16 (from CJS) │ node16 (from ESM) │ bundler │
├──────────┼────────┼───────────────────┼───────────────────┼─────────┤
│ "moment" │ 🟢 │ 🟢 (CJS) │ 🟢 (CJS) │ 🟢 │
└──────────┴────────┴───────────────────┴───────────────────┴─────────┘


```

Exit code: 0
Binary file added packages/core/test/fixtures/[email protected]
Binary file not shown.
Binary file added packages/core/test/fixtures/[email protected]
Binary file not shown.
19 changes: 15 additions & 4 deletions packages/core/test/snapshots.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ describe("snapshots", async () => {
"[email protected]": "@[email protected]",
};

const errorPackages = ["[email protected]"];

for (const fixture of fs.readdirSync(new URL("../fixtures", import.meta.url))) {
if (fixture === ".DS_Store" || fixture.startsWith("@types__")) {
continue;
Expand All @@ -35,10 +37,19 @@ describe("snapshots", async () => {
const typesTarball = typesPackages[fixture]
? await readFile(new URL(`../fixtures/${typesPackages[fixture]}`, import.meta.url))
: undefined;
const pkg = createPackageFromTarballData(tarball);
const analysis = await checkPackage(
typesTarball ? pkg.mergedWithTypes(createPackageFromTarballData(typesTarball)) : pkg
);
let analysis;
try {
const pkg = createPackageFromTarballData(tarball);
analysis = await checkPackage(
typesTarball ? pkg.mergedWithTypes(createPackageFromTarballData(typesTarball)) : pkg,
);
} catch (error) {
if (errorPackages.includes(fixture)) {
return;
}
throw error;
}

const snapshotURL = new URL(`../snapshots/${fixture}.json`, import.meta.url);
const expectedSnapshot = JSON.stringify(analysis, null, 2) + "\n";

Expand Down
165 changes: 165 additions & 0 deletions packages/core/test/snapshots/[email protected]
Original file line number Diff line number Diff line change
@@ -0,0 +1,165 @@
{
"packageName": "moment",
"packageVersion": "2.29.1",
"types": {
"kind": "included"
},
"buildTools": {
"typescript": "^1.8.10",
"rollup": "2.17.1"
},
"entrypoints": {
".": {
"subpath": ".",
"resolutions": {
"node10": {
"name": ".",
"resolutionKind": "node10",
"resolution": {
"fileName": "/node_modules/moment/ts3.1-typings/moment.d.ts",
"isJson": false,
"isTypeScript": true,
"trace": [
"======== Resolving module 'moment' from '/index.ts'. ========",
"Explicitly specified module resolution kind: 'Node10'.",
"Loading module 'moment' from 'node_modules' folder, target file types: TypeScript, Declaration.",
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
"Found 'package.json' at '/node_modules/moment/package.json'.",
"File '/node_modules/moment.ts' does not exist.",
"File '/node_modules/moment.tsx' does not exist.",
"File '/node_modules/moment.d.ts' does not exist.",
"'package.json' has a 'typesVersions' field with version-specific path mappings.",
"'package.json' has 'typings' field './moment.d.ts' that references '/node_modules/moment/moment.d.ts'.",
"'package.json' has a 'typesVersions' entry '>=3.1' that matches compiler version '5.2.2', looking for a pattern to match module name 'moment.d.ts'.",
"Module name 'moment.d.ts', matched pattern '*'.",
"Trying substitution 'ts3.1-typings/*', candidate module location: 'ts3.1-typings/moment.d.ts'.",
"File '/node_modules/moment/ts3.1-typings/moment.d.ts' exists - use it as a name resolution result.",
"======== Module name 'moment' was successfully resolved to '/node_modules/moment/ts3.1-typings/moment.d.ts' with Package ID 'moment/ts3.1-typings/[email protected]'. ========"
]
},
"files": [
"/node_modules/typescript/lib/lib.d.ts",
"/node_modules/moment/ts3.1-typings/moment.d.ts"
],
"visibleProblems": []
},
"node16-cjs": {
"name": ".",
"resolutionKind": "node16-cjs",
"resolution": {
"fileName": "/node_modules/moment/ts3.1-typings/moment.d.ts",
"isJson": false,
"isTypeScript": true,
"trace": [
"======== Resolving module 'moment' from '/index.ts'. ========",
"Explicitly specified module resolution kind: 'Node16'.",
"Resolving in CJS mode with conditions 'require', 'types', 'node'.",
"File '/package.json' does not exist.",
"Loading module 'moment' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
"Found 'package.json' at '/node_modules/moment/package.json'.",
"File '/node_modules/moment.ts' does not exist.",
"File '/node_modules/moment.tsx' does not exist.",
"File '/node_modules/moment.d.ts' does not exist.",
"'package.json' has a 'typesVersions' field with version-specific path mappings.",
"'package.json' has 'typings' field './moment.d.ts' that references '/node_modules/moment/moment.d.ts'.",
"'package.json' has a 'typesVersions' entry '>=3.1' that matches compiler version '5.2.2', looking for a pattern to match module name 'moment.d.ts'.",
"Module name 'moment.d.ts', matched pattern '*'.",
"Trying substitution 'ts3.1-typings/*', candidate module location: 'ts3.1-typings/moment.d.ts'.",
"File '/node_modules/moment/ts3.1-typings/moment.d.ts' exists - use it as a name resolution result.",
"======== Module name 'moment' was successfully resolved to '/node_modules/moment/ts3.1-typings/moment.d.ts' with Package ID 'moment/ts3.1-typings/[email protected]'. ========"
]
},
"files": [
"/node_modules/typescript/lib/lib.d.ts",
"/node_modules/moment/ts3.1-typings/moment.d.ts"
],
"visibleProblems": []
},
"node16-esm": {
"name": ".",
"resolutionKind": "node16-esm",
"resolution": {
"fileName": "/node_modules/moment/ts3.1-typings/moment.d.ts",
"isJson": false,
"isTypeScript": true,
"trace": [
"======== Resolving module 'moment' from '/index.mts'. ========",
"Explicitly specified module resolution kind: 'Node16'.",
"Resolving in ESM mode with conditions 'import', 'types', 'node'.",
"File '/package.json' does not exist according to earlier cached lookups.",
"Loading module 'moment' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
"File '/node_modules/moment/package.json' exists according to earlier cached lookups.",
"'package.json' has 'typings' field './moment.d.ts' that references '/node_modules/moment/moment.d.ts'.",
"'package.json' has a 'typesVersions' entry '>=3.1' that matches compiler version '5.2.2', looking for a pattern to match module name 'moment.d.ts'.",
"Module name 'moment.d.ts', matched pattern '*'.",
"Trying substitution 'ts3.1-typings/*', candidate module location: 'ts3.1-typings/moment.d.ts'.",
"File '/node_modules/moment/ts3.1-typings/moment.d.ts' exists - use it as a name resolution result.",
"======== Module name 'moment' was successfully resolved to '/node_modules/moment/ts3.1-typings/moment.d.ts' with Package ID 'moment/ts3.1-typings/[email protected]'. ========"
]
},
"files": [
"/node_modules/typescript/lib/lib.d.ts",
"/node_modules/moment/ts3.1-typings/moment.d.ts"
],
"visibleProblems": []
},
"bundler": {
"name": ".",
"resolutionKind": "bundler",
"resolution": {
"fileName": "/node_modules/moment/ts3.1-typings/moment.d.ts",
"isJson": false,
"isTypeScript": true,
"trace": [
"======== Resolving module 'moment' from '/index.ts'. ========",
"Explicitly specified module resolution kind: 'Bundler'.",
"Resolving in CJS mode with conditions 'import', 'types'.",
"File '/package.json' does not exist.",
"Loading module 'moment' from 'node_modules' folder, target file types: TypeScript, JavaScript, Declaration, JSON.",
"Searching all ancestor node_modules directories for preferred extensions: TypeScript, Declaration.",
"Found 'package.json' at '/node_modules/moment/package.json'.",
"File '/node_modules/moment.ts' does not exist.",
"File '/node_modules/moment.tsx' does not exist.",
"File '/node_modules/moment.d.ts' does not exist.",
"'package.json' has a 'typesVersions' field with version-specific path mappings.",
"'package.json' has 'typings' field './moment.d.ts' that references '/node_modules/moment/moment.d.ts'.",
"'package.json' has a 'typesVersions' entry '>=3.1' that matches compiler version '5.2.2', looking for a pattern to match module name 'moment.d.ts'.",
"Module name 'moment.d.ts', matched pattern '*'.",
"Trying substitution 'ts3.1-typings/*', candidate module location: 'ts3.1-typings/moment.d.ts'.",
"File '/node_modules/moment/ts3.1-typings/moment.d.ts' exists - use it as a name resolution result.",
"======== Module name 'moment' was successfully resolved to '/node_modules/moment/ts3.1-typings/moment.d.ts' with Package ID 'moment/ts3.1-typings/[email protected]'. ========"
]
},
"files": [
"/node_modules/typescript/lib/lib.d.ts",
"/node_modules/moment/ts3.1-typings/moment.d.ts"
],
"visibleProblems": []
}
},
"hasTypes": true,
"isWildcard": false
}
},
"programInfo": {
"node10": {},
"node16": {
"moduleKinds": {
"/node_modules/typescript/lib/lib.d.ts": {
"detectedKind": 1,
"detectedReason": "no:type",
"reasonFileName": "/node_modules/typescript/lib/lib.d.ts"
},
"/node_modules/moment/ts3.1-typings/moment.d.ts": {
"detectedKind": 1,
"detectedReason": "no:type",
"reasonFileName": "/node_modules/moment/package.json"
}
}
},
"bundler": {}
},
"problems": []
}
2 changes: 0 additions & 2 deletions packages/history/scripts/generateFull.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,6 @@ const excludedSpecs = [
"[email protected]", // File not found: /node_modules/next/types/misc.d.ts
"[email protected]", // File not found: /node_modules/next/types/misc.d.ts
"[email protected]", // File not found: /node_modules/next/types/misc.d.ts
"[email protected]", // Invalid gzip data
"[email protected]", // Invalid gzip data
Comment on lines -32 to -33
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These were fixed by #103

];

// Array of month starts from 2022-01-01 until the first of this month
Expand Down