@haltcase/run 2.0.1 → 3.0.1

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.
Files changed (52) hide show
  1. package/dist/cli/bin.js +0 -1
  2. package/dist/cli/handler.js +5 -7
  3. package/dist/cli/main.js +5 -1
  4. package/dist/cli/parseOptions.js +0 -1
  5. package/dist/config.js +0 -1
  6. package/dist/index.js +0 -1
  7. package/dist/tasks/executeTask.js +2 -4
  8. package/dist/tasks/guards.d.ts +1 -1
  9. package/dist/tasks/guards.js +0 -1
  10. package/dist/tasks/task.d.ts +11 -4
  11. package/dist/tasks/task.js +33 -27
  12. package/dist/tasks/types.d.ts +9 -16
  13. package/dist/tasks/types.js +0 -1
  14. package/dist/tsconfig.build.tsbuildinfo +1 -1
  15. package/dist/util/getSchemaProperties.d.ts +2 -2
  16. package/dist/util/getSchemaProperties.js +30 -9
  17. package/dist/util/loadTaskFile.js +0 -1
  18. package/dist/util/resolveTaskFile.d.ts +1 -1
  19. package/dist/util/resolveTaskFile.js +0 -1
  20. package/dist/util/result.d.ts +5 -5
  21. package/dist/util/result.js +0 -1
  22. package/package.json +76 -78
  23. package/readme.md +63 -31
  24. package/dist/cli/bin.js.map +0 -1
  25. package/dist/cli/handler.js.map +0 -1
  26. package/dist/cli/handler.test.d.ts +0 -1
  27. package/dist/cli/handler.test.js +0 -23
  28. package/dist/cli/handler.test.js.map +0 -1
  29. package/dist/cli/main.js.map +0 -1
  30. package/dist/cli/parseOptions.js.map +0 -1
  31. package/dist/cli/parseOptions.test.d.ts +0 -1
  32. package/dist/cli/parseOptions.test.js +0 -43
  33. package/dist/cli/parseOptions.test.js.map +0 -1
  34. package/dist/config.js.map +0 -1
  35. package/dist/index.js.map +0 -1
  36. package/dist/tasks/executeTask.js.map +0 -1
  37. package/dist/tasks/guards.js.map +0 -1
  38. package/dist/tasks/task.js.map +0 -1
  39. package/dist/tasks/task.test.d.ts +0 -1
  40. package/dist/tasks/task.test.js +0 -124
  41. package/dist/tasks/task.test.js.map +0 -1
  42. package/dist/tasks/types.js.map +0 -1
  43. package/dist/util/getSchemaProperties.js.map +0 -1
  44. package/dist/util/getSchemaProperties.test.d.ts +0 -1
  45. package/dist/util/getSchemaProperties.test.js +0 -16
  46. package/dist/util/getSchemaProperties.test.js.map +0 -1
  47. package/dist/util/loadTaskFile.js.map +0 -1
  48. package/dist/util/resolveTaskFile.js.map +0 -1
  49. package/dist/util/result.js.map +0 -1
  50. package/dist/util/types.d.ts +0 -4
  51. package/dist/util/types.js +0 -2
  52. package/dist/util/types.js.map +0 -1
package/dist/cli/bin.js CHANGED
@@ -5,4 +5,3 @@ const handler = createHandler();
5
5
  void main({
6
6
  handler
7
7
  });
8
- //# sourceMappingURL=bin.js.map
@@ -1,8 +1,8 @@
1
1
  import { readdirSync } from "node:fs";
2
2
  import { extname } from "node:path";
3
3
  import { Spinner } from "@favware/colorette-spinner";
4
- import cliui from "@isaacs/cliui";
5
- import { bold, yellow } from "colorette";
4
+ import cliui from "cliui";
5
+ import { bold, gray, yellow } from "colorette";
6
6
  import { isBrandedTask } from "../tasks/guards.js";
7
7
  import { getSchemaProperties } from "../util/getSchemaProperties.js";
8
8
  import { extensions } from "../util/resolveTaskFile.js";
@@ -41,7 +41,7 @@ export const taskListHandler = (context) => {
41
41
  wrap: true
42
42
  });
43
43
  const { config } = context.taskFile.data;
