firest commit

This commit is contained in:
wwweww
2026-02-21 22:48:40 +08:00
commit 55e8053e07
1034 changed files with 99049 additions and 0 deletions
+21
View File
@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2022 Jake Bailey
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
+139
View File
@@ -0,0 +1,139 @@
# hereby
[![npm](https://img.shields.io/npm/v/hereby.svg)](https://npmjs.com/package/hereby)
[![node](https://img.shields.io/node/v/hereby.svg)](https://nodejs.org)
[![install size](https://packagephobia.com/badge?p=hereby)](https://packagephobia.com/result?p=hereby)
[![tokei](https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/jakebailey/hereby/gh-pages/tokei.json)](https://github.com/XAMPPRocky/tokei)
[![ci](https://github.com/jakebailey/hereby/actions/workflows/ci.yml/badge.svg)](https://github.com/jakebailey/hereby/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/jakebailey/hereby/branch/main/graph/badge.svg?token=YL2Z1uk5dh)](https://codecov.io/gh/jakebailey/hereby)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/jakebailey/hereby/badge)](https://securityscorecards.dev/viewer/?uri=github.com/jakebailey/hereby)
> _I hereby declare thee built._
`hereby` is a simple task runner.
```console
$ npm i -D hereby
$ yarn add -D hereby
```
## Herebyfile.mjs
Tasks are defined in `Herebyfile.mjs`. Exported tasks are available to run at
the CLI, with support for `export default`.
For example:
```js
import { execa } from "execa";
import { task } from "hereby";
export const build = task({
name: "build",
run: async () => {
await execa("tsc", ["-b", "./src"]);
},
});
export const test = task({
name: "test",
dependencies: [build],
run: async () => {
await execa("node", ["./out/test.js"]);
},
});
export const lint = task({
name: "lint",
run: async () => {
await runLinter(...);
},
});
export const testAndLint = task({
name: "testAndLint",
dependencies: [test, lint],
});
export default testAndLint;
export const bundle = task({
name: "bundle",
dependencies: [build],
run: async () => {
await execa("esbuild", [
"--bundle",
"./out/index.js",
"--outfile=./out/bundled.js",
]);
},
});
```
## Running tasks
Given the above Herebyfile:
```console
$ hereby build # Run the "build" task
$ hereby test # Run the "test" task, which depends on "build".
$ hereby # Run the default exported task.
$ hereby test bundle # Run the "test" and "bundle" tasks in parallel.
```
## Flags
`hereby` also supports a handful of flags:
```console
-h, --help Display this usage guide.
--herebyfile path A path to a Herebyfile. Optional.
-T, --tasks Print a listing of the available tasks.
```
## ESM
`hereby` is implemented in ES modules. But, don't fret! This does not mean that
your project must be ESM-only, only that your `Herebyfile` must be ESM module so
that `hereby`'s `task` function can be imported. It's recommended to use the
filename `Herebyfile.mjs` to ensure that it is treated as ESM. This will work in
a CommonJS project; ES modules can import CommonJS modules.
If your package already sets `"type": "module"`, `Herebyfile.js` will work as
well.
## TypeScript support
`hereby` supports `Herebyfile.mts` and `Herebyfile.ts`, so long as your runtime
supports loading these files. This includes like Node's type stripping, `bun`,
or even a custom loader, and so on.
## Caveats
### No serial tasks
`hereby` does not support running tasks in series; specifying multiple tasks at
the CLI or as dependencies of another task will run them in parallel. This
matches the behavior of tools like `make`, which like `hereby` intend to encode
a dependency graph of tasks, not act as a script.
In general, if you're trying to emulate a serial task, you will likely be better
served by writing out explicit dependencies for your tasks.
### Tasks only run once
`hereby` will only run each task once during its execution. This means that
tasks which consist of other tasks run in order like a script cannot be
constructed. For example, it's not possible to run "build", then "clean", then
"build" again within the same invocation of `hereby`, since "build" will only be
executed once (and the lack of serial tasks prevents such a construction
anyway).
To run tasks in a specific order and more than once, run `hereby` multiple
times:
```console
$ hereby build
$ hereby clean
$ hereby build
```
+2
View File
@@ -0,0 +1,2 @@
#!/usr/bin/env node
import "../dist/cli.js";
+12
View File
@@ -0,0 +1,12 @@
import module from "node:module";
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (module.enableCompileCache) {
module.enableCompileCache();
}
async function run() {
const { main } = await import("./cli/index.js");
const { real } = await import("./cli/utils.js");
await main(await real());
}
void run();
//# sourceMappingURL=cli.js.map
+29
View File
@@ -0,0 +1,29 @@
import commandLineUsage from "command-line-usage";
import pc from "picocolors";
import { compareTaskNames } from "./utils.js";
export function formatTasks(format, tasks, defaultTask) {
const visibleTasks = [...tasks].filter(isTaskVisible).sort(compareTaskNames);
if (format === "simple") {
return visibleTasks.map((task) => task.options.name).join("\n");
}
return commandLineUsage({
header: "Available tasks",
content: visibleTasks.map((task) => {
var _a;
const name = task === defaultTask
? `${pc.green(task.options.name)} (default)`
: pc.blue(task.options.name);
let descriptionParts = task.options.description ? [task.options.description] : undefined;
const deps = (_a = task.options.dependencies) === null || _a === void 0 ? void 0 : _a.filter(isTaskVisible).sort(compareTaskNames);
if (deps === null || deps === void 0 ? void 0 : deps.length) {
const depNames = deps.map((task) => pc.blue(task.options.name));
(descriptionParts !== null && descriptionParts !== void 0 ? descriptionParts : (descriptionParts = [])).push(`Depends on: ${depNames.join(", ")}`);
}
return { name, description: descriptionParts === null || descriptionParts === void 0 ? void 0 : descriptionParts.join("\n") };
}),
});
}
function isTaskVisible(task) {
return !task.options.hiddenFromTaskList;
}
//# sourceMappingURL=formatTasks.js.map
+95
View File
@@ -0,0 +1,95 @@
import path from "node:path";
import { performance } from "node:perf_hooks";
import { types } from "node:util";
import pc from "picocolors";
import { formatTasks } from "./formatTasks.js";
import { findHerebyfile, loadHerebyfile } from "./loadHerebyfile.js";
import { getUsage, parseArgs } from "./parseArgs.js";
import { reexec } from "./reexec.js";
import { Runner } from "./runner.js";
import { UserError } from "./utils.js";
export async function main(d) {
try {
await mainWorker(d);
}
catch (e) {
if (e instanceof UserError) {
d.error(`${pc.red("Error")}: ${e.message}`);
}
else if (types.isNativeError(e) && e.stack) { // eslint-disable-line @typescript-eslint/no-deprecated
d.error(e.stack);
}
else {
d.error(`${e}`);
}
d.setExitCode(1);
}
}
async function mainWorker(d) {
var _a;
const args = parseArgs(d.argv.slice(2));
if (args.help) {
d.log(getUsage());
return;
}
const herebyfilePath = path.resolve(d.cwd(), (_a = args.herebyfile) !== null && _a !== void 0 ? _a : findHerebyfile(d.cwd()));
if (await reexec(herebyfilePath))
return;
if (args.version) {
d.log(`hereby ${d.version()}`);
return;
}
d.chdir(path.dirname(herebyfilePath));
const herebyfile = await loadHerebyfile(herebyfilePath);
if (args.printTasks) {
d.log(formatTasks(args.printTasks, herebyfile.tasks.values(), herebyfile.defaultTask));
return;
}
const tasks = await selectTasks(d, herebyfile, herebyfilePath, args.run);
const taskNames = tasks.map((task) => pc.blue(task.options.name)).join(", ");
d.log(`Using ${pc.yellow(d.simplifyPath(herebyfilePath))} to run ${taskNames}`);
const start = performance.now();
const runner = new Runner(d);
try {
await runner.runTasks(...tasks);
}
catch {
// We will have already printed some message here.
// Set the error code and let the process run to completion,
// so we don't end up with an unflushed output.
d.setExitCode(1);
}
finally {
const took = performance.now() - start;
const failed = runner.failedTasks.length > 0;
d.log(`Completed ${taskNames}${failed ? pc.red(" with errors") : ""} in ${d.prettyMilliseconds(took)}`);
if (failed) {
const names = runner.failedTasks.sort().map((task) => pc.red(task)).join(", ");
d.log(`Failed tasks: ${names}`);
}
}
}
// Exported for testing.
export async function selectTasks(d, herebyfile, herebyfilePath, taskNames) {
if (taskNames.length === 0) {
if (herebyfile.defaultTask)
return [herebyfile.defaultTask];
throw new UserError(`No default task has been exported from ${d.simplifyPath(herebyfilePath)}; please specify a task name.`);
}
const tasks = [];
for (const name of taskNames) {
const task = herebyfile.tasks.get(name);
if (!task) {
let message = `Task "${name}" does not exist or is not exported from ${d.simplifyPath(herebyfilePath)}.`;
const { closest, distance } = await import("fastest-levenshtein");
const candidate = closest(name, [...herebyfile.tasks.keys()]);
if (distance(name, candidate) < name.length * 0.4) {
message += ` Did you mean "${candidate}"?`;
}
throw new UserError(message);
}
tasks.push(task);
}
return tasks;
}
//# sourceMappingURL=index.js.map
+89
View File
@@ -0,0 +1,89 @@
import fs from "node:fs";
import path from "node:path";
import { pathToFileURL } from "node:url";
import pc from "picocolors";
import { Task } from "../index.js";
import { findUp, UserError } from "./utils.js";
const herebyfileRegExp = /^herebyfile\.m?[jt]s$/i;
export function findHerebyfile(dir) {
const result = findUp(dir, (dir) => {
const entries = fs.readdirSync(dir, { withFileTypes: true });
const matching = entries.filter((e) => herebyfileRegExp.test(e.name));
if (matching.length > 1) {
throw new UserError(`Found more than one Herebyfile: ${matching.map((e) => e.name).join(", ")}`);
}
if (matching.length === 1) {
const candidate = matching[0];
if (!candidate.isFile()) {
throw new UserError(`${candidate.name} is not a file.`);
}
return path.join(dir, candidate.name);
}
if (entries.some((e) => e.name === "package.json")) {
return false; // TODO: Is this actually desirable? What about monorepos?
}
return undefined;
});
if (result) {
return result;
}
throw new UserError("Unable to find Herebyfile.");
}
export async function loadHerebyfile(herebyfilePath) {
// Note: calling pathToFileURL is required on Windows to disambiguate URLs
// from drive letters.
const herebyfile = await import(pathToFileURL(herebyfilePath).toString());
const exportedTasks = new Set();
let defaultTask;
for (const [key, value] of Object.entries(herebyfile)) {
if (!(value instanceof Task))
continue;
if (key === "default") {
defaultTask = value;
}
else if (exportedTasks.has(value)) {
throw new UserError(`Task "${pc.blue(value.options.name)}" has been exported twice.`);
}
else {
exportedTasks.add(value);
}
}
if (defaultTask) {
exportedTasks.add(defaultTask);
}
if (exportedTasks.size === 0) {
throw new UserError("No tasks found. Did you forget to export your tasks?");
}
// We check this here by walking the DAG, as some dependencies may not be
// exported and therefore would not be seen by the above loop.
checkTaskInvariants(exportedTasks);
const tasks = new Map([...exportedTasks].map((task) => [task.options.name, task]));
return { tasks, defaultTask };
}
function checkTaskInvariants(tasks) {
const checkedTasks = new Set();
const taskStack = new Set();
const seenNames = new Set();
checkTaskInvariantsWorker(tasks);
function checkTaskInvariantsWorker(tasks) {
for (const task of tasks) {
if (checkedTasks.has(task))
continue;
if (taskStack.has(task)) {
throw new UserError(`Task "${pc.blue(task.options.name)}" references itself.`);
}
const name = task.options.name;
if (seenNames.has(name)) {
throw new UserError(`Task "${pc.blue(name)}" was declared twice.`);
}
seenNames.add(name);
if (task.options.dependencies) {
taskStack.add(task);
checkTaskInvariantsWorker(task.options.dependencies);
taskStack.delete(task);
}
checkedTasks.add(task);
}
}
}
//# sourceMappingURL=loadHerebyfile.js.map
+74
View File
@@ -0,0 +1,74 @@
import commandLineUsage from "command-line-usage";
import minimist from "minimist";
export function parseArgs(argv) {
let parseUnknownAsTask = true;
const options = minimist(argv, {
"--": true,
string: ["herebyfile"],
boolean: ["tasks", "tasks-simple", "help", "version"],
alias: {
"h": "help",
"T": "tasks",
},
unknown: (name) => parseUnknownAsTask && (parseUnknownAsTask = !name.startsWith("-")),
});
return {
help: options["help"],
run: options._,
herebyfile: options["herebyfile"],
printTasks: options["tasks"] ? "normal" : (options["tasks-simple"] ? "simple" : undefined),
version: options["version"],
};
}
export function getUsage() {
const usage = commandLineUsage([
{
header: "hereby",
content: "A simple task runner.",
},
{
header: "Synopsis",
content: "$ hereby <task>",
},
{
header: "Options",
optionList: [
{
name: "help",
description: "Display this usage guide.",
alias: "h",
type: Boolean,
},
{
name: "herebyfile",
description: "A path to a Herebyfile. Optional.",
type: String,
defaultOption: true,
typeLabel: "{underline path}",
},
{
name: "tasks",
description: "Print a listing of the available tasks.",
alias: "T",
type: Boolean,
},
{
name: "version",
description: "Print the current hereby version.",
type: Boolean,
},
],
},
{
header: "Example usage",
content: [
"$ hereby build",
"$ hereby build lint",
"$ hereby test --skip someTest --lint=false",
"$ hereby --tasks",
],
},
]);
return usage;
}
//# sourceMappingURL=parseArgs.js.map
+58
View File
@@ -0,0 +1,58 @@
import fs from "node:fs";
import path from "node:path";
import { fileURLToPath, pathToFileURL } from "node:url";
import { findUp, UserError } from "./utils.js";
const thisCLI = fileURLToPath(new URL("../cli.js", import.meta.url));
const distCLIPath = path.join("dist", "cli.js");
const expectedCLIPath = path.join("node_modules", "hereby", distCLIPath);
/**
* Checks to see if we need to re-exec another version of hereby.
* If this function returns true, the caller should return immediately
* and do no further work.
*/
export async function reexec(herebyfilePath) {
// If hereby is installed globally, but run against a Herebyfile in some
// other package, that Herebyfile's import will resolve to a different
// installation of the hereby package. There's no guarantee that the two
// are compatible (in fact, they are guaranteed not to as Task is a class).
//
// Rather than trying to fix this by messing around with Node's resolution
// (which won't work in ESM anyway), instead opt to figure out the location
// of hereby as imported by the Herebyfile, and then "reexec" it by importing.
//
// This code used to use `import.meta.resolve` to find `hereby/cli`, but
// manually encoding this behavior is faster and avoids the dependency.
// If Node ever makes the two-argument form of `import.meta.resolve` unflagged,
// we could switch to that.
const otherCLI = findUp(path.dirname(herebyfilePath), (dir) => {
const p = path.resolve(dir, expectedCLIPath);
// This is the typical case; we've walked up and found it in node_modules.
if (fs.existsSync(p))
return p;
// Otherwise, we check to see if we're self-resolving. Realistically,
// this only happens when developing hereby itself.
//
// Technically, this should go before the above check since self-resolution
// comes before node_modules resolution, but this could only happen if hereby
// happened to depend on itself somehow.
const packageJsonPath = path.join(dir, "package.json");
if (fs.existsSync(packageJsonPath)) {
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, "utf8"));
if (packageJson.name === "hereby") {
return path.resolve(dir, distCLIPath);
}
}
return undefined;
});
if (!otherCLI) {
throw new UserError("Unable to find hereby; ensure hereby is installed in your package.");
}
if (fs.realpathSync(thisCLI) === fs.realpathSync(otherCLI)) {
return false;
}
// Note: calling pathToFileURL is required on Windows to disambiguate URLs
// from drive letters.
await import(pathToFileURL(otherCLI).toString());
return true;
}
//# sourceMappingURL=reexec.js.map
+65
View File
@@ -0,0 +1,65 @@
import { performance } from "node:perf_hooks";
import pc from "picocolors";
export class Runner {
constructor(_d) {
this._d = _d;
this._addedTasks = new Map();
this.failedTasks = [];
this._startTimes = new Map();
}
async runTasks(...tasks) {
// Using allSettled here so that we don't immediately exit; it could be
// the case that a task has code that needs to run before, e.g. a
// cleanup function in a "finally" or something.
const results = await Promise.allSettled(tasks.map((task) => {
const cached = this._addedTasks.get(task);
if (cached)
return cached;
const promise = this._runTask(task);
this._addedTasks.set(task, promise);
return promise;
}));
for (const result of results) {
if (result.status === "rejected") {
throw result.reason;
}
}
}
async _runTask(task) {
const { dependencies, run } = task.options;
if (dependencies) {
await this.runTasks(...dependencies);
}
if (!run)
return;
try {
this.onTaskStart(task);
await run();
this.onTaskFinish(task);
}
catch (e) {
this.onTaskError(task, e);
throw e;
}
}
onTaskStart(task) {
this._startTimes.set(task, performance.now());
if (this.failedTasks.length > 0)
return; // Skip logging.
this._d.log(`Starting ${pc.blue(task.options.name)}`);
}
onTaskFinish(task) {
if (this.failedTasks.length > 0)
return; // Skip logging.
const took = performance.now() - this._startTimes.get(task);
this._d.log(`Finished ${pc.green(task.options.name)} in ${this._d.prettyMilliseconds(took)}`);
}
onTaskError(task, e) {
this.failedTasks.push(task.options.name);
if (this.failedTasks.length > 1)
return; // Skip logging.
const took = performance.now() - this._startTimes.get(task);
this._d.error(`Error in ${pc.red(task.options.name)} in ${this._d.prettyMilliseconds(took)}\n${e}`);
}
}
//# sourceMappingURL=runner.js.map
+61
View File
@@ -0,0 +1,61 @@
import fs from "node:fs";
import os from "node:os";
import path from "node:path";
export function compareTaskNames(a, b) {
return compareStrings(a.options.name, b.options.name);
}
// eslint-disable-next-line @typescript-eslint/unbound-method
const compareStrings = new Intl.Collator(undefined, { numeric: true }).compare;
// Exported for testing.
export function simplifyPath(p) {
p = path.normalize(p);
const homedir = path.normalize(os.homedir() + path.sep);
if (p.startsWith(homedir)) {
p = p.slice(homedir.length);
return `~${path.sep}${p}`;
}
return p;
}
export function findUp(dir, predicate) {
const root = path.parse(dir).root;
while (true) {
const result = predicate(dir);
if (result !== undefined)
return result;
if (dir === root)
break;
dir = path.dirname(dir);
}
return undefined;
}
/**
* UserError is a special error that, when caught in the CLI will be printed
* as a message only, without stacktrace. Use this instead of process.exit.
*/
export class UserError extends Error {
}
export async function real() {
const { default: prettyMilliseconds } = await import("pretty-ms");
/* eslint-disable no-restricted-globals */
return {
log: console.log,
error: console.error,
// eslint-disable-next-line @typescript-eslint/unbound-method
cwd: process.cwd,
// eslint-disable-next-line @typescript-eslint/unbound-method
chdir: process.chdir,
simplifyPath,
argv: process.argv,
setExitCode: (code) => {
process.exitCode = code;
},
version: () => {
const packageJsonURL = new URL("../../package.json", import.meta.url);
const packageJson = fs.readFileSync(packageJsonURL, "utf8");
return JSON.parse(packageJson).version;
},
prettyMilliseconds,
};
/* eslint-enable no-restricted-globals */
}
//# sourceMappingURL=utils.js.map
+39
View File
@@ -0,0 +1,39 @@
export interface TaskOptions {
/**
* The name of the task, as referenced in logs and the CLI.
*
* This name must not start with a "-" in order to prevent conflicts
* with flags.
*/
name: string;
/**
* A description of the task, for display in the CLI.
*/
description?: string | undefined;
/**
* A list of tasks that must have been run to completion before
* this task can execute.
*/
dependencies?: readonly Task[] | undefined;
/**
* A function to execute when this task is run. If this function
* returns a promise, the task will not be marked as finished until
* that promise resolves.
*/
run?: (() => void) | (() => PromiseLike<void>) | undefined;
/**
* If true, this task will be hidden from `hereby --tasks`.
*/
hiddenFromTaskList?: boolean | undefined;
}
/**
* A hereby Task. To get an instance, call `test`.
*/
export declare class Task {
private _;
private constructor();
}
/**
* Creates a new Task.
*/
export declare function task(options: TaskOptions): Task;
+53
View File
@@ -0,0 +1,53 @@
/**
* A hereby Task. To get an instance, call `test`.
*/
export class Task {
/* @internal */
static create(options) {
return new Task(options);
}
// Note: private such that "private constructor();" is emitted in the d.ts files,
// which prevents extending or direct instantiation.
constructor(options) {
// Runtime typecheck; consumers of hereby may not have enabled
// typechecking, so this is helpful.
var _a, _b;
/* eslint-disable @typescript-eslint/no-unnecessary-condition */
if (typeof options.name !== "string") {
throw new TypeError("Task name is not a string.");
}
if (typeof options.description !== "string" && options.description !== undefined) {
throw new TypeError("Task description is not a string or undefined.");
}
if (!Array.isArray(options.dependencies) && options.dependencies !== undefined) {
throw new TypeError("Task dependencies is not an array or undefined.");
}
for (const dep of (_a = options.dependencies) !== null && _a !== void 0 ? _a : []) {
if (!(dep instanceof Task)) {
throw new TypeError("Task dependency is not a task.");
}
}
if (typeof options.run !== "function" && options.run !== undefined) {
throw new TypeError("Task run is not a function or undefined.");
}
/* eslint-enable @typescript-eslint/no-unnecessary-condition */
// Non-type checks.
if (!options.name) {
throw new Error("Task name must not be empty.");
}
if (options.name.startsWith("-")) {
throw new Error('Task name must not start with "-".');
}
if (!((_b = options.dependencies) === null || _b === void 0 ? void 0 : _b.length) && !options.run) {
throw new Error("Task must have a run function or dependencies.");
}
this.options = options;
}
}
/**
* Creates a new Task.
*/
export function task(options) {
return Task.create(options);
}
//# sourceMappingURL=index.js.map
+113
View File
@@ -0,0 +1,113 @@
{
"name": "hereby",
"version": "1.11.1",
"description": "A simple task runner",
"repository": "github:jakebailey/hereby",
"type": "module",
"bin": "./bin/hereby.js",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./cli": "./dist/cli.js",
"./package.json": "./package.json"
},
"author": "Jake Bailey",
"license": "MIT",
"keywords": [
"hereby",
"herebyfile",
"task",
"runner",
"build",
"gulp",
"make",
"makefile"
],
"engines": {
"node": ">= 12.20"
},
"preferUnplugged": true,
"files": [
"README.md",
"LICENSE",
"./dist/**/*.js",
"!**/__tests__/**",
"./dist/index.d.ts"
],
"dependencies": {
"command-line-usage": "^6.1.3",
"fastest-levenshtein": "^1.0.16",
"minimist": "^1.2.8",
"picocolors": "^1.1.0",
"pretty-ms": "^8.0.0"
},
"devDependencies": {
"@ava/typescript": "^3.0.1",
"@changesets/cli": "^2.29.7",
"@codspeed/tinybench-plugin": "^4.0.1",
"@fast-check/ava": "2.0.1",
"@tsconfig/node12": "^12.1.5",
"@types/command-line-usage": "^5.0.4",
"@types/minimist": "^1.2.5",
"@types/node": "^24.7.2",
"@types/tmp": "^0.2.6",
"ava": "~5.0.1",
"c8": "^10.1.3",
"dprint": "^0.50.2",
"eslint": "^9.37.0",
"eslint-plugin-ava": "^15.1.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"eslint-plugin-unicorn": "^61.0.2",
"execa": "^6.1.0",
"globals": "^16.4.0",
"monocart-coverage-reports": "^2.12.9",
"moq.ts": "^10.1.0",
"rimraf": "^5.0.10",
"tinybench": "~2.8.0",
"tmp": "0.2.1",
"typescript": "^5.9.3",
"typescript-eslint": "^8.46.0"
},
"overrides": {
"ava": {
"emittery": "1.0.0"
}
},
"packageManager": "npm@8.19.4",
"scripts": {
"ci": "npm ci",
"build": "tsc",
"watch": "tsc --watch",
"test": "ava",
"coverage": "c8 --experimental-monocart ava",
"prepack": "rimraf dist && npm run build",
"version": "changeset version && npm install"
},
"ava": {
"files": [
"**/*.test.ts"
],
"typescript": {
"rewritePaths": {
"src/": "dist/"
},
"compile": false
},
"environmentVariables": {
"NO_COLOR": "1"
}
},
"c8": {
"all": true,
"include": "dist",
"reporter": [
"text",
"html",
"lcov"
]
}
}