8000 feat: Add `oxfmt` support by aklinker1 · Pull Request #11 · aklinker1/check · GitHub
[go: up one dir, main page]

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
9 changes: 9 additions & 0 deletions .oxfmtrc.jsonc
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"$schema": "./node_modules/oxfmt/configuration_schema.json",
"ignorePatterns": ["CHANGELOG.md"],
"sortImports": {},
"proseWrap": "always",
"sortPackageJson": {
"sortScripts": true,
},
}
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
# Check

An opinionated CLI tool to run all your checks all at once. The command will only exit with code 0 when no problems exist.
An opinionated CLI tool to run all your checks all at once. The command will only exit with code 0
when no problems exist.

https://github.com/aklinker1/check/assets/10101283/c8089e5c-e25f-4f59-8897-d2a6f97a3139

Expand Down
43 changes: 43 additions & 0 deletions bun.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

70 changes: 36 additions & 34 deletions package.json
8000
Original file line number Diff line number Diff line change
@@ -1,8 +1,41 @@
{
"name": "@aklinker1/check",
"version": "2.2.0",
"packageManager": "bun@1.3.2",
"keywords": [
"check",
"eslint",
"format",
"lint",
"oxfmt",
"prettier",
"publint",
"typescript"
],
"homepage": "https://github.com/aklinker1/check",
"license": "MIT",
"author": {
"name": "Aaron Klinker",
"email": "aaronklinker1+npm@gmail.com"
},
"repository": {
"url": "https://github.com/aklinker1/check"
},
"bin": {
"check": "bin/check.mjs"
},
"files": [
"bin",
"dist"
],
"type": "module",
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"scripts": {
"build": "tsdown src/index.ts src/cli.ts",
"check": "bun src/cli.ts",
Expand All @@ -15,42 +48,11 @@
"devDependencies": {
"@types/bun": "latest",
"@typescript/native-preview": "^7.0.0-dev.20251114.1",
"oxfmt": "^0.40.0",
"oxlint": "^1.22.0",
"publint": "^0.3.14",
"tsdown": "^0.15.9",
"typescript": "^5.9.3"
},
"repository": {
"url": "https://github.com/aklinker1/check"
},
"license": "MIT",
"homepage": "https://github.com/aklinker1/check",
"author": {
"name": "Aaron Klinker",
"email": "aaronklinker1+npm@gmail.com"
},
"keywords": [
"lint",
"format",
"check",
"eslint",
"publint",
"prettier",
"typescript"
],
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
}
},
"module": "./dist/index.js",
"types": "./dist/index.d.ts",
"files": [
"bin",
"dist"
],
"bin": {
"check": "bin/check.mjs"
}
"packageManager": "bun@1.3.2"
}
4 changes: 2 additions & 2 deletions src/cli.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { isCI } from "ci-info";

import { check } from ".";
import { version } from "../package.json" with { type: "json" };
import { ALL_TOOLS } from "./tools";
Expand All @@ -22,8 +23,7 @@ const help = `\x1b[34m\x1b[1mcheck\x1b[0m runs all your project checks at once,
\x1b[36m-h\x1b[0m, \x1b[36m--help\x1b[0m Show this help message and exit`;

const args = process.argv.slice(2);
const boolArg = (arg: string): boolean | undefined =>
args.includes(arg) || undefined;
const boolArg = (arg: string): boolean | undefined => args.includes(arg) || undefined;