44
- const baseUsage = usage.replace("<action>", context.taskFile.name);
44
+ const baseUsage = usage.replace("<taskFile>", context.taskFile.name);
45
45
  ui.div(`${baseUsage} <parameter> [...options]`);
46
46
  ui.div({
47
47
  text: "Available tasks:",
@@ -58,13 +58,12 @@ export const taskListHandler = (context) => {
58
58
  const formattedName = bold(name);
59
59
  if (isBrandedTask(value)) {
60
60
  if (value.kind === "strictTask") {
61
- const properties = getSchemaProperties(value.schema);
62
- const { description = "" } = value.schema;
61
+ const properties = getSchemaProperties(value.schema) || gray("not available");
63
62
  ui.div({
64
63
  text: formattedName,
65
64
  width: nameColumnWidth,
66
65
  padding: [0, taskListPaddingX, 0, taskListPaddingX]
67
- }, ...[properties, description].filter(Boolean));
66
+ }, properties);
68
67
  continue;
69
68
  }
70
69
  ui.div({
@@ -104,4 +103,3 @@ export const createHandler = () => {
104
103
  failWith: (message) => failWith(spinner, message)
105
104
  };
106
105
  };
107
- //# sourceMappingURL=handler.js.map
package/dist/cli/main.js CHANGED
@@ -33,6 +33,11 @@ export const main = async (props) => {
33
33
  resolutions.map((it) => ` ${it}`).join("\n")
34
34
  ]);
35
35
  }
36
+ // update context with the fully resolved file path
37
+ context.taskFile = {
38
+ ...parse(resolutions),
39
+ path: resolutions
40
+ };
36
41
  const taskFileResult = await loadTaskFile(context);
37
42
  if (!taskFileResult.ok) {
38
43
  props.handler.failWith(taskFileResult.error);
@@ -57,4 +62,3 @@ export const main = async (props) => {
57
62
  props.handler.failWith([`Failed to execute task`, String(error)]);
58
63
  }
59
64
  };
60
- //# sourceMappingURL=main.js.map
@@ -46,4 +46,3 @@ export const parseOptions = (args) => {
46
46
  }
47
47
  return options;
48
48
  };
49
- //# sourceMappingURL=parseOptions.js.map
package/dist/config.js CHANGED
@@ -14,4 +14,3 @@ export const getAppConfig = async () => {
14
14
  }
15
15
  });
16
16
  };
17
- //# sourceMappingURL=config.js.map
package/dist/index.js CHANGED
@@ -1,2 +1 @@
1
1
  export { task } from "./tasks/task.js";
2
- //# sourceMappingURL=index.js.map
@@ -1,4 +1,3 @@
1
- import { join } from "node:path";
2
1
  import { $, execa } from "execa";
