Skip to content

Commit

Permalink
Expose renderer in CLI package
Browse files Browse the repository at this point in the history
  • Loading branch information
andrewbranch committed Feb 8, 2024
1 parent 0224946 commit 783555d
Show file tree
Hide file tree
Showing 8 changed files with 72 additions and 49 deletions.
7 changes: 6 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,16 @@
},
"files": [
"LICENSE",
"dist/**/*.js"
"dist/**/*.js",
"dist/**/*.js.map",
"dist/**/*.d.ts"
],
"bin": {
"attw": "./dist/index.js"
},
"exports": {
"./internal/render": "./dist/render/index.js"
},
"publishConfig": {
"access": "public"
},
Expand Down
36 changes: 19 additions & 17 deletions packages/cli/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,20 @@ import { major, minor } from "semver";
const packageJson = createRequire(import.meta.url)("../package.json");
const version = packageJson.version;

const formats = ["auto", "table", "table-flipped", "ascii", "json"] as const;

type Format = (typeof formats)[number];

export interface Opts {
const formats = Object.keys({
auto: true,
json: true,
ascii: true,
table: true,
"table-flipped": true,
} satisfies Record<render.Format, any>) as render.Format[];

interface Opts extends render.RenderOptions {
pack?: boolean;
fromNpm?: boolean;
definitelyTyped?: boolean | string;
summary?: boolean;
emoji?: boolean;
color?: boolean;
quiet?: boolean;
configPath?: string;
ignoreRules?: string[];
format: Format;

entrypoints?: string[];
includeEntrypoints?: string[];
Expand Down Expand Up @@ -81,9 +80,6 @@ particularly ESM-related module resolution issues.`,
.action(async (fileOrDirectory = ".") => {
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,
);

if (opts.quiet) {
console.log = () => {};
Expand Down Expand Up @@ -210,21 +206,27 @@ particularly ESM-related module resolution issues.`,

console.log(JSON.stringify(result));

if (analysis.types && analysis.problems.some((problem) => !opts.ignoreRules?.includes(problem.kind)))
if (
analysis.types &&
analysis.problems.some((problem) => !opts.ignoreRules?.includes(problemFlags[problem.kind]))
)
process.exit(1);

return;
}

console.log();
if (analysis.types) {
await render.typed(analysis, opts);
console.log(await render.typed(analysis, opts));

if (analysis.types && analysis.problems.some((problem) => !opts.ignoreRules?.includes(problem.kind))) {
if (
analysis.types &&
analysis.problems.some((problem) => !opts.ignoreRules?.includes(problemFlags[problem.kind]))
) {
process.exitCode = 1;
}
} else {
render.untyped(analysis as core.UntypedResult);
console.log(render.untyped(analysis as core.UntypedResult));
}

if (deleteTgz) {
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/src/problemUtils.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as core from "@arethetypeswrong/core";
import type { ProblemKind } from "@arethetypeswrong/core";

export const problemFlags: Record<ProblemKind, string> = {
export const problemFlags = {
NoResolution: "no-resolution",
UntypedResolution: "untyped-resolution",
FalseCJS: "false-cjs",
Expand All @@ -13,7 +13,7 @@ export const problemFlags: Record<ProblemKind, string> = {
MissingExportEquals: "missing-export-equals",
UnexpectedModuleSyntax: "unexpected-module-syntax",
InternalResolutionError: "internal-resolution-error",
};
} as const satisfies Record<ProblemKind, string>;

export const resolutionKinds: Record<core.ResolutionKind, string> = {
node10: "node10",
Expand Down
11 changes: 11 additions & 0 deletions packages/cli/src/render/index.ts
Original file line number Diff line number Diff line change
@@ -1,2 +1,13 @@
import type { problemFlags } from "../problemUtils.js";

export type Format = "auto" | "table" | "table-flipped" | "ascii" | "json";
export interface RenderOptions {
ignoreRules?: (typeof problemFlags)[keyof typeof problemFlags][];
format?: Format;
color?: boolean;
summary?: boolean;
emoji?: boolean;
}

export * from "./typed.js";
export * from "./untyped.js";
54 changes: 28 additions & 26 deletions packages/cli/src/render/typed.ts
Original file line number Diff line number Diff line change
@@ -1,48 +1,44 @@
import * as core from "@arethetypeswrong/core";
import { filterProblems, problemAffectsEntrypoint, problemKindInfo } from "@arethetypeswrong/core/problems";
import { allResolutionKinds, getResolutionOption, groupProblemsByKind } from "@arethetypeswrong/core/utils";
import chalk from "chalk";
import Table, { type GenericTable, type HorizontalTableRow } from "cli-table3";
import { marked } from "marked";

import { filterProblems, problemAffectsEntrypoint, problemKindInfo } from "@arethetypeswrong/core/problems";
import type { Opts } from "../index.js";
import TerminalRenderer from "marked-terminal";
import { moduleKinds, problemFlags, resolutionKinds } from "../problemUtils.js";
import { asciiTable } from "./asciiTable.js";
import TerminalRenderer from "marked-terminal";
import type { RenderOptions } from "./index.js";

export async function typed(analysis: core.Analysis, opts: Opts) {
const problems = analysis.problems.filter((problem) => !opts.ignoreRules || !opts.ignoreRules.includes(problem.kind));
export async function typed(analysis: core.Analysis, opts: RenderOptions): Promise<string> {
let output = "";
const problems = analysis.problems.filter(
(problem) => !opts.ignoreRules || !opts.ignoreRules.includes(problemFlags[problem.kind]),
);
const grouped = groupProblemsByKind(problems);
const entrypoints = Object.keys(analysis.entrypoints);
marked.setOptions({
renderer: new TerminalRenderer(),
});

console.log(`${analysis.packageName} v${analysis.packageVersion}`);
out(`${analysis.packageName} v${analysis.packageVersion}`);
if (analysis.types.kind === "@types") {
console.log(`${analysis.types.packageName} v${analysis.types.packageVersion}`);
out(`${analysis.types.packageName} v${analysis.types.packageVersion}`);
}
console.log();
out();
if (Object.keys(analysis.buildTools).length) {
console.log("Build tools:");
console.log(
out("Build tools:");
out(
Object.entries(analysis.buildTools)
.map(([tool, version]) => {
return `- ${tool}@${version}`;
})
.join("\n"),
);
console.log();
out();
}

if (opts.ignoreRules && opts.ignoreRules.length) {
console.log(
chalk.gray(
` (ignoring rules: ${opts.ignoreRules
.map((rule) => `'${problemFlags[rule as core.ProblemKind]}'`)
.join(", ")})\n`,
),
);
out(chalk.gray(` (ignoring rules: ${opts.ignoreRules.map((rule) => `'${rule}'`).join(", ")})\n`));
}

if (opts.summary) {
Expand All @@ -54,7 +50,7 @@ export async function typed(analysis: core.Analysis, opts: Opts) {
return `${emoji}${description}`;
});

console.log(summaryTexts.join("") || defaultSummary);
out(summaryTexts.join("") || defaultSummary);
}

const entrypointNames = entrypoints.map(
Expand Down Expand Up @@ -119,25 +115,31 @@ export async function typed(analysis: core.Analysis, opts: Opts) {

switch (opts.format) {
case "table":
console.log(table!.toString());
out(table!.toString());
break;
case "table-flipped":
console.log(flippedTable!.toString());
out(flippedTable!.toString());
break;
case "ascii":
console.log(asciiTable(table!));
out(asciiTable(table!));
break;
case "auto":
const terminalWidth = process.stdout.columns || 133; // This looks like GitHub Actions' width
if (table!.width <= terminalWidth) {
console.log(table!.toString());
out(table!.toString());
} else if (flippedTable!.width <= terminalWidth) {
console.log(flippedTable!.toString());
out(flippedTable!.toString());
} else {
console.log(asciiTable(table!));
out(asciiTable(table!));
}
break;
}

return output.trimEnd();

function out(s: string = "") {
output += s + "\n";
}
}

function memo<Args extends (string | number)[], Result>(fn: (...args: Args) => Result): (...args: Args) => Result {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/src/render/untyped.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as core from "@arethetypeswrong/core";

export function untyped(analysis: core.UntypedResult) {
console.log("This package does not contain types.\nDetails: ", analysis);
return "This package does not contain types.\nDetails: " + JSON.stringify(analysis, null, 2);
}
6 changes: 5 additions & 1 deletion packages/cli/test/snapshots/[email protected]
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@ $ attw [email protected] -f table-flipped
This package does not contain types.
Details: { packageName: 'ejs', packageVersion: '3.1.9', types: false }
Details: {
"packageName": "ejs",
"packageVersion": "3.1.9",
"types": false
}
```
Expand Down
1 change: 0 additions & 1 deletion packages/cli/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
"rootDir": "src",
"types": ["ts-expose-internals", "node"],
"outDir": "./dist",
"declarationDir": "./lib",
"sourceMap": true
},
"include": ["src"],
Expand Down

0 comments on commit 783555d

Please sign in to comment.