@codeandmoney/jargal 0.0.0-rc.2 → 0.0.0-rc.5
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/actions/context/context.ts +44 -0
- package/actions/context.ts +2 -2
- package/actions/echo.ts +16 -4
- package/actions/jargal-context.ts +21 -0
- package/actions/jargal-templates.ts +64 -0
- package/actions/jargal-write.ts +46 -0
- package/actions/load-templates.ts +83 -13
- package/actions/parallel.ts +1 -1
- package/actions/pipe/pipe.ts +993 -0
- package/actions/pipe.ts +7 -0
- package/actions/render-template.ts +7 -14
- package/actions/run/run.ts +20 -0
- package/actions/validate-answers.ts +1 -1
- package/actions/write/write.ts +69 -0
- package/actions/write.ts +18 -14
- package/bun.lock +68 -0
- package/jargal.ts +139 -0
- package/package.json +3 -2
- package/renderer.ts +4 -4
- package/runner.ts +3 -5
- package/types.ts +11 -14
package/actions/pipe.ts
ADDED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import type { Action, Context } from "../types.ts";
|
|
2
2
|
|
|
3
3
|
export function renderTemplate({
|
|
4
|
-
|
|
4
|
+
templatePath,
|
|
5
5
|
template,
|
|
6
6
|
getData,
|
|
7
|
-
|
|
7
|
+
save,
|
|
8
8
|
}: {
|
|
9
9
|
template: string;
|
|
10
|
-
|
|
10
|
+
templatePath: string;
|
|
11
11
|
getData?: (ctx: Context) => Record<string, unknown>;
|
|
12
|
-
|
|
12
|
+
save?: Action<{ templateContent?: string; destination?: string }>;
|
|
13
13
|
}): Action {
|
|
14
14
|
if (!template) {
|
|
15
15
|
return () => undefined;
|
|
@@ -20,17 +20,10 @@ export function renderTemplate({
|
|
|
20
20
|
|
|
21
21
|
const renderedTemplate = params.renderer.renderString({ template, data });
|
|
22
22
|
|
|
23
|
-
const renderedPath = params.renderer.renderString({
|
|
24
|
-
template: fullpath,
|
|
25
|
-
data,
|
|
26
|
-
});
|
|
23
|
+
const renderedPath = params.renderer.renderString({ template: templatePath, data });
|
|
27
24
|
|
|
28
|
-
if (
|
|
29
|
-
return
|
|
30
|
-
...params,
|
|
31
|
-
content: renderedTemplate,
|
|
32
|
-
destination: renderedPath,
|
|
33
|
-
});
|
|
25
|
+
if (save) {
|
|
26
|
+
return save({ ...params, context: { ...params.context, templateContent: renderedTemplate, destination: renderedPath } });
|
|
34
27
|
}
|
|
35
28
|
};
|
|
36
29
|
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { BaseIssue, BaseAction, Config, InferIssue, InferOutput } from "../../types/index.ts";
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Parses an unknown input based on a schema.
|
|
5
|
+
*
|
|
6
|
+
* @param action The action to be used.
|
|
7
|
+
* @param input The input to be parsed.
|
|
8
|
+
* @param config The run configuration.
|
|
9
|
+
*
|
|
10
|
+
* @returns The parsed input.
|
|
11
|
+
*/
|
|
12
|
+
export function run<const Action extends BaseAction<unknown, unknown>>(action: Action, input: unknown): InferOutput<Action> {
|
|
13
|
+
const context = action["~run"]({ value: input }, {});
|
|
14
|
+
|
|
15
|
+
if (context.issues) {
|
|
16
|
+
throw new Error("msg");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return context.value;
|
|
20
|
+
}
|
|
@@ -6,7 +6,7 @@ const primitiveSchema = v.union([v.pipe(v.string(), v.minLength(1)), v.boolean()
|
|
|
6
6
|
|
|
7
7
|
const defaultSchema = v.record(v.string(), v.union([primitiveSchema, v.array(primitiveSchema)]));
|
|
8
8
|
|
|
9
|
-
export function validateAnswers<Schema extends v.
|
|
9
|
+
export function validateAnswers<Schema extends v.BaseAction<unknown, unknown, v.BaseIssue<unknown>>>(schema?: Schema): Action {
|
|
10
10
|
return function execute(params) {
|
|
11
11
|
v.assert(schema ?? defaultSchema, params.context.answers);
|
|
12
12
|
};
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import type { BaseIssue, BaseAction, ErrorMessage, Context, OutputContext, BaseContext } from "../../types/index.ts";
|
|
2
|
+
// import { _addIssue, _getStandardProps } from "../../utils/index.ts";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Write issue interface.
|
|
6
|
+
*/
|
|
7
|
+
export interface WriteIssue extends BaseIssue<unknown> {
|
|
8
|
+
/**
|
|
9
|
+
* The issue kind.
|
|
10
|
+
*/
|
|
11
|
+
readonly kind: "action";
|
|
12
|
+
/**
|
|
13
|
+
* The issue type.
|
|
14
|
+
*/
|
|
15
|
+
readonly type: "string";
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Write schema interface.
|
|
20
|
+
*/
|
|
21
|
+
export interface WriteAction<Config extends Record<string, any> | undefined, Output extends Record<string, any>> extends BaseAction<Config, Output> {
|
|
22
|
+
readonly config: Config;
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* The expected property.
|
|
26
|
+
*/
|
|
27
|
+
readonly expects: "string";
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export type WriteActionConfig = {
|
|
31
|
+
destination?: string;
|
|
32
|
+
templateContent?: string;
|
|
33
|
+
mode?: "force" | "skip-if-exists";
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
// /**
|
|
37
|
+
// * Creates a string schema.
|
|
38
|
+
// *
|
|
39
|
+
// * @param config The error config.
|
|
40
|
+
// *
|
|
41
|
+
// * @returns A string schema.
|
|
42
|
+
// */
|
|
43
|
+
|
|
44
|
+
export function write<Ctx extends Record<string, any>>(config?: WriteActionConfig): WriteAction<WriteActionConfig, Ctx>;
|
|
45
|
+
export function write<Ctx extends undefined = undefined>(config: WriteActionConfig): WriteAction<WriteActionConfig, {}>;
|
|
46
|
+
export function write<Ctx extends undefined | Record<string, any> = undefined>(
|
|
47
|
+
config?: WriteActionConfig,
|
|
48
|
+
): WriteAction<WriteActionConfig, Ctx extends undefined ? {} : Ctx> {
|
|
49
|
+
return {
|
|
50
|
+
kind: "action",
|
|
51
|
+
expects: "string",
|
|
52
|
+
|
|
53
|
+
config: config ?? {},
|
|
54
|
+
"~run"(context, config) {
|
|
55
|
+
context.renderer;
|
|
56
|
+
|
|
57
|
+
if (typeof context.value === "string") {
|
|
58
|
+
// @ts-expect-error
|
|
59
|
+
context.typed = true;
|
|
60
|
+
} else {
|
|
61
|
+
// _addIssue(this, "type", context, config);
|
|
62
|
+
}
|
|
63
|
+
// @ts-expect-error
|
|
64
|
+
return context as OutputContext<string, WriteIssue>;
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
// hooks?: ActionHooks;
|
package/actions/write.ts
CHANGED
|
@@ -6,38 +6,42 @@ import { dirname } from "node:path";
|
|
|
6
6
|
|
|
7
7
|
export type WriteActionConfig = {
|
|
8
8
|
destination?: string;
|
|
9
|
-
|
|
9
|
+
templateContent?: string;
|
|
10
10
|
mode?: "force" | "skip-if-exists";
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
export function write({
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
export function write({
|
|
14
|
+
destination: writeDestination,
|
|
15
|
+
templateContent: writeContent,
|
|
16
|
+
mode,
|
|
17
|
+
}: WriteActionConfig): Action<{ templateContent?: string; destination?: string }> {
|
|
18
|
+
return async function execute({ context: { templateContent: executeContent, destination: executeDestination } }) {
|
|
19
|
+
const destination = executeDestination || writeDestination;
|
|
20
|
+
const templateContent = executeContent || writeContent;
|
|
17
21
|
|
|
18
|
-
assert(
|
|
19
|
-
assert(
|
|
22
|
+
assert(destination, "must provide `destination`");
|
|
23
|
+
assert(templateContent, "must provide `templateContent`");
|
|
20
24
|
|
|
21
|
-
await mkdir(dirname(
|
|
25
|
+
await mkdir(dirname(destination), { recursive: true });
|
|
22
26
|
|
|
23
|
-
let doesExist = await fileExists(
|
|
27
|
+
let doesExist = await fileExists(destination);
|
|
24
28
|
|
|
25
29
|
if (doesExist && mode === "force") {
|
|
26
|
-
await rm(
|
|
30
|
+
await rm(destination, { recursive: true, force: true });
|
|
27
31
|
doesExist = false;
|
|
28
32
|
}
|
|
29
33
|
|
|
30
34
|
if (doesExist && mode !== "skip-if-exists") {
|
|
31
|
-
throw `File already exists\n -> ${
|
|
35
|
+
throw `File already exists\n -> ${destination}`;
|
|
32
36
|
}
|
|
33
37
|
|
|
34
38
|
if (doesExist && mode === "skip-if-exists") {
|
|
35
|
-
console.info(`[SKIPPED] ${
|
|
39
|
+
console.info(`[SKIPPED] ${destination} (exists)`);
|
|
36
40
|
return;
|
|
37
41
|
}
|
|
38
42
|
|
|
39
|
-
await writeFile(
|
|
40
|
-
} satisfies Action<{
|
|
43
|
+
await writeFile(destination, new TextEncoder().encode(templateContent));
|
|
44
|
+
} satisfies Action<{ templateContent?: string; destination?: string }>;
|
|
41
45
|
}
|
|
42
46
|
|
|
43
47
|
function fileExists(destination: string) {
|
package/bun.lock
ADDED
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lockfileVersion": 1,
|
|
3
|
+
"workspaces": {
|
|
4
|
+
"": {
|
|
5
|
+
"name": "@codeandmoney/jargal",
|
|
6
|
+
"dependencies": {
|
|
7
|
+
"change-case": "^5.4.4",
|
|
8
|
+
"enquirer": "^2.4.1",
|
|
9
|
+
"es-toolkit": "^1.40.0",
|
|
10
|
+
"handlebars": "^4.7.8",
|
|
11
|
+
"title-case": "^4.3.2",
|
|
12
|
+
"valibot": "^1.1.0",
|
|
13
|
+
},
|
|
14
|
+
"devDependencies": {
|
|
15
|
+
"@types/bun": "^1.3.0",
|
|
16
|
+
"@types/node": "^24.7.2",
|
|
17
|
+
},
|
|
18
|
+
"peerDependencies": {
|
|
19
|
+
"typescript": "^5",
|
|
20
|
+
},
|
|
21
|
+
},
|
|
22
|
+
},
|
|
23
|
+
"packages": {
|
|
24
|
+
"@types/bun": ["@types/bun@1.3.0", "", { "dependencies": { "bun-types": "1.3.0" } }, "sha512-+lAGCYjXjip2qY375xX/scJeVRmZ5cY0wyHYyCYxNcdEXrQ4AOe3gACgd4iQ8ksOslJtW4VNxBJ8llUwc3a6AA=="],
|
|
25
|
+
|
|
26
|
+
"@types/node": ["@types/node@24.7.2", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-/NbVmcGTP+lj5oa4yiYxxeBjRivKQ5Ns1eSZeB99ExsEQ6rX5XYU1Zy/gGxY/ilqtD4Etx9mKyrPxZRetiahhA=="],
|
|
27
|
+
|
|
28
|
+
"@types/react": ["@types/react@19.2.2", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-6mDvHUFSjyT2B2yeNx2nUgMxh9LtOWvkhIU3uePn2I2oyNymUAX1NIsdgviM4CH+JSrp2D2hsMvJOkxY+0wNRA=="],
|
|
29
|
+
|
|
30
|
+
"ansi-colors": ["ansi-colors@4.1.3", "", {}, "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw=="],
|
|
31
|
+
|
|
32
|
+
"ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="],
|
|
33
|
+
|
|
34
|
+
"bun-types": ["bun-types@1.3.0", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-u8X0thhx+yJ0KmkxuEo9HAtdfgCBaM/aI9K90VQcQioAmkVp3SG3FkwWGibUFz3WdXAdcsqOcbU40lK7tbHdkQ=="],
|
|
35
|
+
|
|
36
|
+
"change-case": ["change-case@5.4.4", "", {}, "sha512-HRQyTk2/YPEkt9TnUPbOpr64Uw3KOicFWPVBb+xiHvd6eBx/qPr9xqfBFDT8P2vWsvvz4jbEkfDe71W3VyNu2w=="],
|
|
37
|
+
|
|
38
|
+
"csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="],
|
|
39
|
+
|
|
40
|
+
"enquirer": ["enquirer@2.4.1", "", { "dependencies": { "ansi-colors": "^4.1.1", "strip-ansi": "^6.0.1" } }, "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ=="],
|
|
41
|
+
|
|
42
|
+
"es-toolkit": ["es-toolkit@1.40.0", "", {}, "sha512-8o6w0KFmU0CiIl0/Q/BCEOabF2IJaELM1T2PWj6e8KqzHv1gdx+7JtFnDwOx1kJH/isJ5NwlDG1nCr1HrRF94Q=="],
|
|
43
|
+
|
|
44
|
+
"handlebars": ["handlebars@4.7.8", "", { "dependencies": { "minimist": "^1.2.5", "neo-async": "^2.6.2", "source-map": "^0.6.1", "wordwrap": "^1.0.0" }, "optionalDependencies": { "uglify-js": "^3.1.4" }, "bin": { "handlebars": "bin/handlebars" } }, "sha512-vafaFqs8MZkRrSX7sFVUdo3ap/eNiLnb4IakshzvP56X5Nr1iGKAIqdX6tMlm6HcNRIkr6AxO5jFEoJzzpT8aQ=="],
|
|
45
|
+
|
|
46
|
+
"minimist": ["minimist@1.2.8", "", {}, "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA=="],
|
|
47
|
+
|
|
48
|
+
"neo-async": ["neo-async@2.6.2", "", {}, "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw=="],
|
|
49
|
+
|
|
50
|
+
"source-map": ["source-map@0.6.1", "", {}, "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g=="],
|
|
51
|
+
|
|
52
|
+
"strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="],
|
|
53
|
+
|
|
54
|
+
"title-case": ["title-case@4.3.2", "", {}, "sha512-I/nkcBo73mO42Idfv08jhInV61IMb61OdIFxk+B4Gu1oBjWBPOLmhZdsli+oJCVaD+86pYQA93cJfFt224ZFAA=="],
|
|
55
|
+
|
|
56
|
+
"typescript": ["typescript@5.9.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-jl1vZzPDinLr9eUt3J/t7V6FgNEw9QjvBPdysz9KfQDD41fQrC2Y4vKQdiaUpFT4bXlb1RHhLpp8wtm6M5TgSw=="],
|
|
57
|
+
|
|
58
|
+
"uglify-js": ["uglify-js@3.19.3", "", { "bin": { "uglifyjs": "bin/uglifyjs" } }, "sha512-v3Xu+yuwBXisp6QYTcH4UbH+xYJXqnq2m/LtQVWKWzYc1iehYnLixoQDN9FH6/j9/oybfd6W9Ghwkl8+UMKTKQ=="],
|
|
59
|
+
|
|
60
|
+
"undici-types": ["undici-types@7.14.0", "", {}, "sha512-QQiYxHuyZ9gQUIrmPo3IA+hUl4KYk8uSA7cHrcKd/l3p1OTpZcM0Tbp9x7FAtXdAYhlasd60ncPpgu6ihG6TOA=="],
|
|
61
|
+
|
|
62
|
+
"valibot": ["valibot@1.1.0", "", { "peerDependencies": { "typescript": ">=5" }, "optionalPeers": ["typescript"] }, "sha512-Nk8lX30Qhu+9txPYTwM0cFlWLdPFsFr6LblzqIySfbZph9+BFsAHsNvHOymEviUepeIW6KFHzpX8TKhbptBXXw=="],
|
|
63
|
+
|
|
64
|
+
"wordwrap": ["wordwrap@1.0.0", "", {}, "sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q=="],
|
|
65
|
+
|
|
66
|
+
"bun-types/@types/node": ["@types/node@24.7.0", "", { "dependencies": { "undici-types": "~7.14.0" } }, "sha512-IbKooQVqUBrlzWTi79E8Fw78l8k1RNtlDDNWsFZs7XonuQSJ8oNYfEeclhprUldXISRMLzBpILuKgPlIxm+/Yw=="],
|
|
67
|
+
}
|
|
68
|
+
}
|
package/jargal.ts
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { merge, toMerged } from "es-toolkit";
|
|
2
|
+
import { Renderer } from "./renderer";
|
|
3
|
+
import { write } from "./actions/jargal-write";
|
|
4
|
+
import { resolve, dirname, join } from "path";
|
|
5
|
+
import { mkdir } from "fs/promises";
|
|
6
|
+
import { writeFile } from "fs/promises";
|
|
7
|
+
|
|
8
|
+
import { templates, type TemplatesMap } from "./actions/jargal-templates";
|
|
9
|
+
import { context } from "./actions/jargal-context";
|
|
10
|
+
|
|
11
|
+
export { templates, context };
|
|
12
|
+
|
|
13
|
+
export type RenderEntry = { control: "user"; data: any; pathTemplate: string; contentTemplate: string } | { control?: "auto"; data: any; destination: string };
|
|
14
|
+
|
|
15
|
+
export class Jargal<const in out Context> {
|
|
16
|
+
#context = {
|
|
17
|
+
templates: { default: {} },
|
|
18
|
+
renderData: [] as { baseSavePath: string; data: any }[],
|
|
19
|
+
renderedContent: [] as { savePath: string; content: string }[],
|
|
20
|
+
} as Context;
|
|
21
|
+
|
|
22
|
+
#renderer: Renderer;
|
|
23
|
+
|
|
24
|
+
get context() {
|
|
25
|
+
return this.#context;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
constructor() {
|
|
29
|
+
this.#renderer = new Renderer();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
setContext<Setter extends (...args: any) => any>(setter: Setter): Jargal<ReturnType<Setter> & Context>;
|
|
33
|
+
setContext<const Setter extends Record<string, any>>(setter: Setter): Jargal<Setter & Context>;
|
|
34
|
+
setContext(setter: any) {
|
|
35
|
+
if (typeof setter === "function") {
|
|
36
|
+
const context = setter(this.#context);
|
|
37
|
+
this.#context = toMerged(this.#context as any, context);
|
|
38
|
+
return this as any;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
this.#context = toMerged(this.#context as any, setter);
|
|
42
|
+
return this as any;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
async render(params?: {
|
|
46
|
+
composeRenderData?: (ctx: Context) => RenderEntry[] | Promise<RenderEntry[]>;
|
|
47
|
+
scope?: Context extends { templates: { [key: string]: any } } ? keyof Context["templates"] : "default";
|
|
48
|
+
}): Promise<Jargal<Context & { renderedContent: { savePath: string; content: string }[] }>> {
|
|
49
|
+
const composeData: (ctx: Context) => RenderEntry[] | Promise<RenderEntry[]> =
|
|
50
|
+
params?.composeRenderData ??
|
|
51
|
+
// @ts-expect-error
|
|
52
|
+
((ctx: Context) => ctx.renderData);
|
|
53
|
+
|
|
54
|
+
// @ts-expect-error
|
|
55
|
+
const templatesToRender = this.#context.templates[params?.scope ?? "default"] as TemplatesMap;
|
|
56
|
+
|
|
57
|
+
const composedData = await composeData(this.#context);
|
|
58
|
+
|
|
59
|
+
for (const renderEntry of composedData) {
|
|
60
|
+
if (!renderEntry.control || renderEntry.control === "auto") {
|
|
61
|
+
for (const [filename, template] of Object.entries(templatesToRender)) {
|
|
62
|
+
// @ts-expect-error
|
|
63
|
+
this.#context.renderedContent.push({
|
|
64
|
+
savePath: this.#renderer.renderString({ template: join(renderEntry.destination, template.savePath), data: renderEntry.data }),
|
|
65
|
+
content: this.#renderer.renderString({ template: template.templateContent, data: renderEntry.data }),
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
if (renderEntry.control === "user") {
|
|
73
|
+
// @ts-expect-error
|
|
74
|
+
this.#context.renderedContent.push({
|
|
75
|
+
savePath: this.#renderer.renderString({ template: renderEntry.pathTemplate, data: renderEntry.data }),
|
|
76
|
+
content: this.#renderer.renderString({ template: renderEntry.contentTemplate, data: renderEntry.data }),
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
// const entryContentTemplate = renderEntry.contentTemplate;
|
|
84
|
+
|
|
85
|
+
// let renderedContent: string | undefined = undefined;
|
|
86
|
+
// let renderedPath: string | undefined = undefined;
|
|
87
|
+
|
|
88
|
+
// if (renderEntry.contentTemplate) {
|
|
89
|
+
// const templateToRender =
|
|
90
|
+
// // @ts-expect-error
|
|
91
|
+
// (this.#context.templates[params?.scope ?? "default"] as TemplatesMap)[renderEntry.contentTemplate]?.templateContent || renderEntry.contentTemplate;
|
|
92
|
+
|
|
93
|
+
// renderedContent = this.#renderer.renderString({ template: templateToRender, data: renderEntry.data });
|
|
94
|
+
// continue;
|
|
95
|
+
// }
|
|
96
|
+
|
|
97
|
+
// if (renderEntry.pathTemplate) {
|
|
98
|
+
// renderedPath = this.#renderer.renderString({ template: renderEntry.pathTemplate, data: renderEntry.data });
|
|
99
|
+
// continue;
|
|
100
|
+
// }
|
|
101
|
+
|
|
102
|
+
// for (const [filename, template] of Object.entries(templatesToRender)) {
|
|
103
|
+
// // console.log({ renderEntry, template });
|
|
104
|
+
|
|
105
|
+
// // @ts-expect-error
|
|
106
|
+
// this.#context.renderedContent.push({
|
|
107
|
+
// savePath:
|
|
108
|
+
// renderedPath ||
|
|
109
|
+
// this.#renderer.renderString({
|
|
110
|
+
// template: renderEntry.baseSavePath ?? (renderEntry?.fullSavePath ? renderEntry?.fullSavePath : join(renderEntry.baseSavePath, template.savePath)),
|
|
111
|
+
// data: renderEntry.data,
|
|
112
|
+
// }),
|
|
113
|
+
// content:
|
|
114
|
+
// renderedContent || this.#renderer.renderString({ template: renderEntry?.contentTemplate ?? template.templateContent, data: renderEntry.data }),
|
|
115
|
+
// });
|
|
116
|
+
// }
|
|
117
|
+
|
|
118
|
+
return this as any;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
async write(write?: (params: { savePath: string; content: string }) => void | Promise<void>): Promise<void> {
|
|
122
|
+
if (typeof write === "function") {
|
|
123
|
+
// @ts-expect-error
|
|
124
|
+
for (const renderConfig of this.#context.renderedContent as { savePath: string; content: string }[]) {
|
|
125
|
+
// console.log({ renderConfig })
|
|
126
|
+
await write(renderConfig);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// console.log({ renderedContent: this.#context.renderedContent})
|
|
133
|
+
// @ts-expect-error
|
|
134
|
+
for (const renderConfig of this.#context.renderedContent as { savePath: string; content: string }[]) {
|
|
135
|
+
await mkdir(dirname(renderConfig.savePath), { recursive: true });
|
|
136
|
+
await writeFile(renderConfig.savePath, new TextEncoder().encode(renderConfig.content), {});
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@codeandmoney/jargal",
|
|
3
|
-
"version": "0.0.0-rc.
|
|
3
|
+
"version": "0.0.0-rc.5",
|
|
4
4
|
"description": "Renderer",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Code & Money Team",
|
|
@@ -12,7 +12,8 @@
|
|
|
12
12
|
}
|
|
13
13
|
],
|
|
14
14
|
"exports": {
|
|
15
|
-
"
|
|
15
|
+
"./old": "./exports.ts",
|
|
16
|
+
".": "./jargal.ts",
|
|
16
17
|
"./types": "./types.ts",
|
|
17
18
|
"./actions": "./actions/exports.ts"
|
|
18
19
|
},
|
package/renderer.ts
CHANGED
|
@@ -31,10 +31,10 @@ export class Renderer {
|
|
|
31
31
|
return this;
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
-
|
|
35
|
-
|
|
34
|
+
private readonly partials: Partials = readonly(this.#partials);
|
|
35
|
+
private readonly helpers: Helpers = readonly(this.#helpers);
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
private get<T extends SetterScope>(scope: T, name: string): GetReturnType<T> {
|
|
38
38
|
const target = get(this.#mapping, scope);
|
|
39
39
|
|
|
40
40
|
if (!target) {
|
|
@@ -44,7 +44,7 @@ export class Renderer {
|
|
|
44
44
|
return get(target, name);
|
|
45
45
|
}
|
|
46
46
|
|
|
47
|
-
|
|
47
|
+
private list<T extends `${SetterScope}s`, O extends boolean = false>(
|
|
48
48
|
scope: T,
|
|
49
49
|
options?: { full?: O },
|
|
50
50
|
): O extends true ? MappingScope[T extends `${infer S}s` ? S : T][] : string[] {
|
package/runner.ts
CHANGED
|
@@ -60,8 +60,6 @@ async function execRecursive(executed: Action | Action[], { context, renderer }:
|
|
|
60
60
|
return await executeAction({ action: executed, context, renderer });
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
-
// assert(!executed);
|
|
64
|
-
|
|
65
63
|
return undefined;
|
|
66
64
|
}
|
|
67
65
|
|
|
@@ -79,7 +77,7 @@ const ConfigSchema = v.object({
|
|
|
79
77
|
});
|
|
80
78
|
|
|
81
79
|
export async function run(runConfig: Config): Promise<void> {
|
|
82
|
-
const config = v.
|
|
80
|
+
const config = v.run(ConfigSchema, runConfig);
|
|
83
81
|
|
|
84
82
|
if (config.generators.length === 1) {
|
|
85
83
|
const generator = config.generators[0];
|
|
@@ -87,14 +85,14 @@ export async function run(runConfig: Config): Promise<void> {
|
|
|
87
85
|
assert(generator);
|
|
88
86
|
|
|
89
87
|
return await runGenerator({
|
|
90
|
-
context: { errors: [], answers: {}
|
|
88
|
+
context: { errors: [], answers: {} },
|
|
91
89
|
renderer: new Renderer(),
|
|
92
90
|
generator,
|
|
93
91
|
});
|
|
94
92
|
}
|
|
95
93
|
|
|
96
94
|
return await runGenerator({
|
|
97
|
-
context: { errors: [], answers: {}
|
|
95
|
+
context: { errors: [], answers: {} },
|
|
98
96
|
renderer: new Renderer(),
|
|
99
97
|
generator: { name: "select", actions: [selectGenerator(config)] },
|
|
100
98
|
});
|
package/types.ts
CHANGED
|
@@ -4,11 +4,10 @@ export interface Config {
|
|
|
4
4
|
generators: GeneratorConfig[];
|
|
5
5
|
}
|
|
6
6
|
|
|
7
|
-
export
|
|
7
|
+
export type Context<Ctx extends object = {}> = Ctx & {
|
|
8
8
|
answers: Record<string, string | boolean | (string | boolean)[]>;
|
|
9
9
|
errors: Error[];
|
|
10
|
-
|
|
11
|
-
}
|
|
10
|
+
};
|
|
12
11
|
|
|
13
12
|
export type DeepReadonly<T> = {
|
|
14
13
|
readonly [Key in keyof T]: T[Key] extends any[] ? T[Key] : T[Key] extends object ? DeepReadonly<T[Key]> : T[Key];
|
|
@@ -21,31 +20,31 @@ export interface GeneratorParams {
|
|
|
21
20
|
hooks?: ActionHooks;
|
|
22
21
|
}
|
|
23
22
|
|
|
24
|
-
export interface ActionParams {
|
|
25
|
-
context: Context
|
|
23
|
+
export interface ActionParams<Ctx extends object = {}> {
|
|
24
|
+
context: Context<Ctx>;
|
|
26
25
|
renderer: Renderer;
|
|
27
26
|
hooks?: ActionHooks;
|
|
28
27
|
}
|
|
29
28
|
|
|
30
|
-
export interface ExecuteActionParams {
|
|
31
|
-
context: Context
|
|
29
|
+
export interface ExecuteActionParams<Ctx extends object = {}> {
|
|
30
|
+
context: Context<Ctx>;
|
|
32
31
|
renderer: Renderer;
|
|
33
32
|
action: Action;
|
|
34
33
|
}
|
|
35
34
|
|
|
35
|
+
export type ContextAction<Ctx extends object = {}> = (params: DeepReadonly<ExecuteActionParams<Ctx>>) => Partial<Context<Ctx>> | Promise<Partial<Context<Ctx>>>;
|
|
36
|
+
|
|
36
37
|
export interface GeneratorConfig {
|
|
37
38
|
name: string;
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// TODO: implement commented out interface
|
|
41
|
-
actions: Action[]; // | Promise<Action[]> | (( params: unknown ) => Action[] | Promise<Action[]>)
|
|
39
|
+
description?: string;
|
|
40
|
+
actions: Action[];
|
|
42
41
|
}
|
|
43
42
|
|
|
44
43
|
export type HelperFn = (str: string) => string;
|
|
45
44
|
|
|
46
45
|
export interface TextHelpers extends Record<string, HelperFn> {}
|
|
47
46
|
|
|
48
|
-
export type Action<
|
|
47
|
+
export type Action<Ctx extends object = {}> = (params: ActionParams<Ctx>) => void | Action | Action[] | Promise<void | Action | Action[]>;
|
|
49
48
|
|
|
50
49
|
export interface ActionHooksFailures {
|
|
51
50
|
path: string;
|
|
@@ -90,5 +89,3 @@ export type GetReturnType<T extends SetterScope> = Mapping[T];
|
|
|
90
89
|
|
|
91
90
|
export interface Partials extends Record<string, string> {}
|
|
92
91
|
export interface Helpers extends Record<string, any> {}
|
|
93
|
-
|
|
94
|
-
export type ContextAction = (context: DeepReadonly<Context>) => Partial<Context> | Promise<Partial<Context>>;
|