3
2
  const execaInherited = execa({
4
3
  stdin: "inherit",
@@ -22,8 +21,8 @@ export const executeTask = async (context, options) => {
22
21
  context.handler.failWith(`Task name is required.`);
23
22
  }
24
23
  context.handler.failWith([
25
- `Task file '${context.taskFile.base}' does not export '${context.taskName}'`,
26
- `Resolved to: ${join(context.taskFile.dir, context.taskFile.base)}`
24
+ `Task file '${context.taskFile.name}' does not export '${context.taskName}'`,
25
+ `Resolved to: ${context.taskFile.path}`
27
26
  ]);
28
27
  }
29
28
  try {
@@ -44,4 +43,3 @@ export const executeTask = async (context, options) => {
44
43
  context.handler.failWith([`Failed to execute ${specifier}`, message]);
45
44
  }
46
45
  };
47
- //# sourceMappingURL=executeTask.js.map
@@ -1,3 +1,3 @@
1
1
  import type { BrandedTask, BrandedTaskStrict, Task } from "./types.js";
2
2
  export declare const isBrandedTask: (task: Task) => task is BrandedTask;
3
- export declare const isBrandedTaskStrict: (task: Task) => task is BrandedTaskStrict;
3
+ export declare const isBrandedTaskStrict: <T>(task: Task<T>) => task is BrandedTaskStrict<T>;
@@ -1,3 +1,2 @@
1
1
  export const isBrandedTask = (task) => "kind" in task;
2
2
  export const isBrandedTaskStrict = (task) => "kind" in task && task.kind === "strictTask";
3
- //# sourceMappingURL=guards.js.map
@@ -1,7 +1,14 @@
1
- import { z } from "zod";
2
- import type { Defined, Merge } from "../util/types.js";
3
- import type { BrandedTask, BrandedTaskStrict, DefaultOptionsInput, SchemaDefaults, SchemaInput, Task } from "./types.js";
1
+ import type { Type } from "arktype";
2
+ import { type } from "arktype";
3
+ import type { BrandedTask, BrandedTaskStrict, DefaultOptionsInput, Task } from "./types.js";
4
4
  export declare const task: {
5
5
  <T = DefaultOptionsInput>(fn: Task<T>): BrandedTask<T>;
6
- strict<TShape extends Partial<SchemaInput>, TSchema extends z.ZodObject<Merge<SchemaDefaults, Defined<TShape>>> = z.ZodObject<Merge<SchemaDefaults, Defined<TShape>>, z.UnknownKeysParam, z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Merge<SchemaDefaults, Defined<TShape>>>, any> extends infer T ? { [k in keyof T]: z.objectUtil.addQuestionMarks<z.baseObjectOutputType<Merge<SchemaDefaults, Defined<TShape>>>, any>[k]; } : never, z.baseObjectInputType<Merge<SchemaDefaults, Defined<TShape>>> extends infer T_1 ? { [k_1 in keyof T_1]: z.baseObjectInputType<Merge<SchemaDefaults, Defined<TShape>>>[k_1]; } : never>>(shape: TShape, fn: Task<z.infer<TSchema>>): BrandedTaskStrict<TSchema>;
6
+ strict<const TShape>(shape: type.validate<TShape>, fn: Task<NoInfer<Type<type.infer<TShape>>["infer"]>>): BrandedTaskStrict<Type<type.infer<TShape>>["inferIn"]>;
7
7
  };
8
+ /**
9
+ * Default schema for the options received by a {@link task}.
10
+ */
11
+ export declare const defaultOptionsInput: import("arktype/internal/methods/object.ts").ObjectType<{
12
+ _: string[];
13
+ env: Record<string, string | undefined>;
14
+ }, {}>;
@@ -1,49 +1,55 @@
1
+ import { type } from "arktype";
1
2
  import { red } from "colorette";
2
- import { z } from "zod";
3
- import { fromZodError } from "zod-validation-error";
4
- const zodMessageBuilder = (issues) => issues
5
- .map((issue) => {
6
- const propertyName = issue.path[0];
7
- if (issue.code === "unrecognized_keys") {
8
- const keyList = issue.keys.map((key) => `--${key}`).join(", ");
9
- return `${red("Unrecognized options")}: ${keyList}`;
10
- }
3
+ const formatValidationIssues = (errors) => errors
4
+ .map((error) => {
5
+ const propertyName = String(error.path[0]);
6
+ const dottedPath = error.path.join(".");
11
7
  if (!propertyName) {
12
- return issue.message;
8
+ return error.message;
13
9
  }
10
+ const messageWithoutProperty = error.message.startsWith(dottedPath)
11
+ ? error.message.slice(dottedPath.length + 1)
12
+ : error.message;
14
13
  if (propertyName === "env") {
15
- const prefix = red(`Environment variable '${issue.path[1]}'`);
16
- return `${prefix}: ${issue.message}`;
14
+ const prefix = red(`Environment variable '${String(error.path[1])}'`);
15
+ return `${prefix}: ${messageWithoutProperty}`;
17
16
  }
18
17
  const optionText = propertyName === "_" ? "Positionals" : `--${propertyName}`;
18
+ if (error.code === "predicate" && error.expected === "removed") {
19
+ return `${red(optionText)}: unknown option`;
20
+ }
19
21
  // we currently assume there is only ever one path segment
20
- return `${red(optionText)}: ${issue.message}`;
22
+ return `${red(optionText)}: ${messageWithoutProperty}`;
21
23
  })
22
24
  .join("\n");
23
25
  export const task = (fn) => {
24
26
  fn.kind = "task";
25
27
  return fn;
26
28
  };
29
+ /**
30
+ * Default schema for the options received by a {@link task}.
31
+ */
32
+ export const defaultOptionsInput = type({
33
+ _: "string[]",
34
+ env: "Record<string, string | undefined>"
35
+ });
36
+ /**
37
+ * Create a task that validates its input against a schema.
38
+ */
27
39
  task.strict = (shape, fn) => {
28
- const defaultValidators = {
29
- _: z.string().array(),
30
- env: z.object({}).passthrough()
31
- };
32
- const schema = z.strictObject({
33
- ...defaultValidators,
34
- ...shape
35
- });
40
+ const schema = defaultOptionsInput
41
+ .merge(type.raw(shape))
42
+ .onUndeclaredKey("reject");
36
43
  const taskFunction = (options, utilities) => {
37
- const { data, success, error } = schema.safeParse(options);
38
- if (!success) {
39
- throw new Error(fromZodError(error, { messageBuilder: zodMessageBuilder }).message, {
40
- cause: error
44
+ const validationResult = schema(options);
45
+ if (validationResult instanceof type.errors) {
46
+ throw new TypeError(formatValidationIssues(validationResult), {
47
+ cause: validationResult
41
48
  });
42
49
  }
43
- return fn(data, utilities);
50
+ return fn(validationResult, utilities);
44
51
  };
45
52
  taskFunction.kind = "strictTask";
46
53
  taskFunction.schema = schema;
47
54
  return taskFunction;
48
55
  };
49
- //# sourceMappingURL=task.js.map
@@ -1,5 +1,5 @@
1
+ import type { Type } from "arktype";
1
2
  import type { ExecaMethod, ExecaScriptMethod } from "execa";
2
- import type { z } from "zod";
3
3
  import type { ParsedOptions } from "../cli/parseOptions.js";
4
4
  export interface TaskUtilities {
5
5
  /**
@@ -39,27 +39,20 @@ export interface TaskUtilities {
39
39
  stderr: "inherit";
40
40
  }>;
41
41
  }
42
- export type CustomShape = Record<string, z.ZodTypeAny>;
43
- export interface SchemaInput {
44
- _: z.ZodType<any, z.ZodTypeDef, string[]>;
45
- env: z.ZodType<any, z.ZodTypeDef, Record<string, string | undefined>>;
46
- [key: string]: z.ZodTypeAny;
47
- }
48
- export interface SchemaDefaults {
49
- _: z.ZodArray<z.ZodString>;
50
- env: z.ZodObject<Record<string, z.ZodOptional<z.ZodString>>>;
51
- }
52
42
  export type DefaultOptionsInput = ParsedOptions & {
53
43
  env: Record<string, string | undefined>;
54
44
  };
55
45
  export type TaskCollection = Partial<Record<string, Task>>;
56
- export type Task<TOptions = DefaultOptionsInput> = (options: TOptions, utilities: TaskUtilities) => unknown;
57
- export type BrandedTaskStrict<TSchema extends z.ZodTypeAny = z.ZodType<DefaultOptionsInput>> = Task<z.input<TSchema>> & {
46
+ type MergePositionals<TOptions> = "_" extends keyof TOptions ? TOptions : TOptions & ParsedOptions;
47
+ type MergeEnvironment<TOptions> = "env" extends keyof TOptions ? TOptions : TOptions & Pick<DefaultOptionsInput, "env">;
48
+ export type Task<TOptions = unknown> = (options: MergePositionals<MergeEnvironment<TOptions>>, utilities: TaskUtilities) => unknown;
49
+ export type BrandedTaskStrict<TShape = DefaultOptionsInput> = Task<TShape> & {
58
50
  kind: "strictTask";
59
- schema: TSchema;
51
+ schema: Type<TShape>;
60
52
  };
61
- export type BrandedTaskLoose<TOptions = DefaultOptionsInput> = Task<TOptions> & {
53
+ export type BrandedTaskLoose<TOptions = unknown> = Task<TOptions> & {
62
54
  kind: "task";
63
55
  schema: never;
64
56
  };
65
- export type BrandedTask<TOptions = DefaultOptionsInput> = BrandedTaskLoose<TOptions> | BrandedTaskStrict<z.ZodType<TOptions>>;
57
+ export type BrandedTask<TOptions = unknown> = BrandedTaskLoose<TOptions> | BrandedTaskStrict<TOptions>;
58
+ export {};
@@ -1,2 +1 @@
1
1
  export {};
2
- //# sourceMappingURL=types.js.map