@haltcase/run 1.0.0
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/dist/cli/bin.d.ts +2 -0
- package/dist/cli/bin.js +8 -0
- package/dist/cli/bin.js.map +1 -0
- package/dist/cli/handler.d.ts +22 -0
- package/dist/cli/handler.js +79 -0
- package/dist/cli/handler.js.map +1 -0
- package/dist/cli/handler.test.d.ts +1 -0
- package/dist/cli/handler.test.js +23 -0
- package/dist/cli/handler.test.js.map +1 -0
- package/dist/cli/main.d.ts +21 -0
- package/dist/cli/main.js +57 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/parseOptions.d.ts +12 -0
- package/dist/cli/parseOptions.js +45 -0
- package/dist/cli/parseOptions.js.map +1 -0
- package/dist/cli/parseOptions.test.d.ts +1 -0
- package/dist/cli/parseOptions.test.js +35 -0
- package/dist/cli/parseOptions.test.js.map +1 -0
- package/dist/cli/util.d.ts +15 -0
- package/dist/cli/util.js +68 -0
- package/dist/config.d.ts +16 -0
- package/dist/config.js +17 -0
- package/dist/config.js.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/tasks/executeTask.d.ts +12 -0
- package/dist/tasks/executeTask.js +43 -0
- package/dist/tasks/executeTask.js.map +1 -0
- package/dist/tasks/guards.d.ts +3 -0
- package/dist/tasks/guards.js +3 -0
- package/dist/tasks/guards.js.map +1 -0
- package/dist/tasks/task.d.ts +7 -0
- package/dist/tasks/task.js +39 -0
- package/dist/tasks/task.js.map +1 -0
- package/dist/tasks/task.test.d.ts +1 -0
- package/dist/tasks/task.test.js +25 -0
- package/dist/tasks/task.test.js.map +1 -0
- package/dist/tasks/types.d.ts +57 -0
- package/dist/tasks/types.js +2 -0
- package/dist/tasks/types.js.map +1 -0
- package/dist/tsconfig.build.tsbuildinfo +1 -0
- package/dist/util/loadTaskFile.d.ts +8 -0
- package/dist/util/loadTaskFile.js +31 -0
- package/dist/util/loadTaskFile.js.map +1 -0
- package/dist/util/resolveTaskFile.d.ts +2 -0
- package/dist/util/resolveTaskFile.js +18 -0
- package/dist/util/resolveTaskFile.js.map +1 -0
- package/dist/util/result.d.ts +9 -0
- package/dist/util/result.js +2 -0
- package/dist/util/result.js.map +1 -0
- package/dist/util/types.d.ts +7 -0
- package/dist/util/types.js +1 -0
- package/license +21 -0
- package/package.json +80 -0
- package/readme.md +352 -0
package/dist/cli/bin.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../../src/cli/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAEhC,KAAK,IAAI,CAAC;IACT,OAAO;CACP,CAAC,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Spinner } from "@favware/colorette-spinner";
|
|
2
|
+
import type { MainContextWithData } from "./main.js";
|
|
3
|
+
export declare const failWith: (spinner: Spinner, message: unknown) => never;
|
|
4
|
+
export declare const write: (message: string) => void;
|
|
5
|
+
interface HelpContextCommand {
|
|
6
|
+
command: string;
|
|
7
|
+
}
|
|
8
|
+
interface HelpContextScript extends MainContextWithData {
|
|
9
|
+
taskList: true;
|
|
10
|
+
}
|
|
11
|
+
type HelpContext = HelpContextCommand | HelpContextScript;
|
|
12
|
+
export declare const commandHandler: (_context: HelpContextCommand) => string;
|
|
13
|
+
export declare const taskListHandler: (context: HelpContextScript) => string;
|
|
14
|
+
export declare const help: (context: HelpContext) => string;
|
|
15
|
+
export interface Handler {
|
|
16
|
+
spinner: Spinner;
|
|
17
|
+
help: (context: HelpContext) => string;
|
|
18
|
+
write: (message: string) => void;
|
|
19
|
+
failWith: (message: unknown) => never;
|
|
20
|
+
}
|
|
21
|
+
export declare const createHandler: () => Handler;
|
|
22
|
+
export {};
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { Spinner } from "@favware/colorette-spinner";
|
|
2
|
+
import cliui from "@isaacs/cliui";
|
|
3
|
+
import { bold, yellow } from "colorette";
|
|
4
|
+
import { isBrandedTask } from "../tasks/guards.js";
|
|
5
|
+
export const failWith = (spinner, message) => {
|
|
6
|
+
let text;
|
|
7
|
+
if (Array.isArray(message)) {
|
|
8
|
+
text = message.map(String).join("\n");
|
|
9
|
+
}
|
|
10
|
+
if (text == null || typeof text !== "string") {
|
|
11
|
+
text = String(message);
|
|
12
|
+
}
|
|
13
|
+
spinner.error({
|
|
14
|
+
text
|
|
15
|
+
});
|
|
16
|
+
process.exit(1);
|
|
17
|
+
};
|
|
18
|
+
export const write = (message) => {
|
|
19
|
+
process.stdout.write(`${message}\n`);
|
|
20
|
+
};
|
|
21
|
+
const usage = `Usage: ${yellow("hr")} <action> [task]`;
|
|
22
|
+
export const commandHandler = (_context) => {
|
|
23
|
+
return usage;
|
|
24
|
+
};
|
|
25
|
+
export const taskListHandler = (context) => {
|
|
26
|
+
const ui = cliui({
|
|
27
|
+
width: Math.max(0, process.stdout.columns - 4),
|
|
28
|
+
wrap: true
|
|
29
|
+
});
|
|
30
|
+
const { config } = context.taskFile.data;
|
|
31
|
+
const taskInfo = Object.entries(config)
|
|
32
|
+
.map(([name, value]) => {
|
|
33
|
+
if (!value) {
|
|
34
|
+
return "";
|
|
35
|
+
}
|
|
36
|
+
const formattedName = bold(name);
|
|
37
|
+
if (isBrandedTask(value)) {
|
|
38
|
+
if (value.kind === "strictTask") {
|
|
39
|
+
const keys = Object.keys(value.inputSchema).join(", ");
|
|
40
|
+
const { description = "" } = value.schema;
|
|
41
|
+
return [formattedName, keys && `{ ${keys} }`, description]
|
|
42
|
+
.filter(Boolean)
|
|
43
|
+
.join("\t");
|
|
44
|
+
}
|
|
45
|
+
return formattedName;
|
|
46
|
+
}
|
|
47
|
+
return formattedName;
|
|
48
|
+
})
|
|
49
|
+
.join("\n");
|
|
50
|
+
ui.div(usage.replace("<action>", context.taskFile.name));
|
|
51
|
+
ui.div({
|
|
52
|
+
text: "Available tasks:",
|
|
53
|
+
padding: [1, 0, 1, 0]
|
|
54
|
+
});
|
|
55
|
+
ui.div({
|
|
56
|
+
text: taskInfo,
|
|
57
|
+
padding: [0, 2, 1, 2]
|
|
58
|
+
});
|
|
59
|
+
return ui.toString();
|
|
60
|
+
};
|
|
61
|
+
export const help = (context) => {
|
|
62
|
+
if ("command" in context) {
|
|
63
|
+
return commandHandler(context);
|
|
64
|
+
}
|
|
65
|
+
if ("taskList" in context) {
|
|
66
|
+
return taskListHandler(context);
|
|
67
|
+
}
|
|
68
|
+
return "";
|
|
69
|
+
};
|
|
70
|
+
export const createHandler = () => {
|
|
71
|
+
const spinner = new Spinner();
|
|
72
|
+
return {
|
|
73
|
+
spinner,
|
|
74
|
+
help,
|
|
75
|
+
write,
|
|
76
|
+
failWith: (message) => failWith(spinner, message)
|
|
77
|
+
};
|
|
78
|
+
};
|
|
79
|
+
//# sourceMappingURL=handler.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.js","sourceRoot":"","sources":["../../src/cli/handler.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { expect, test, vi } from "vitest";
|
|
2
|
+
import { createHandler } from "./handler.js";
|
|
3
|
+
const handler = createHandler();
|
|
4
|
+
const stdoutSpy = vi.spyOn(globalThis.process.stdout, "write");
|
|
5
|
+
const stderrSpy = vi.spyOn(globalThis.process.stderr, "write");
|
|
6
|
+
const exitSpy = vi.spyOn(globalThis.process, "exit");
|
|
7
|
+
test("handler: writes to stdout", () => {
|
|
8
|
+
const stdout = stdoutSpy.mockImplementationOnce(() => true);
|
|
9
|
+
const message = "Success";
|
|
10
|
+
handler.write(message);
|
|
11
|
+
expect(stdout).toHaveBeenCalledWith(`${message}\n`);
|
|
12
|
+
});
|
|
13
|
+
test("handler: writes to stderr and exits", () => {
|
|
14
|
+
const stderr = stderrSpy.mockImplementationOnce(() => true);
|
|
15
|
+
// @ts-expect-error we can't actually return never
|
|
16
|
+
const exit = exitSpy.mockImplementationOnce(() => {
|
|
17
|
+
// nothing
|
|
18
|
+
});
|
|
19
|
+
handler.failWith("Error message");
|
|
20
|
+
expect(stderr).toHaveBeenCalled();
|
|
21
|
+
expect(exit).toHaveBeenCalled();
|
|
22
|
+
});
|
|
23
|
+
//# sourceMappingURL=handler.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"handler.test.js","sourceRoot":"","sources":["../../src/cli/handler.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;AAE1C,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAE7C,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;AAEhC,MAAM,SAAS,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC/D,MAAM,SAAS,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAC/D,MAAM,OAAO,GAAG,EAAE,CAAC,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;AAErD,IAAI,CAAC,2BAA2B,EAAE,GAAG,EAAE;IACtC,MAAM,MAAM,GAAG,SAAS,CAAC,sBAAsB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5D,MAAM,OAAO,GAAG,SAAS,CAAC;IAC1B,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACvB,MAAM,CAAC,MAAM,CAAC,CAAC,oBAAoB,CAAC,GAAG,OAAO,IAAI,CAAC,CAAC;AACrD,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,qCAAqC,EAAE,GAAG,EAAE;IAChD,MAAM,MAAM,GAAG,SAAS,CAAC,sBAAsB,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,CAAC;IAC5D,kDAAkD;IAClD,MAAM,IAAI,GAAG,OAAO,CAAC,sBAAsB,CAAC,GAAG,EAAE;QAChD,UAAU;IACX,CAAC,CAAC,CAAC;IAEH,OAAO,CAAC,QAAQ,CAAC,eAAe,CAAC,CAAC;IAElC,MAAM,CAAC,MAAM,CAAC,CAAC,gBAAgB,EAAE,CAAC;IAClC,MAAM,CAAC,IAAI,CAAC,CAAC,gBAAgB,EAAE,CAAC;AACjC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ParsedPath } from "node:path";
|
|
2
|
+
import type { AppConfig } from "../config.js";
|
|
3
|
+
import type { TaskCollection } from "../tasks/types.js";
|
|
4
|
+
import type { ResolvedConfigWithFile } from "../util/loadTaskFile.js";
|
|
5
|
+
import type { Handler } from "./handler.js";
|
|
6
|
+
export interface MainProps {
|
|
7
|
+
handler: Handler;
|
|
8
|
+
}
|
|
9
|
+
export interface MainContext extends MainProps {
|
|
10
|
+
config: AppConfig;
|
|
11
|
+
taskFile: ParsedPath & {
|
|
12
|
+
path: string;
|
|
13
|
+
};
|
|
14
|
+
taskName: string;
|
|
15
|
+
}
|
|
16
|
+
export interface MainContextWithData extends MainContext {
|
|
17
|
+
taskFile: MainContext["taskFile"] & {
|
|
18
|
+
data: ResolvedConfigWithFile<TaskCollection>;
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export declare const main: (props: MainProps) => Promise<void>;
|
package/dist/cli/main.js
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { parse, resolve } from "node:path";
|
|
2
|
+
import { getAppConfig } from "../config.js";
|
|
3
|
+
import { executeTask } from "../tasks/executeTask.js";
|
|
4
|
+
import { loadTaskFile } from "../util/loadTaskFile.js";
|
|
5
|
+
import { resolveTaskFile } from "../util/resolveTaskFile.js";
|
|
6
|
+
import { parseOptions } from "./parseOptions.js";
|
|
7
|
+
export const main = async (props) => {
|
|
8
|
+
const { config } = await getAppConfig();
|
|
9
|
+
const inputFileName = process.argv[2];
|
|
10
|
+
const taskName = process.argv[3] ?? "";
|
|
11
|
+
if (!inputFileName) {
|
|
12
|
+
props.handler.help({ command: "help" });
|
|
13
|
+
props.handler.failWith("Task file name is required");
|
|
14
|
+
}
|
|
15
|
+
const fullFilePath = resolve(config.taskDirectory, inputFileName);
|
|
16
|
+
const context = {
|
|
17
|
+
...props,
|
|
18
|
+
config,
|
|
19
|
+
taskFile: {
|
|
20
|
+
...parse(fullFilePath),
|
|
21
|
+
path: fullFilePath
|
|
22
|
+
},
|
|
23
|
+
taskName
|
|
24
|
+
};
|
|
25
|
+
const resolutions = resolveTaskFile(context);
|
|
26
|
+
if (Array.isArray(resolutions)) {
|
|
27
|
+
props.handler.failWith([
|
|
28
|
+
`Found multiple task files with the name '${context.taskFile.name}'`,
|
|
29
|
+
`Rename the ambiguous files or specify an extension and try again`,
|
|
30
|
+
resolutions.map((it) => ` ${it}`).join("\n")
|
|
31
|
+
]);
|
|
32
|
+
}
|
|
33
|
+
const taskFileResult = await loadTaskFile(context);
|
|
34
|
+
if (!taskFileResult.ok) {
|
|
35
|
+
props.handler.failWith(taskFileResult.error);
|
|
36
|
+
}
|
|
37
|
+
const contextWithData = {
|
|
38
|
+
...context,
|
|
39
|
+
taskFile: {
|
|
40
|
+
...context.taskFile,
|
|
41
|
+
data: taskFileResult.value
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
try {
|
|
45
|
+
const options = parseOptions(process.argv.slice(4));
|
|
46
|
+
await executeTask(contextWithData, options);
|
|
47
|
+
if (!config.quiet) {
|
|
48
|
+
props.handler.spinner.success({
|
|
49
|
+
text: "Success"
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
props.handler.failWith([`Failed to execute task`, String(error)]);
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//# sourceMappingURL=main.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAG3C,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAC;AACvD,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAE7D,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAoBjD,MAAM,CAAC,MAAM,IAAI,GAAG,KAAK,EAAE,KAAgB,EAAE,EAAE;IAC9C,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,YAAY,EAAE,CAAC;IAExC,MAAM,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IACtC,MAAM,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;IAEvC,IAAI,CAAC,aAAa,EAAE,CAAC;QACpB,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;QACxC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,4BAA4B,CAAC,CAAC;IACtD,CAAC;IAED,MAAM,YAAY,GAAG,OAAO,CAAC,MAAM,CAAC,aAAa,EAAE,aAAa,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG;QACf,GAAG,KAAK;QACR,MAAM;QACN,QAAQ,EAAE;YACT,GAAG,KAAK,CAAC,YAAY,CAAC;YACtB,IAAI,EAAE,YAAY;SAClB;QACD,QAAQ;KACc,CAAC;IAExB,MAAM,WAAW,GAAG,eAAe,CAAC,OAAO,CAAC,CAAC;IAE7C,IAAI,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAChC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YACtB,4CAA4C,OAAO,CAAC,QAAQ,CAAC,IAAI,GAAG;YACpE,kEAAkE;YAClE,WAAW,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;SAC7C,CAAC,CAAC;IACJ,CAAC;IAED,MAAM,cAAc,GAAG,MAAM,YAAY,CAAC,OAAO,CAAC,CAAC;IAEnD,IAAI,CAAC,cAAc,CAAC,EAAE,EAAE,CAAC;QACxB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC;IAED,MAAM,eAAe,GAAG;QACvB,GAAG,OAAO;QACV,QAAQ,EAAE;YACT,GAAG,OAAO,CAAC,QAAQ;YACnB,IAAI,EAAE,cAAc,CAAC,KAAK;SAC1B;KAC6B,CAAC;IAEhC,IAAI,CAAC;QACJ,MAAM,OAAO,GAAG,YAAY,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;QACpD,MAAM,WAAW,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;QAE5C,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;YACnB,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC;gBAC7B,IAAI,EAAE,SAAS;aACf,CAAC,CAAC;QACJ,CAAC;IACF,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,wBAAwB,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IACnE,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export interface ParsedOptions {
|
|
2
|
+
_: string[];
|
|
3
|
+
[key: string]: unknown;
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Wrapper around Node's {@link parseArgs} that treats options as strings
|
|
7
|
+
* by default, instead of boolean flags.
|
|
8
|
+
*
|
|
9
|
+
* @param args - argv-like string
|
|
10
|
+
* @returns
|
|
11
|
+
*/
|
|
12
|
+
export declare const parseOptions: (args: string[]) => ParsedOptions;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { parseArgs } from "node:util";
|
|
2
|
+
/**
|
|
3
|
+
* Wrapper around Node's {@link parseArgs} that treats options as strings
|
|
4
|
+
* by default, instead of boolean flags.
|
|
5
|
+
*
|
|
6
|
+
* @param args - argv-like string
|
|
7
|
+
* @returns
|
|
8
|
+
*/
|
|
9
|
+
export const parseOptions = (args) => {
|
|
10
|
+
const { tokens } = parseArgs({
|
|
11
|
+
args,
|
|
12
|
+
allowPositionals: true,
|
|
13
|
+
strict: false,
|
|
14
|
+
tokens: true
|
|
15
|
+
});
|
|
16
|
+
const options = {
|
|
17
|
+
_: []
|
|
18
|
+
};
|
|
19
|
+
for (let index = 0; index < tokens.length; index++) {
|
|
20
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
21
|
+
const token = tokens[index];
|
|
22
|
+
if (token.kind === "option-terminator") {
|
|
23
|
+
continue;
|
|
24
|
+
}
|
|
25
|
+
if (token.kind === "option") {
|
|
26
|
+
if (index + 1 < tokens.length) {
|
|
27
|
+
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
|
28
|
+
const next = tokens[index + 1];
|
|
29
|
+
if (next.kind !== "positional") {
|
|
30
|
+
throw new Error(`Expected value for option ${token.rawName}`);
|
|
31
|
+
}
|
|
32
|
+
options[token.name] = next.value;
|
|
33
|
+
index++;
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
throw new Error(`Expected option ${token.rawName} to be followed by a value`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
if (token.kind === "positional") {
|
|
40
|
+
options._.push(token.value);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return options;
|
|
44
|
+
};
|
|
45
|
+
//# sourceMappingURL=parseOptions.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseOptions.js","sourceRoot":"","sources":["../../src/cli/parseOptions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAOtC;;;;;;GAMG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,CAAC,IAAc,EAAiB,EAAE;IAC7D,MAAM,EAAE,MAAM,EAAE,GAAG,SAAS,CAAC;QAC5B,IAAI;QACJ,gBAAgB,EAAE,IAAI;QACtB,MAAM,EAAE,KAAK;QACb,MAAM,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,MAAM,OAAO,GAAkB;QAC9B,CAAC,EAAE,EAAE;KACL,CAAC;IAEF,KAAK,IAAI,KAAK,GAAG,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,EAAE,EAAE,CAAC;QACpD,oEAAoE;QACpE,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAE,CAAC;QAE7B,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACxC,SAAS;QACV,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YAC7B,IAAI,KAAK,GAAG,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC/B,oEAAoE;gBACpE,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,GAAG,CAAC,CAAE,CAAC;gBAEhC,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;oBAChC,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBAC/D,CAAC;gBAED,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC;gBACjC,KAAK,EAAE,CAAC;YACT,CAAC;iBAAM,CAAC;gBACP,MAAM,IAAI,KAAK,CACd,mBAAmB,KAAK,CAAC,OAAO,4BAA4B,CAC5D,CAAC;YACH,CAAC;QACF,CAAC;QAED,IAAI,KAAK,CAAC,IAAI,KAAK,YAAY,EAAE,CAAC;YACjC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;QAC7B,CAAC;IACF,CAAC;IAED,OAAO,OAAO,CAAC;AAChB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
|
+
import { parseOptions } from "./parseOptions.js";
|
|
3
|
+
test("parseOptions: parses options as key/value and returns positionals", () => {
|
|
4
|
+
expect(parseOptions([
|
|
5
|
+
"--file",
|
|
6
|
+
"readme.md",
|
|
7
|
+
"--dryRun",
|
|
8
|
+
"true",
|
|
9
|
+
"you",
|
|
10
|
+
"spin",
|
|
11
|
+
"me",
|
|
12
|
+
"right",
|
|
13
|
+
"round"
|
|
14
|
+
])).toStrictEqual({
|
|
15
|
+
_: ["you", "spin", "me", "right", "round"],
|
|
16
|
+
file: "readme.md",
|
|
17
|
+
dryRun: "true"
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
test("parseOptions: expects all options to have values", () => {
|
|
21
|
+
expect(() => parseOptions(["--name"])).toThrow("Expected option --name to be followed by a value");
|
|
22
|
+
});
|
|
23
|
+
test("parseOptions: returns everything after terminator as positionals", () => {
|
|
24
|
+
expect(parseOptions(["--color", "blue", "--", "--name", "-aBcDeF"]))
|
|
25
|
+
.toMatchInlineSnapshot(`
|
|
26
|
+
{
|
|
27
|
+
"_": [
|
|
28
|
+
"--name",
|
|
29
|
+
"-aBcDeF",
|
|
30
|
+
],
|
|
31
|
+
"color": "blue",
|
|
32
|
+
}
|
|
33
|
+
`);
|
|
34
|
+
});
|
|
35
|
+
//# sourceMappingURL=parseOptions.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parseOptions.test.js","sourceRoot":"","sources":["../../src/cli/parseOptions.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAEtC,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAEjD,IAAI,CAAC,mEAAmE,EAAE,GAAG,EAAE;IAC9E,MAAM,CACL,YAAY,CAAC;QACZ,QAAQ;QACR,WAAW;QACX,UAAU;QACV,MAAM;QACN,KAAK;QACL,MAAM;QACN,IAAI;QACJ,OAAO;QACP,OAAO;KACP,CAAC,CACF,CAAC,aAAa,CAAC;QACf,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,OAAO,CAAC;QAC1C,IAAI,EAAE,WAAW;QACjB,MAAM,EAAE,MAAM;KACd,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kDAAkD,EAAE,GAAG,EAAE;IAC7D,MAAM,CAAC,GAAG,EAAE,CAAC,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,OAAO,CAC7C,kDAAkD,CAClD,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,IAAI,CAAC,kEAAkE,EAAE,GAAG,EAAE;IAC7E,MAAM,CAAC,YAAY,CAAC,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,CAAC,CAAC,CAAC;SAClE,qBAAqB,CAAC;;;;;;;;EAQvB,CAAC,CAAC;AACJ,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ResultError } from "../util/result.js";
|
|
2
|
+
import type { MainContextWithData } from "./main.js";
|
|
3
|
+
export declare const failWith: (message: unknown) => ResultError<Error>;
|
|
4
|
+
export declare const write: (message: string) => void;
|
|
5
|
+
interface HelpContextCommand {
|
|
6
|
+
command: string;
|
|
7
|
+
}
|
|
8
|
+
interface HelpContextScript extends MainContextWithData {
|
|
9
|
+
taskList: true;
|
|
10
|
+
}
|
|
11
|
+
type HelpContext = HelpContextCommand | HelpContextScript;
|
|
12
|
+
export declare const commandHandler: (_context: HelpContextCommand) => string;
|
|
13
|
+
export declare const taskListHandler: (context: HelpContextScript) => string;
|
|
14
|
+
export declare const help: (context: HelpContext) => string;
|
|
15
|
+
export {};
|
package/dist/cli/util.js
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import cliui from "@isaacs/cliui";
|
|
2
|
+
import { bold, yellow } from "colorette";
|
|
3
|
+
import { isBrandedTask } from "../tasks/guards.js";
|
|
4
|
+
export const failWith = (message) => {
|
|
5
|
+
let text;
|
|
6
|
+
if (Array.isArray(message)) {
|
|
7
|
+
text = message.map(String).join("\n");
|
|
8
|
+
}
|
|
9
|
+
if (text == null || typeof text !== "string") {
|
|
10
|
+
text = String(message);
|
|
11
|
+
}
|
|
12
|
+
return {
|
|
13
|
+
ok: false,
|
|
14
|
+
error: new Error(text)
|
|
15
|
+
};
|
|
16
|
+
};
|
|
17
|
+
export const write = (message) => {
|
|
18
|
+
process.stdout.write(`${message}\n`);
|
|
19
|
+
};
|
|
20
|
+
const usage = `Usage: ${yellow("funtask")} <action> [task]`;
|
|
21
|
+
export const commandHandler = (_context) => {
|
|
22
|
+
return usage;
|
|
23
|
+
};
|
|
24
|
+
export const taskListHandler = (context) => {
|
|
25
|
+
const ui = cliui({
|
|
26
|
+
width: Math.max(0, process.stdout.columns - 4),
|
|
27
|
+
wrap: true
|
|
28
|
+
});
|
|
29
|
+
const { config } = context.taskFile.data;
|
|
30
|
+
const taskInfo = Object.entries(config)
|
|
31
|
+
.map(([name, value]) => {
|
|
32
|
+
if (!value) {
|
|
33
|
+
return "";
|
|
34
|
+
}
|
|
35
|
+
const formattedName = bold(name);
|
|
36
|
+
if (isBrandedTask(value)) {
|
|
37
|
+
if (value.kind === "strictTask") {
|
|
38
|
+
const keys = Object.keys(value.inputSchema).join(", ");
|
|
39
|
+
const { description = "" } = value.schema;
|
|
40
|
+
return [formattedName, keys && `{ ${keys} }`, description]
|
|
41
|
+
.filter(Boolean)
|
|
42
|
+
.join("\t");
|
|
43
|
+
}
|
|
44
|
+
return formattedName;
|
|
45
|
+
}
|
|
46
|
+
return formattedName;
|
|
47
|
+
})
|
|
48
|
+
.join("\n");
|
|
49
|
+
ui.div(usage.replace("<action>", context.taskFile.name));
|
|
50
|
+
ui.div({
|
|
51
|
+
text: "Available tasks:",
|
|
52
|
+
padding: [1, 0, 1, 0]
|
|
53
|
+
});
|
|
54
|
+
ui.div({
|
|
55
|
+
text: taskInfo,
|
|
56
|
+
padding: [0, 2, 1, 2]
|
|
57
|
+
});
|
|
58
|
+
return ui.toString();
|
|
59
|
+
};
|
|
60
|
+
export const help = (context) => {
|
|
61
|
+
if ("command" in context) {
|
|
62
|
+
return commandHandler(context);
|
|
63
|
+
}
|
|
64
|
+
if ("taskList" in context) {
|
|
65
|
+
return taskListHandler(context);
|
|
66
|
+
}
|
|
67
|
+
return "";
|
|
68
|
+
};
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface AppConfig {
|
|
2
|
+
/**
|
|
3
|
+
* Directory containing task files. Defaults to the `scripts` folder within
|
|
4
|
+
* the current working directory.
|
|
5
|
+
*
|
|
6
|
+
* @default `<cwd>/scripts`
|
|
7
|
+
*/
|
|
8
|
+
taskDirectory: string;
|
|
9
|
+
/**
|
|
10
|
+
* Print no output unless errors occur.
|
|
11
|
+
*
|
|
12
|
+
* @default false
|
|
13
|
+
*/
|
|
14
|
+
quiet: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare const getAppConfig: () => Promise<import("c12").ResolvedConfig<AppConfig, import("c12").ConfigLayerMeta>>;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { cwd } from "node:process";
|
|
3
|
+
import { loadConfig } from "c12";
|
|
4
|
+
export const getAppConfig = async () => {
|
|
5
|
+
const configName = "haltcase.run";
|
|
6
|
+
return loadConfig({
|
|
7
|
+
name: configName,
|
|
8
|
+
configFile: configName,
|
|
9
|
+
packageJson: configName,
|
|
10
|
+
rcFile: configName,
|
|
11
|
+
defaults: {
|
|
12
|
+
taskDirectory: join(cwd(), "scripts"),
|
|
13
|
+
quiet: false
|
|
14
|
+
}
|
|
15
|
+
});
|
|
16
|
+
};
|
|
17
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,GAAG,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,UAAU,EAAE,MAAM,KAAK,CAAC;AAmBjC,MAAM,CAAC,MAAM,YAAY,GAAG,KAAK,IAAI,EAAE;IACtC,MAAM,UAAU,GAAG,cAAc,CAAC;IAElC,OAAO,UAAU,CAAY;QAC5B,IAAI,EAAE,UAAU;QAChB,UAAU,EAAE,UAAU;QACtB,WAAW,EAAE,UAAU;QACvB,MAAM,EAAE,UAAU;QAElB,QAAQ,EAAE;YACT,aAAa,EAAE,IAAI,CAAC,GAAG,EAAE,EAAE,SAAS,CAAC;YACrC,KAAK,EAAE,KAAK;SACZ;KACD,CAAC,CAAC;AACJ,CAAC,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { MainContextWithData } from "../cli/main.js";
|
|
2
|
+
import type { ParsedOptions } from "../cli/parseOptions.js";
|
|
3
|
+
export declare const taskUtilities: {
|
|
4
|
+
command: import("execa").ExecaMethod<{}>;
|
|
5
|
+
$: import("execa").ExecaScriptMethod<{}>;
|
|
6
|
+
exec: import("execa").ExecaMethod<{
|
|
7
|
+
stdin: "inherit";
|
|
8
|
+
stdout: "inherit";
|
|
9
|
+
stderr: "inherit";
|
|
10
|
+
}>;
|
|
11
|
+
};
|
|
12
|
+
export declare const executeTask: (context: MainContextWithData, options: ParsedOptions) => Promise<void>;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import { $, execa } from "execa";
|
|
3
|
+
const execaInherited = execa({
|
|
4
|
+
stdin: "inherit",
|
|
5
|
+
stdout: "inherit",
|
|
6
|
+
stderr: "inherit"
|
|
7
|
+
});
|
|
8
|
+
export const taskUtilities = {
|
|
9
|
+
command: execa,
|
|
10
|
+
$,
|
|
11
|
+
exec: execaInherited
|
|
12
|
+
};
|
|
13
|
+
export const executeTask = async (context, options) => {
|
|
14
|
+
const taskFunction = context.taskFile.data.config[context.taskName];
|
|
15
|
+
const specifier = `${context.taskFile.name}::${context.taskName}`;
|
|
16
|
+
if (taskFunction == null) {
|
|
17
|
+
context.handler.write(context.handler.help({
|
|
18
|
+
taskList: true,
|
|
19
|
+
...context
|
|
20
|
+
}));
|
|
21
|
+
if (!context.taskName) {
|
|
22
|
+
context.handler.failWith(`Task name is required.`);
|
|
23
|
+
}
|
|
24
|
+
context.handler.failWith([
|
|
25
|
+
`Task file '${context.taskFile.base}' does not export '${context.taskName}'`,
|
|
26
|
+
`Resolved to: ${join(context.taskFile.dir, context.taskFile.base)}`
|
|
27
|
+
]);
|
|
28
|
+
}
|
|
29
|
+
try {
|
|
30
|
+
await taskFunction(options, taskUtilities);
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
34
|
+
if (message.includes("is not a function")) {
|
|
35
|
+
context.handler.failWith([
|
|
36
|
+
`Failed to execute ${specifier}`,
|
|
37
|
+
`Exported value '${context.taskName}' is not a function`
|
|
38
|
+
]);
|
|
39
|
+
}
|
|
40
|
+
context.handler.failWith([`Failed to execute ${specifier}`, message]);
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
//# sourceMappingURL=executeTask.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"executeTask.js","sourceRoot":"","sources":["../../src/tasks/executeTask.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,MAAM,OAAO,CAAC;AAMjC,MAAM,cAAc,GAAG,KAAK,CAAC;IAC5B,KAAK,EAAE,SAAS;IAChB,MAAM,EAAE,SAAS;IACjB,MAAM,EAAE,SAAS;CACjB,CAAiC,CAAC;AAEnC,MAAM,CAAC,MAAM,aAAa,GAAG;IAC5B,OAAO,EAAE,KAAK;IACd,CAAC;IACD,IAAI,EAAE,cAAc;CACI,CAAC;AAE1B,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAC/B,OAA4B,EAC5B,OAAsB,EACrB,EAAE;IACH,MAAM,YAAY,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC;IACpE,MAAM,SAAS,GAAG,GAAG,OAAO,CAAC,QAAQ,CAAC,IAAI,KAAK,OAAO,CAAC,QAAQ,EAAE,CAAC;IAElE,IAAI,YAAY,IAAI,IAAI,EAAE,CAAC;QAC1B,OAAO,CAAC,OAAO,CAAC,KAAK,CACpB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC;YACpB,QAAQ,EAAE,IAAI;YACd,GAAG,OAAO;SACV,CAAC,CACF,CAAC;QAEF,IAAI,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;YACvB,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,wBAAwB,CAAC,CAAC;QACpD,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;YACxB,cAAc,OAAO,CAAC,QAAQ,CAAC,IAAI,sBAAsB,OAAO,CAAC,QAAQ,GAAG;YAC5E,gBAAgB,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,EAAE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE;SACnE,CAAC,CAAC;IACJ,CAAC;IAED,IAAI,CAAC;QACJ,MAAM,YAAY,CAAC,OAAO,EAAE,aAAa,CAAC,CAAC;IAC5C,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QAChB,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;QAEvE,IAAI,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAAC,EAAE,CAAC;YAC3C,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;gBACxB,qBAAqB,SAAS,EAAE;gBAChC,mBAAmB,OAAO,CAAC,QAAQ,qBAAqB;aACxD,CAAC,CAAC;QACJ,CAAC;QAED,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,qBAAqB,SAAS,EAAE,EAAE,OAAO,CAAC,CAAC,CAAC;IACvE,CAAC;AACF,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"guards.js","sourceRoot":"","sources":["../../src/tasks/guards.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,IAAU,EAAuB,EAAE,CAChE,MAAM,IAAI,IAAI,CAAC;AAEhB,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,IAAU,EAA6B,EAAE,CAC5E,MAAM,IAAI,IAAI,IAAI,IAAI,CAAC,IAAI,KAAK,YAAY,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import type { ParsedOptions } from "../cli/parseOptions.js";
|
|
3
|
+
import type { BrandedTask, ExpectShape, Task } from "./types.js";
|
|
4
|
+
export declare const task: {
|
|
5
|
+
<T = ParsedOptions>(fn: Task<T>): BrandedTask<T>;
|
|
6
|
+
strict<TShape extends ExpectShape, TSchema extends z.ZodObject<TShape> = z.ZodObject<TShape, z.UnknownKeysParam, z.ZodTypeAny, z.objectUtil.addQuestionMarks<z.baseObjectOutputType<TShape>, any> extends infer T ? { [k in keyof T]: z.objectUtil.addQuestionMarks<z.baseObjectOutputType<TShape>, any>[k]; } : never, z.baseObjectInputType<TShape> extends infer T_1 ? { [k_1 in keyof T_1]: z.baseObjectInputType<TShape>[k_1]; } : never>>(shape: TShape, fn: Task<z.infer<TSchema>>): BrandedTask<z.infer<TSchema>>;
|
|
7
|
+
};
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
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
|
+
}
|
|
11
|
+
if (!propertyName) {
|
|
12
|
+
return issue.message;
|
|
13
|
+
}
|
|
14
|
+
const optionText = propertyName === "_" ? "Positionals" : `--{propertyName}`;
|
|
15
|
+
// we currently assume there is only ever one path segment
|
|
16
|
+
return `${red(optionText)}: ${issue.message}`;
|
|
17
|
+
})
|
|
18
|
+
.join("\n");
|
|
19
|
+
export const task = (fn) => {
|
|
20
|
+
fn.kind = "task";
|
|
21
|
+
return fn;
|
|
22
|
+
};
|
|
23
|
+
task.strict = (shape, fn) => {
|
|
24
|
+
const schema = z.strictObject(shape);
|
|
25
|
+
const taskFunction = (options, utilities) => {
|
|
26
|
+
const { data, success, error } = schema.safeParse(options);
|
|
27
|
+
if (!success) {
|
|
28
|
+
throw new Error(fromZodError(error, { messageBuilder: zodMessageBuilder }).message, {
|
|
29
|
+
cause: error
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
return fn(data, utilities);
|
|
33
|
+
};
|
|
34
|
+
taskFunction.kind = "strictTask";
|
|
35
|
+
taskFunction.schema = schema;
|
|
36
|
+
taskFunction.inputSchema = shape;
|
|
37
|
+
return taskFunction;
|
|
38
|
+
};
|
|
39
|
+
//# sourceMappingURL=task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/tasks/task.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,WAAW,CAAC;AAChC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAC;AAUpD,MAAM,iBAAiB,GAAmB,CAAC,MAAM,EAAE,EAAE,CACpD,MAAM;KACJ,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;IACd,MAAM,YAAY,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAEnC,IAAI,KAAK,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,GAAG,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/D,OAAO,GAAG,GAAG,CAAC,sBAAsB,CAAC,KAAK,OAAO,EAAE,CAAC;IACrD,CAAC;IAED,IAAI,CAAC,YAAY,EAAE,CAAC;QACnB,OAAO,KAAK,CAAC,OAAO,CAAC;IACtB,CAAC;IAED,MAAM,UAAU,GACf,YAAY,KAAK,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,kBAAkB,CAAC;IAE3D,0DAA0D;IAC1D,OAAO,GAAG,GAAG,CAAC,UAAU,CAAC,KAAK,KAAK,CAAC,OAAO,EAAE,CAAC;AAC/C,CAAC,CAAC;KACD,IAAI,CAAC,IAAI,CAAC,CAAC;AAEd,MAAM,CAAC,MAAM,IAAI,GAAG,CAAoB,EAAW,EAAkB,EAAE;IACrE,EAAqB,CAAC,IAAI,GAAG,MAAM,CAAC;IACrC,OAAO,EAAoB,CAAC;AAC7B,CAAC,CAAC;AAEF,IAAI,CAAC,MAAM,GAAG,CAIb,KAAa,EACb,EAA0B,EACM,EAAE;IAClC,MAAM,MAAM,GAAG,CAAC,CAAC,YAAY,CAAC,KAAK,CAAC,CAAC;IAErC,MAAM,YAAY,GAAwC,CACzD,OAAO,EACP,SAAS,EACR,EAAE;QACH,MAAM,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAE3D,IAAI,CAAC,OAAO,EAAE,CAAC;YACd,MAAM,IAAI,KAAK,CACd,YAAY,CAAC,KAAK,EAAE,EAAE,cAAc,EAAE,iBAAiB,EAAE,CAAC,CAAC,OAAO,EAClE;gBACC,KAAK,EAAE,KAAK;aACZ,CACD,CAAC;QACH,CAAC;QAED,OAAO,EAAE,CAAC,IAAwB,EAAE,SAAS,CAAC,CAAC;IAChD,CAAC,CAAC;IAEF,YAAY,CAAC,IAAI,GAAG,YAAY,CAAC;IACjC,YAAY,CAAC,MAAM,GAAG,MAAM,CAAC;IAC7B,YAAY,CAAC,WAAW,GAAG,KAAK,CAAC;IAEjC,OAAO,YAAY,CAAC;AACrB,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|