Skip to content

Commit

Permalink
feat: Add custom binDir option (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
aklinker1 authored Apr 4, 2024
1 parent 42c1bbd commit ccb7b2d
Show file tree
Hide file tree
Showing 8 changed files with 102 additions and 70 deletions.
5 changes: 5 additions & 0 deletions src/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,11 @@ const main = defineCommand({
alias: "d",
description: "Enable debug logs",
},
binDir: {
type: "string",
alias: "b",
description: "Directory where binaries are located",
},
},
async run(ctx) {
await check(ctx.args);
Expand Down
27 changes: 16 additions & 11 deletions src/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { ALL_TOOLS } from "./tools";
import type { CheckOptions, Tool, Problem } from "./types";
import type { CheckOptions, Tool, Problem, ToolDefinition } from "./types";
import { p } from "@antfu/utils";
import { bold, cyan, debug, dim, humanMs, isDebug, red, yellow } from "./utils";
import { createTaskList } from "./tasklist";
Expand All @@ -9,13 +9,18 @@ import { isCI } from "ci-info";
export type * from "./types";

export async function check(options: CheckOptions = {}) {
const { debug, fix = !isCI, root } = options;
const {
debug,
fix = !isCI,
root = process.cwd(),
binDir = "node_modules/.bin",
} = options;
if (debug) {
process.env.DEBUG = "true";
}
console.log();

const tools = await findInstalledTools(root);
const tools = await findInstalledTools({ root, binDir });
if (tools.length === 0) {
console.log("No tools detected! Run with --debug for more info");
console.log();
Expand All @@ -27,7 +32,7 @@ export async function check(options: CheckOptions = {}) {
const startTime = performance.now();
// Run checks
const fn = fix ? tool.fix ?? tool.check : tool.check;
const problems = await fn(root);
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);
Expand Down Expand Up @@ -92,13 +97,13 @@ export async function check(options: CheckOptions = {}) {
process.exit(problems.length);
}

async function findInstalledTools(root: string | undefined): Promise<Tool[]> {
const status = await p(ALL_TOOLS).map(async (tool) => {
const t = typeof tool === "function" ? await tool(root) : tool;
return {
tool: t,
isInstalled: await t.isInstalled(root),
};
async function findInstalledTools(
opts: Parameters<ToolDefinition>[0],
): Promise<Tool[]> {
const status = await p(ALL_TOOLS).map(async (def) => {
const tool = await def(opts);
const isInstalled = await tool.isInstalled();
return { tool, isInstalled };
}).promise;

if (isDebug()) {
Expand Down
36 changes: 20 additions & 16 deletions src/tools/eslint.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,26 @@
import type { OutputParser, Problem, Tool } from "../types";
import type { OutputParser, Problem, ToolDefinition } from "../types";
import { isBinInstalled, execAndParse } from "../utils";
import { resolve } from "node:path";

const bin = "node_modules/.bin/eslint";
const args = [
".",
"--ext",
".js,.ts,.jsx,.tsx,.mjs,.mts,.cjs,.cts,.vue",
"--format",
"compact",
"--max-warnings",
"0",
];
export const eslint: ToolDefinition = ({ binDir, root }) => {
const bin = resolve(root, binDir, "eslint");
const checkArgs = [
".",
"--ext",
".js,.ts,.jsx,.tsx,.mjs,.mts,.cjs,.cts,.vue",
"--format",
"compact",
"--max-warnings",
"0",
];
const fixArgs = [...checkArgs, "--fix"];

export const eslint: Tool = {
name: "ESLint",
isInstalled: (root) => isBinInstalled(bin, root),
check: (root) => execAndParse(root, bin, args, parseOuptut),
fix: (root) => execAndParse(root, bin, [...args, "--fix"], parseOuptut),
return {
name: "ESLint",
isInstalled: () => isBinInstalled(bin),
check: () => execAndParse(bin, checkArgs, root, parseOuptut),
fix: () => execAndParse(bin, fixArgs, root, parseOuptut),
};
};

export const parseOuptut: OutputParser = ({ stdout, stderr }) => {
Expand Down
21 changes: 12 additions & 9 deletions src/tools/prettier.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
import type { Tool, OutputParser, Problem } from "../types";
import type { OutputParser, Problem, ToolDefinition } from "../types";
import { execAndParse, isBinInstalled } from "../utils";
import { resolve } from "node:path";

const bin = "node_modules/.bin/prettier";
const checkArgs = [".", "--list-different"];
const fixArgs = [".", "-w"];
export const prettier: ToolDefinition = ({ binDir, root }) => {
const bin = resolve(root, binDir, "prettier");
const checkArgs = [".", "--list-different"];
const fixArgs = [".", "-w"];

export const prettier: Tool = {
name: "Prettier",
isInstalled: (root) => isBinInstalled(bin, root),
check: (root) => execAndParse(root, bin, checkArgs, parseOuptut),
fix: (root) => execAndParse(root, bin, fixArgs, parseOuptut),
return {
name: "Prettier",
isInstalled: () => isBinInstalled(bin),
check: () => execAndParse(bin, checkArgs, root, parseOuptut),
fix: () => execAndParse(bin, fixArgs, root, parseOuptut),
};
};

export const parseOuptut: OutputParser = ({ stdout, stderr }) => {
Expand Down
23 changes: 17 additions & 6 deletions src/tools/publint.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import type { OutputParser, Problem, ProblemKind, Tool } from "../types";
import type {
OutputParser,
Problem,
ProblemKind,
ToolDefinition,
} from "../types";
import { isBinInstalled, execAndParse } from "../utils";
import { resolve } from "node:path";

const bin = "node_modules/.bin/publint";
const bin = "publint";
const args: string[] = [];

export const publint: Tool = {
name: "Publint",
isInstalled: (root) => isBinInstalled(bin, root),
check: (root) => execAndParse(root, bin, args, parseOuptut),
export const publint: ToolDefinition = ({ binDir, root }) => {
const bin = resolve(root, binDir, "publint");
const args: string[] = [];

return {
name: "Publint",
isInstalled: () => isBinInstalled(bin),
check: () => execAndParse(bin, args, root, parseOuptut),
};
};

export const parseOuptut: OutputParser = ({ stdout }) => {
Expand Down
30 changes: 17 additions & 13 deletions src/tools/typescript.ts
Original file line number Diff line number Diff line change
@@ -1,26 +1,30 @@
import type { Tool, OutputParser, Problem } from "../types";
import type { Tool, OutputParser, Problem, ToolDefinition } from "../types";
import { debug, execAndParse, isBinInstalled } from "../utils";
import { resolve } from "node:path";

const tsc = {
bin: "node_modules/.bin/tsc",
args: ["--noEmit", "--pretty", "false"],
};
const vueTsc = {
bin: "node_modules/.bin/vue-tsc",
args: ["--noEmit", "--pretty", "false"],
};
export const typescript: ToolDefinition = async ({
root,
binDir,
}): Promise<Tool> => {
const tsc = {
bin: resolve(root, binDir, "tsc"),
args: ["--noEmit", "--pretty", "false"],
};
const vueTsc = {
bin: resolve(root, binDir, "vue-tsc"),
args: ["--noEmit", "--pretty", "false"],
};

export const typescript = async (root: string | undefined): Promise<Tool> => {
const isVueTsc = await isBinInstalled(vueTsc.bin, root);
const isVueTsc = await isBinInstalled(vueTsc.bin);
debug("TypeScript: Is vue-tsc installed? " + isVueTsc);
const cmd = isVueTsc ? vueTsc : tsc;
const name = isVueTsc ? "TypeScript (Vue)" : "Typescript";
return {
name,
// Always check if tsc is installed
isInstalled: (root) => isBinInstalled(tsc.bin, root),
isInstalled: () => isBinInstalled(tsc.bin),
// Execute the other TSC binary if necessary
check: async (root) => execAndParse(root, cmd.bin, cmd.args, parseOuptut),
check: async () => execAndParse(cmd.bin, cmd.args, root, parseOuptut),
};
};

Expand Down
12 changes: 9 additions & 3 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,14 @@ export interface CheckOptions {
* Set to true to enable debug logs.
*/
debug?: boolean;
binDir?: string;
}

export type ToolDefinition = (opts: {
root: string;
binDir: string;
}) => Promise<Tool> | Tool;

export interface Tool {
/**
* Name of tool shown in the console output.
Expand All @@ -23,15 +29,15 @@ export interface Tool {
/**
* Check if the tool is installed.
*/
isInstalled: (root: string | undefined) => Promise<boolean>;
isInstalled: () => Promise<boolean>;
/**
* Run the tool, only checking for problems.
*/
check: (root: string | undefined) => Promise<Problem[]>;
check: () => Promise<Problem[]>;
/**
* Run the tool, but fix problems if possible. If the tool doesn't support fixing problems, `check` will be called instead.
*/
fix?: (root: string | undefined) => Promise<Problem[]>;
fix?: () => Promise<Problem[]>;
}

export interface Problem {
Expand Down
18 changes: 6 additions & 12 deletions src/utils.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,11 @@
import { spawn } from "node:child_process";
import type { OutputParser, Problem } from "./types";
import { stat } from "fs/promises";
import { resolve } from "node:path";

function resolveRoot(root: string | undefined, ...path: string[]): string {
return root != null ? resolve(root, ...path) : resolve(...path);
}

export async function isBinInstalled(bin: string, root?: string) {
export async function isBinInstalled(bin: string) {
try {
const binPath = resolveRoot(root, bin);
if (isDebug()) debug(`Checking if binary exists: ${binPath}`);
await stat(resolveRoot(root, bin));
if (isDebug()) debug(`Checking if binary exists: ${bin}`);
await stat(bin);
return true;
} catch (err) {
return false;
Expand Down Expand Up @@ -43,14 +37,14 @@ function exec(
}

export async function execAndParse(
root: string | undefined,
bin: string,
args: string[],
cwd: string,
parser: OutputParser,
): Promise<Problem[]> {
const res = await exec(resolveRoot(root, bin), args, { cwd: root });
const res = await exec(bin, args, { cwd });
if (res.exitCode == null) throw Error("Exit code was null");
if (isDebug()) console.debug({ bin, args, root, ...res });
if (isDebug()) console.debug({ bin, args, cwd, ...res });
return parser({
code: res.exitCode,
stderr: res.stderr,
Expand Down

0 comments on commit ccb7b2d

Please sign in to comment.