const showHelp = boolArg("-h") || boolArg("--help");
if (showHelp) {
Expand Down
86 changes: 32 additions & 54 deletions src/index.ts
10BC8
Original file line number Diff line number Diff line change
@@ -1,35 +1,24 @@
import { ALL_TOOLS } from "./tools";
import type { CheckOptions, Tool, Problem, ToolDefinition } from "./types";
import {
bold,
cyan,
debug as debugLog,
dim,
humanMs,
isDebug,
red,
yellow,
} from "./utils";
import { createTaskList } from "./tasklist";
import { readFile } from "node:fs/promises";
import { relative, resolve, sep, join } from "node:path";

import { isCI } from "ci-info";
import { readFile } from "node:fs/promises";

import { createTaskList } from "./tasklist";
import { ALL_TOOLS } from "./tools";
import type { CheckOptions, Tool, Problem, ToolDefinition } from "./types";
import { bold, cyan, debug as debugLog, dim, humanMs, isDebug, red, yellow } from "./utils";

export type * from "./types";

export async function check(options: CheckOptions = {}): Promise<never> {
const { debug, fix = !isCI, root = process.cwd() } = options;
const packageJson = JSON.parse(
await readFile(join(root, "package.json"), "utf8"),
);
const packageJson = JSON.parse(await readFile(join(root, "package.json"), "utf8"));
if (debug) {
process.env.DEBUG = "true";
}
console.log();
debugLog("Options:" + JSON.stringify(options));
debugLog(
"Resolved options:" + JSON.stringify({ debug, fix, root, packageJson }),
);
debugLog("Resolved options:" + JSON.stringify({ debug, fix, root, packageJson }));

const tools = await findInstalledTools({ root, packageJson });
if (tools.length === 0) {
Expand All @@ -41,28 +30,25 @@ export async function check(options: CheckOptions = {}): Promise<never> {
console.log();
process.exit(1);
}
const results = await createTaskList(
tools,
async ({ input: tool, fail, succeed, warn }) => {
const startTime = performance.now();
// Run checks
const fn = fix ? (tool.fix ?? tool.check) : tool.check;
const problems = await fn();
// Ensure problems are absolute paths relative to the root dir
problems.forEach((problem) => {
problem.file = resolve(root ?? process.cwd(), problem.file);
});
const duration = humanMs(performance.now() - startTime);

const title = `${tool.name} ${dim(`(${duration})`)}`;
const errorCount = problems.filter((p) => p.kind === "error").length;
if (errorCount > 0) fail(title);
else if (problems.length > 0) warn(title);
else succeed(title);

return problems;
},
);
const results = await createTaskList(tools, async ({ input: tool, fail, succeed, warn }) => {
const startTime = performance.now();
// Run checks
const fn = fix ? (tool.fix ?? tool.check) : tool.check;
const problems = await fn();
// Ensure problems are absolute paths relative to the root dir
problems.forEach((problem) => {
problem.file = resolve(root ?? process.cwd(), problem.file);
});
const duration = humanMs(performance.now() - startTime);

const title = `${tool.name} ${dim(`(${duration})`)}`;
const errorCount = problems.filter((p) => p.kind === "error").length;
if (errorCount > 0) fail(title);
else if (problems.length > 0) warn(title);
else succeed(title);

return problems;
});

const problems = results.flat();
console.log();
Expand Down Expand Up @@ -97,10 +83,7 @@ export async function check(options: CheckOptions = {}): Promise<never> {
return acc;
}, {}),
);
const maxLength = files.reduce(
(prev, [file]) => Math.max(prev, file.length),
0,
);
const maxLength = files.reduce((prev, [file]) => Math.max(prev, file.length), 0);
console.log();
console.log("Across " + plural(files.length, "File:", "Files:"));
files.forEach(([file, count]) => {
Expand All @@ -112,14 +95,11 @@ export async function check(options: CheckOptions = {}): Promise<never> {
process.exit(problems.length);
}

async function findInstalledTools(
opts: Parameters<ToolDefinition>[0],
): Promise<Tool[]> {
async function findInstalledTools(opts: Parameters<ToolDefinition>[0]): Promise<Tool[]> {
const status = await Promise.all(
ALL_TOOLS.map(async (def) => {
const tool = await def(opts);
const isInstalled =
!!opts.packageJson.devDependencies?.[tool.packageName];
const isInstalled = !!opts.packageJson.devDependencies?.[tool.packageName];
return { tool, isInstalled };
}),
);
Expand All @@ -135,9 +115,7 @@ async function findInstalledTools(
const skipped = getTools(false);
debugLog(`Skipping: ${skipped || "(none)"} `);
}
return status
.filter(({ isInstalled }) => isInstalled)
.map((item) => item.tool);
return status.filter(({ isInstalled }) => isInstalled).map((item) => item.tool);
}

function plural(count: number, singular: string, plural: string): string {
Expand Down
8 changes: 3 additions & 5 deletions src/tasklist/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import { cyan, dim, green, red, yellow } from "../utils";
import readline from "node:readline";

export async function createTaskList<
TInput extends { name: string },
TResult = void,
>(
import { cyan, dim, green, red, yellow } from "../utils";

export async function createTaskList<TInput extends { name: string }, TResult = void>(
inputs: TInput[],
run: (ctx: {
input: TInput;
Expand Down
1 change: 1 addition & 0 deletions src/tools/eslint.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { describe, it, expect } from "bun:test";

import { parseOutput } from "./eslint";

describe("ESLint", () => {
Expand Down
40 changes: 19 additions & 21 deletions src/tools/eslint.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,25 +14,23 @@ export const eslint: ToolDefinition = ({ root }) => {
};

export const parseOutput: OutputParser = ({ stdout, stderr }) => {
return `${stdout}\n${stderr}`
.split(/\r?\n/)
.reduce<Problem[]>((acc, line) => {
const groups =
/^(?<file>.*?): line (?<line>[0-9]+), col (?<column>[0-9]+), (?<kind>\S+) - (?<message>.*?) \((?<rule>\S*?)\)$/.exec(
line,
)?.groups;
if (groups) {
acc.push({
file: groups.file,
kind: groups.kind === "Warning" ? "warning" : "error",
message: groups.message,
location: {
line: parseInt(groups.line, 10),
column: parseInt(groups.column, 10),
},
rule: groups.rule,
});
}
return acc;
}, []);
return `${stdout}\n${stderr}`.split(/\r?\n/).reduce<Problem[]>((acc, line) => {
const groups =
/^(?<file>.*?): line (?<line>[0-9]+), col (?<column>[0-9]+), (?<kind>\S+) - (?<message>.*?) \((?<rule>\S*?)\)$/.exec(
line,
)?.groups;
if (groups) {
acc.push({
file: groups.file,
kind: groups.kind === "Warning" ? "warning" : "error",
message: groups.message,
location: {
line: parseInt(groups.line, 10),
column: parseInt(groups.column, 10),
},
rule: groups.rule,
});
}
return acc;
}, []);
};
Loading
Loading
0