hereby 1.8.6 → 1.8.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -4
- package/dist/cli/formatTasks.js +8 -14
- package/dist/cli/index.js +28 -27
- package/dist/cli/loadHerebyfile.js +13 -15
- package/dist/cli/runner.js +4 -9
- package/dist/cli/utils.js +5 -16
- package/dist/cli.js +1 -9
- package/package.json +13 -24
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@
|
|
|
11
11
|
|
|
12
12
|
`hereby` is a simple task runner.
|
|
13
13
|
|
|
14
|
-
```
|
|
14
|
+
```console
|
|
15
15
|
$ npm i -D hereby
|
|
16
16
|
$ yarn add -D hereby
|
|
17
17
|
```
|
|
@@ -73,7 +73,7 @@ export const bundle = task({
|
|
|
73
73
|
|
|
74
74
|
Given the above Herebyfile:
|
|
75
75
|
|
|
76
|
-
```
|
|
76
|
+
```console
|
|
77
77
|
$ hereby build # Run the "build" task
|
|
78
78
|
$ hereby test # Run the "test" task, which depends on "build".
|
|
79
79
|
$ hereby # Run the default exported task.
|
|
@@ -84,7 +84,7 @@ $ hereby test bundle # Run the "test" and "bundle" tasks in parallel.
|
|
|
84
84
|
|
|
85
85
|
`hereby` also supports a handful of flags:
|
|
86
86
|
|
|
87
|
-
```
|
|
87
|
+
```console
|
|
88
88
|
-h, --help Display this usage guide.
|
|
89
89
|
--herebyfile path A path to a Herebyfile. Optional.
|
|
90
90
|
-T, --tasks Print a listing of the available tasks.
|
|
@@ -125,7 +125,7 @@ anyway).
|
|
|
125
125
|
To run tasks in a specific order and more than once, run `hereby` multiple
|
|
126
126
|
times:
|
|
127
127
|
|
|
128
|
-
```
|
|
128
|
+
```console
|
|
129
129
|
$ hereby build
|
|
130
130
|
$ hereby clean
|
|
131
131
|
$ hereby build
|
package/dist/cli/formatTasks.js
CHANGED
|
@@ -1,28 +1,22 @@
|
|
|
1
1
|
import commandLineUsage from "command-line-usage";
|
|
2
2
|
import pc from "picocolors";
|
|
3
|
-
import {
|
|
3
|
+
import { compareTaskNames } from "./utils.js";
|
|
4
4
|
export function formatTasks(format, tasks, defaultTask) {
|
|
5
|
-
|
|
5
|
+
const visibleTasks = [...tasks].filter(isTaskVisible).sort(compareTaskNames);
|
|
6
6
|
if (format === "simple") {
|
|
7
|
-
return
|
|
7
|
+
return visibleTasks.map((task) => task.options.name).join("\n");
|
|
8
8
|
}
|
|
9
9
|
return commandLineUsage({
|
|
10
10
|
header: "Available tasks",
|
|
11
|
-
content:
|
|
11
|
+
content: visibleTasks.map((task) => {
|
|
12
12
|
var _a;
|
|
13
13
|
const name = task === defaultTask
|
|
14
14
|
? `${pc.green(task.options.name)} (default)`
|
|
15
15
|
: pc.blue(task.options.name);
|
|
16
|
-
let descriptionParts;
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
const deps = (_a = task.options.dependencies) === null || _a === void 0 ? void 0 : _a.filter(isTaskVisible);
|
|
21
|
-
if (deps && deps.length > 0) {
|
|
22
|
-
const depNames = deps
|
|
23
|
-
.map((task) => task.options.name)
|
|
24
|
-
.sort(compareStrings)
|
|
25
|
-
.map((v) => pc.blue(v));
|
|
16
|
+
let descriptionParts = task.options.description ? [task.options.description] : undefined;
|
|
17
|
+
const deps = (_a = task.options.dependencies) === null || _a === void 0 ? void 0 : _a.filter(isTaskVisible).sort(compareTaskNames);
|
|
18
|
+
if (deps === null || deps === void 0 ? void 0 : deps.length) {
|
|
19
|
+
const depNames = deps.map((task) => pc.blue(task.options.name));
|
|
26
20
|
(descriptionParts !== null && descriptionParts !== void 0 ? descriptionParts : (descriptionParts = [])).push(`Depends on: ${depNames.join(", ")}`);
|
|
27
21
|
}
|
|
28
22
|
return { name, description: descriptionParts === null || descriptionParts === void 0 ? void 0 : descriptionParts.join("\n") };
|
package/dist/cli/index.js
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import path from "node:path";
|
|
2
|
+
import util from "node:util";
|
|
2
3
|
import pc from "picocolors";
|
|
3
4
|
import { formatTasks } from "./formatTasks.js";
|
|
4
5
|
import { findHerebyfile, loadHerebyfile } from "./loadHerebyfile.js";
|
|
5
6
|
import { getUsage, parseArgs } from "./parseArgs.js";
|
|
6
7
|
import { reexec } from "./reexec.js";
|
|
7
8
|
import { Runner } from "./runner.js";
|
|
8
|
-
import {
|
|
9
|
+
import { ExitCodeError, UserError } from "./utils.js";
|
|
9
10
|
export async function main(d) {
|
|
10
11
|
try {
|
|
11
12
|
await mainWorker(d);
|
|
@@ -13,14 +14,18 @@ export async function main(d) {
|
|
|
13
14
|
catch (e) {
|
|
14
15
|
if (e instanceof ExitCodeError) {
|
|
15
16
|
d.setExitCode(e.exitCode);
|
|
17
|
+
return;
|
|
16
18
|
}
|
|
17
|
-
|
|
19
|
+
if (e instanceof UserError) {
|
|
18
20
|
d.error(`${pc.red("Error")}: ${e.message}`);
|
|
19
|
-
|
|
21
|
+
}
|
|
22
|
+
else if (util.types.isNativeError(e) && e.stack) {
|
|
23
|
+
d.error(e.stack);
|
|
20
24
|
}
|
|
21
25
|
else {
|
|
22
|
-
|
|
26
|
+
d.error(`${e}`);
|
|
23
27
|
}
|
|
28
|
+
d.setExitCode(1);
|
|
24
29
|
}
|
|
25
30
|
}
|
|
26
31
|
async function mainWorker(d) {
|
|
@@ -30,7 +35,7 @@ async function mainWorker(d) {
|
|
|
30
35
|
d.log(getUsage());
|
|
31
36
|
return;
|
|
32
37
|
}
|
|
33
|
-
let herebyfilePath = (_a = args.herebyfile) !== null && _a !== void 0 ? _a :
|
|
38
|
+
let herebyfilePath = (_a = args.herebyfile) !== null && _a !== void 0 ? _a : findHerebyfile(d.cwd());
|
|
34
39
|
herebyfilePath = path.resolve(d.cwd(), herebyfilePath);
|
|
35
40
|
if (await reexec(d, herebyfilePath)) {
|
|
36
41
|
return;
|
|
@@ -42,7 +47,7 @@ async function mainWorker(d) {
|
|
|
42
47
|
d.chdir(path.dirname(herebyfilePath));
|
|
43
48
|
const herebyfile = await loadHerebyfile(herebyfilePath);
|
|
44
49
|
if (args.printTasks) {
|
|
45
|
-
d.log(formatTasks(args.printTasks, herebyfile.tasks, herebyfile.defaultTask));
|
|
50
|
+
d.log(formatTasks(args.printTasks, herebyfile.tasks.values(), herebyfile.defaultTask));
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
48
53
|
const tasks = await selectTasks(d, herebyfile, herebyfilePath, args.run);
|
|
@@ -68,30 +73,26 @@ async function mainWorker(d) {
|
|
|
68
73
|
}
|
|
69
74
|
// Exported for testing.
|
|
70
75
|
export async function selectTasks(d, herebyfile, herebyfilePath, taskNames) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
76
|
+
if (taskNames.length === 0) {
|
|
77
|
+
if (!herebyfile.defaultTask) {
|
|
78
|
+
throw new UserError(`No default task has been exported from ${d.simplifyPath(herebyfilePath)}; please specify a task name.`);
|
|
79
|
+
}
|
|
80
|
+
return [herebyfile.defaultTask];
|
|
74
81
|
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
message += ` Did you mean "${candidate}"?`;
|
|
85
|
-
}
|
|
86
|
-
throw new UserError(message);
|
|
82
|
+
const tasks = [];
|
|
83
|
+
for (const name of taskNames) {
|
|
84
|
+
const task = herebyfile.tasks.get(name);
|
|
85
|
+
if (!task) {
|
|
86
|
+
let message = `Task "${name}" does not exist or is not exported from ${d.simplifyPath(herebyfilePath)}.`;
|
|
87
|
+
const { closest, distance } = await import("fastest-levenshtein");
|
|
88
|
+
const candidate = closest(name, [...herebyfile.tasks.keys()]);
|
|
89
|
+
if (distance(name, candidate) < name.length * 0.4) {
|
|
90
|
+
message += ` Did you mean "${candidate}"?`;
|
|
87
91
|
}
|
|
88
|
-
|
|
92
|
+
throw new UserError(message);
|
|
89
93
|
}
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
if (!herebyfile.defaultTask) {
|
|
93
|
-
throw new UserError(`No default task has been exported from ${d.simplifyPath(herebyfilePath)}; please specify a task name.`);
|
|
94
|
+
tasks.push(task);
|
|
94
95
|
}
|
|
95
|
-
return
|
|
96
|
+
return tasks;
|
|
96
97
|
}
|
|
97
98
|
//# sourceMappingURL=index.js.map
|
|
@@ -4,28 +4,29 @@ import { pathToFileURL } from "node:url";
|
|
|
4
4
|
import pc from "picocolors";
|
|
5
5
|
import { Task } from "../index.js";
|
|
6
6
|
import { UserError } from "./utils.js";
|
|
7
|
-
const
|
|
8
|
-
|
|
9
|
-
const allFilenames = new Set(extensions.flatMap((e) => filenames.map((f) => `${f}.${e}`)));
|
|
10
|
-
export async function findHerebyfile(dir) {
|
|
7
|
+
const herebyfileRegExp = /^herebyfile\.m?js$/i;
|
|
8
|
+
export function findHerebyfile(dir) {
|
|
11
9
|
const root = path.parse(dir).root;
|
|
12
|
-
|
|
13
|
-
const entries =
|
|
14
|
-
const matching = entries.filter((e) =>
|
|
10
|
+
while (true) {
|
|
11
|
+
const entries = fs.readdirSync(dir);
|
|
12
|
+
const matching = entries.filter((e) => herebyfileRegExp.test(e));
|
|
15
13
|
if (matching.length > 1) {
|
|
16
14
|
throw new UserError(`Found more than one Herebyfile: ${matching.join(", ")}`);
|
|
17
15
|
}
|
|
18
16
|
if (matching.length === 1) {
|
|
19
17
|
const candidate = path.join(dir, matching[0]);
|
|
20
|
-
const stat =
|
|
18
|
+
const stat = fs.statSync(candidate);
|
|
21
19
|
if (!stat.isFile()) {
|
|
22
20
|
throw new UserError(`${matching[0]} is not a file.`);
|
|
23
21
|
}
|
|
24
22
|
return candidate;
|
|
25
23
|
}
|
|
26
24
|
if (entries.includes("package.json")) {
|
|
27
|
-
break;
|
|
25
|
+
break; // TODO: Is this actually desirable? What about monorepos?
|
|
28
26
|
}
|
|
27
|
+
if (dir === root)
|
|
28
|
+
break;
|
|
29
|
+
dir = path.dirname(dir);
|
|
29
30
|
}
|
|
30
31
|
throw new UserError("Unable to find Herebyfile.");
|
|
31
32
|
}
|
|
@@ -54,14 +55,11 @@ export async function loadHerebyfile(herebyfilePath) {
|
|
|
54
55
|
if (exportedTasks.size === 0) {
|
|
55
56
|
throw new UserError("No tasks found. Did you forget to export your tasks?");
|
|
56
57
|
}
|
|
57
|
-
const tasks = [...exportedTasks.values()];
|
|
58
58
|
// We check this here by walking the DAG, as some dependencies may not be
|
|
59
59
|
// exported and therefore would not be seen by the above loop.
|
|
60
|
-
checkTaskInvariants(
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
defaultTask,
|
|
64
|
-
};
|
|
60
|
+
checkTaskInvariants(exportedTasks);
|
|
61
|
+
const tasks = new Map([...exportedTasks.values()].map((task) => [task.options.name, task]));
|
|
62
|
+
return { tasks, defaultTask };
|
|
65
63
|
}
|
|
66
64
|
function checkTaskInvariants(tasks) {
|
|
67
65
|
const checkedTasks = new Set();
|
package/dist/cli/runner.js
CHANGED
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
import assert from "node:assert";
|
|
2
1
|
import pc from "picocolors";
|
|
3
2
|
export class Runner {
|
|
4
|
-
constructor(
|
|
3
|
+
constructor(_d) {
|
|
4
|
+
this._d = _d;
|
|
5
5
|
this._addedTasks = new Map();
|
|
6
6
|
this._errored = false;
|
|
7
7
|
this._startTimes = new Map();
|
|
8
|
-
this._d = d;
|
|
9
8
|
}
|
|
10
9
|
async runTasks(...tasks) {
|
|
11
10
|
// Using allSettled here so that we don't immediately exit; it could be
|
|
@@ -55,7 +54,7 @@ export class Runner {
|
|
|
55
54
|
if (this._errored) {
|
|
56
55
|
return; // Skip logging.
|
|
57
56
|
}
|
|
58
|
-
const took = Date.now() -
|
|
57
|
+
const took = Date.now() - this._startTimes.get(task);
|
|
59
58
|
this._d.log(`Finished ${pc.green(task.options.name)} in ${this._d.prettyMilliseconds(took)}`);
|
|
60
59
|
}
|
|
61
60
|
onTaskError(task, e) {
|
|
@@ -63,12 +62,8 @@ export class Runner {
|
|
|
63
62
|
return; // Skip logging.
|
|
64
63
|
}
|
|
65
64
|
this._errored = true;
|
|
66
|
-
const took = Date.now() -
|
|
65
|
+
const took = Date.now() - this._startTimes.get(task);
|
|
67
66
|
this._d.error(`Error in ${pc.red(task.options.name)} in ${this._d.prettyMilliseconds(took)}\n${e}`);
|
|
68
67
|
}
|
|
69
68
|
}
|
|
70
|
-
function checkDefined(value) {
|
|
71
|
-
assert(value !== undefined);
|
|
72
|
-
return value;
|
|
73
|
-
}
|
|
74
69
|
//# sourceMappingURL=runner.js.map
|
package/dist/cli/utils.js
CHANGED
|
@@ -6,13 +6,11 @@ export function compareTaskNames(a, b) {
|
|
|
6
6
|
return compareStrings(a.options.name, b.options.name);
|
|
7
7
|
}
|
|
8
8
|
// eslint-disable-next-line @typescript-eslint/unbound-method
|
|
9
|
-
|
|
9
|
+
const compareStrings = new Intl.Collator(undefined, { numeric: true }).compare;
|
|
10
10
|
// Exported for testing.
|
|
11
11
|
export function simplifyPath(p) {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
homedir += path.sep;
|
|
15
|
-
}
|
|
12
|
+
p = path.normalize(p);
|
|
13
|
+
const homedir = path.normalize(os.homedir() + path.sep);
|
|
16
14
|
if (p.startsWith(homedir)) {
|
|
17
15
|
p = p.slice(homedir.length);
|
|
18
16
|
return `~${path.sep}${p}`;
|
|
@@ -24,9 +22,6 @@ export function simplifyPath(p) {
|
|
|
24
22
|
* as a message only, without stacktrace. Use this instead of process.exit.
|
|
25
23
|
*/
|
|
26
24
|
export class UserError extends Error {
|
|
27
|
-
constructor(message) {
|
|
28
|
-
super(message);
|
|
29
|
-
}
|
|
30
25
|
}
|
|
31
26
|
/**
|
|
32
27
|
* When thrown, ExitCodeError causes the process to exit with a specific error code,
|
|
@@ -39,7 +34,6 @@ export class ExitCodeError {
|
|
|
39
34
|
}
|
|
40
35
|
}
|
|
41
36
|
export async function real() {
|
|
42
|
-
const importResolve = memoize(async () => (await import("import-meta-resolve")).resolve);
|
|
43
37
|
const { default: prettyMilliseconds } = await import("pretty-ms");
|
|
44
38
|
/* eslint-disable no-restricted-globals */
|
|
45
39
|
return {
|
|
@@ -55,23 +49,18 @@ export async function real() {
|
|
|
55
49
|
process.exitCode = code;
|
|
56
50
|
},
|
|
57
51
|
version: async () => {
|
|
58
|
-
|
|
59
|
-
const resolve = await importResolve();
|
|
52
|
+
const { resolve } = await import("import-meta-resolve");
|
|
60
53
|
const packageJsonPath = fileURLToPath(await resolve("hereby/package.json", import.meta.url));
|
|
61
54
|
const packageJson = await fs.promises.readFile(packageJsonPath, "utf8");
|
|
62
55
|
const { version } = JSON.parse(packageJson);
|
|
63
56
|
return version;
|
|
64
57
|
},
|
|
65
58
|
resolve: async (specifier, parent) => {
|
|
66
|
-
const resolve = await
|
|
59
|
+
const { resolve } = await import("import-meta-resolve");
|
|
67
60
|
return resolve(specifier, parent);
|
|
68
61
|
},
|
|
69
62
|
prettyMilliseconds,
|
|
70
63
|
};
|
|
71
64
|
/* eslint-enable no-restricted-globals */
|
|
72
65
|
}
|
|
73
|
-
function memoize(fn) {
|
|
74
|
-
let value;
|
|
75
|
-
return () => (value !== null && value !== void 0 ? value : (value = fn()));
|
|
76
|
-
}
|
|
77
66
|
//# sourceMappingURL=utils.js.map
|
package/dist/cli.js
CHANGED
|
@@ -1,15 +1,7 @@
|
|
|
1
1
|
import { main } from "./cli/index.js";
|
|
2
2
|
import { real } from "./cli/utils.js";
|
|
3
3
|
async function run() {
|
|
4
|
-
|
|
5
|
-
await main(await real());
|
|
6
|
-
}
|
|
7
|
-
catch (e) {
|
|
8
|
-
// eslint-disable-next-line no-restricted-globals
|
|
9
|
-
console.error(e);
|
|
10
|
-
// eslint-disable-next-line no-restricted-globals
|
|
11
|
-
process.exitCode = 1;
|
|
12
|
-
}
|
|
4
|
+
await main(await real());
|
|
13
5
|
}
|
|
14
6
|
void run();
|
|
15
7
|
//# sourceMappingURL=cli.js.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hereby",
|
|
3
|
-
"version": "1.8.
|
|
3
|
+
"version": "1.8.8",
|
|
4
4
|
"description": "A simple task runner",
|
|
5
5
|
"repository": "github:jakebailey/hereby",
|
|
6
6
|
"type": "module",
|
|
@@ -48,23 +48,24 @@
|
|
|
48
48
|
},
|
|
49
49
|
"devDependencies": {
|
|
50
50
|
"@ava/typescript": "^3.0.1",
|
|
51
|
+
"@changesets/cli": "^2.26.2",
|
|
51
52
|
"@tsconfig/node12": "^12.1.0",
|
|
52
|
-
"@types/command-line-usage": "^5.0.
|
|
53
|
-
"@types/minimist": "^1.2.
|
|
54
|
-
"@types/node": "^
|
|
55
|
-
"@types/tmp": "^0.2.
|
|
56
|
-
"@typescript-eslint/eslint-plugin": "^6.
|
|
57
|
-
"@typescript-eslint/parser": "^6.
|
|
53
|
+
"@types/command-line-usage": "^5.0.3",
|
|
54
|
+
"@types/minimist": "^1.2.4",
|
|
55
|
+
"@types/node": "^20.8.10",
|
|
56
|
+
"@types/tmp": "^0.2.5",
|
|
57
|
+
"@typescript-eslint/eslint-plugin": "^6.9.1",
|
|
58
|
+
"@typescript-eslint/parser": "^6.9.1",
|
|
58
59
|
"ava": "~5.0.1",
|
|
59
60
|
"c8": "^8.0.1",
|
|
60
|
-
"dprint": "^0.
|
|
61
|
-
"eslint": "^8.
|
|
61
|
+
"dprint": "^0.42.5",
|
|
62
|
+
"eslint": "^8.52.0",
|
|
62
63
|
"eslint-plugin-ava": "^14.0.0",
|
|
63
64
|
"eslint-plugin-simple-import-sort": "^10.0.0",
|
|
64
|
-
"eslint-plugin-unicorn": "^
|
|
65
|
+
"eslint-plugin-unicorn": "^49.0.0",
|
|
65
66
|
"execa": "^6.1.0",
|
|
66
|
-
"moq.ts": "^10.0.
|
|
67
|
-
"rimraf": "^5.0.
|
|
67
|
+
"moq.ts": "^10.0.8",
|
|
68
|
+
"rimraf": "^5.0.5",
|
|
68
69
|
"tmp": "^0.2.1",
|
|
69
70
|
"typescript": "^5.2.2"
|
|
70
71
|
},
|
|
@@ -101,17 +102,5 @@
|
|
|
101
102
|
"html",
|
|
102
103
|
"lcov"
|
|
103
104
|
]
|
|
104
|
-
},
|
|
105
|
-
"release-it": {
|
|
106
|
-
"npm": {
|
|
107
|
-
"publish": false
|
|
108
|
-
},
|
|
109
|
-
"git": {
|
|
110
|
-
"commitMessage": "Release v${version}",
|
|
111
|
-
"tagName": "v${version}"
|
|
112
|
-
},
|
|
113
|
-
"hooks": {
|
|
114
|
-
"before:init": "npm run build && npm run test"
|
|
115
|
-
}
|
|
116
105
|
}
|
|
117
106
|
}
|