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 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
@@ -1,28 +1,22 @@
1
1
  import commandLineUsage from "command-line-usage";
2
2
  import pc from "picocolors";
3
- import { compareStrings, compareTaskNames } from "./utils.js";
3
+ import { compareTaskNames } from "./utils.js";
4
4
  export function formatTasks(format, tasks, defaultTask) {
5
- tasks = tasks.filter(isTaskVisible).sort(compareTaskNames);
5
+ const visibleTasks = [...tasks].filter(isTaskVisible).sort(compareTaskNames);
6
6
  if (format === "simple") {
7
- return tasks.map((task) => task.options.name).join("\n");
7
+ return visibleTasks.map((task) => task.options.name).join("\n");
8
8
  }
9
9
  return commandLineUsage({
10
10
  header: "Available tasks",
11
- content: tasks.map((task) => {
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
- if (task.options.description) {
18
- descriptionParts = [task.options.description];
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 { compareTaskNames, ExitCodeError, UserError } from "./utils.js";
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
- else if (e instanceof UserError) {
19
+ if (e instanceof UserError) {
18
20
  d.error(`${pc.red("Error")}: ${e.message}`);
19
- d.setExitCode(1);
21
+ }
22
+ else if (util.types.isNativeError(e) && e.stack) {
23
+ d.error(e.stack);
20
24
  }
21
25
  else {
22
- throw e;
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 : (await findHerebyfile(d.cwd()));
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
- const allTasks = new Map();
72
- for (const task of herebyfile.tasks) {
73
- allTasks.set(task.options.name, task);
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
- if (taskNames.length > 0) {
76
- const tasks = [];
77
- for (const name of taskNames) {
78
- const task = allTasks.get(name);
79
- if (!task) {
80
- let message = `Task "${name}" does not exist or is not exported from ${d.simplifyPath(herebyfilePath)}.`;
81
- const { closest, distance } = await import("fastest-levenshtein");
82
- const candidate = closest(name, [...allTasks.keys()]);
83
- if (distance(name, candidate) < name.length * 0.4) {
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
- tasks.push(task);
92
+ throw new UserError(message);
89
93
  }
90
- return tasks.sort(compareTaskNames);
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 [herebyfile.defaultTask];
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 filenames = ["Herebyfile", "herebyfile"];
8
- const extensions = ["mjs", "js"];
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
- for (; dir !== root; dir = path.dirname(dir)) {
13
- const entries = await fs.promises.readdir(dir);
14
- const matching = entries.filter((e) => allFilenames.has(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 = await fs.promises.stat(candidate);
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(tasks);
61
- return {
62
- tasks,
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();
@@ -1,11 +1,10 @@
1
- import assert from "node:assert";
2
1
  import pc from "picocolors";
3
2
  export class Runner {
4
- constructor(d) {
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() - checkDefined(this._startTimes.get(task));
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() - checkDefined(this._startTimes.get(task));
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
- export const compareStrings = new Intl.Collator(undefined, { numeric: true }).compare;
9
+ const compareStrings = new Intl.Collator(undefined, { numeric: true }).compare;
10
10
  // Exported for testing.
11
11
  export function simplifyPath(p) {
12
- let homedir = os.homedir();
13
- if (!p.endsWith(path.sep)) {
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
- // Not bothering to memoize this function; it will only be called once.
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 importResolve();
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
- try {
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.6",
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.2",
53
- "@types/minimist": "^1.2.2",
54
- "@types/node": "^14.18.56",
55
- "@types/tmp": "^0.2.3",
56
- "@typescript-eslint/eslint-plugin": "^6.4.1",
57
- "@typescript-eslint/parser": "^6.4.1",
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.40.2",
61
- "eslint": "^8.48.0",
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": "^48.0.1",
65
+ "eslint-plugin-unicorn": "^49.0.0",
65
66
  "execa": "^6.1.0",
66
- "moq.ts": "^10.0.6",
67
- "rimraf": "^5.0.1",
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
  }