hbs-magic 0.1.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.
Files changed (33) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +386 -0
  3. package/bin/cli.ts +48 -0
  4. package/dist/bin/cli.js +25 -0
  5. package/dist/src/cli-messages.js +84 -0
  6. package/dist/src/file-helpers.js +94 -0
  7. package/dist/src/formatting-helpers.js +63 -0
  8. package/dist/src/hbs-process-helpers.js +22 -0
  9. package/dist/src/process-helpers.js +50 -0
  10. package/examples/advanced_csharp-url-helpers/Result.gen.cs +455 -0
  11. package/examples/advanced_csharp-url-helpers/external-input/links.ts +182 -0
  12. package/examples/advanced_csharp-url-helpers/input/hbs-helpers.ts +93 -0
  13. package/examples/advanced_csharp-url-helpers/input/input-data.json +244 -0
  14. package/examples/advanced_csharp-url-helpers/input/preparation-script.ts +175 -0
  15. package/examples/advanced_csharp-url-helpers/input/template.hbs +44 -0
  16. package/examples/advanced_csharp-url-helpers/input/template_partial_node.hbs +32 -0
  17. package/examples/from-api_ts-api-client/Result.gen.ts +189 -0
  18. package/examples/from-api_ts-api-client/input/hbs-helpers.ts +53 -0
  19. package/examples/from-api_ts-api-client/input/template.hbs +30 -0
  20. package/examples/simple_assets-helper/Result.gen.ts +36 -0
  21. package/examples/simple_assets-helper/external-input/dummy_audio_1.mp3 +0 -0
  22. package/examples/simple_assets-helper/external-input/dummy_audio_2.mp3 +0 -0
  23. package/examples/simple_assets-helper/external-input/dummy_audio_3.mp3 +0 -0
  24. package/examples/simple_assets-helper/input/preparation-script.ts +45 -0
  25. package/examples/simple_assets-helper/input/template.hbs +31 -0
  26. package/package.json +52 -0
  27. package/src/cli-messages.ts +88 -0
  28. package/src/file-helpers.ts +108 -0
  29. package/src/formatting-helpers.ts +81 -0
  30. package/src/hbs-process-helpers.ts +36 -0
  31. package/src/process-helpers.ts +78 -0
  32. package/tsconfig.json +14 -0
  33. package/tsconfig.node.json +8 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Ivan Kobtsev
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,386 @@
1
+ # hbs-magic
2
+
3
+ A CLI tool designed to simplify source-code generation with [Handlebars](https://handlebarsjs.com/) templates as much as humanly possible.
4
+
5
+ Point it at a folder with a `.hbs` template, give it some data — and it generates a fully formatted source file. That's it.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ yarn add -D hbs-magic
11
+ ```
12
+ Or
13
+ ```bash
14
+ npm install -D hbs-magic
15
+ ```
16
+
17
+
18
+ ## Quick Start
19
+
20
+ ### 1. Create an input folder with a template and some data
21
+
22
+ ```
23
+ my-gen/
24
+ template.hbs
25
+ input-data.json
26
+ ```
27
+
28
+ **`input-data.json`**
29
+ ```json
30
+ {
31
+ "greeting": "Hello",
32
+ "items": ["Apple", "Banana", "Cherry"]
33
+ }
34
+ ```
35
+
36
+ **`template.hbs`**
37
+ ```handlebars
38
+ // {{greeting}}, World!
39
+
40
+ {{#each items}}
41
+ export const {{this}} = "{{this}}";
42
+ {{/each}}
43
+ ```
44
+
45
+ ### 2. Run hbs-magic
46
+
47
+ ```bash
48
+ hbs-magic --hbs=my-gen --output=result.gen.ts
49
+ ```
50
+
51
+ ### 3. Get a formatted output file ✅
52
+
53
+ **`result.gen.ts`**
54
+ ```typescript
55
+ // Hello, World!
56
+
57
+ export const Apple = "Apple";
58
+ export const Banana = "Banana";
59
+ export const Cherry = "Cherry";
60
+ ```
61
+
62
+ That's all it takes. No config files, no boilerplate — just a template and data.
63
+
64
+ ---
65
+
66
+ ## How It Works
67
+
68
+ Everything lives inside a single **input folder** (the `--hbs` folder). Depending on your needs, it can contain:
69
+
70
+ | File | Purpose |
71
+ |------------------------------|--------------------------------------------------------------|
72
+ | `template.hbs` | The Handlebars template to render |
73
+ | `input-data.json` | Static JSON data for the template |
74
+ | `preparation-script.ts` | A script that programmatically builds the data object |
75
+ | `hbs-helpers.ts` | Custom Handlebars helpers |
76
+ | `template_partial_*.hbs` | Handlebars partials (named by the part after the second `_`) |
77
+
78
+ > If multiple data sources are provided, priority is: `--input` flag → `preparation-script` → `input-data.json`.
79
+
80
+ ---
81
+
82
+ ## CLI Usage
83
+
84
+ ```
85
+ hbs-magic --hbs=<folder> --output=<file> [--input=<json>] [--disable-formatting]
86
+ ```
87
+
88
+ | Flag | Description |
89
+ |---|---|
90
+ | `--hbs` | **(required)** Path to the folder containing your template, data, helpers, etc. |
91
+ | `--output` | **(required)** Path for the generated output file |
92
+ | `--input` | Optional external JSON data source — a local file path **or a URL** |
93
+ | `--disable-formatting` | Skip auto-formatting the output (Prettier for JS/TS, CSharpier for C#) |
94
+
95
+ ---
96
+
97
+ ## Data Input — Three Ways
98
+
99
+ ### Option A: Static JSON — `input-data.json`
100
+
101
+ The simplest approach. Just drop a JSON file into the input folder:
102
+
103
+ ```
104
+ my-gen/
105
+ template.hbs
106
+ input-data.json ← hbs-magic picks this up automatically
107
+ ```
108
+
109
+ ### Option B: Preparation Script — `preparation-script.ts`
110
+
111
+ Need to compute data dynamically? Export a default function that returns the data object:
112
+
113
+ ```
114
+ my-gen/
115
+ template.hbs
116
+ preparation-script.ts
117
+ ```
118
+
119
+ ```typescript
120
+ // preparation-script.ts
121
+ export default async function () {
122
+ // Read files, call APIs, parse ASTs — whatever you need
123
+ return {
124
+ items: ["generated", "at", "build-time"],
125
+ };
126
+ }
127
+ ```
128
+
129
+ The function can be `async`. hbs-magic will bundle and execute it for you (TypeScript supported out of the box).
130
+
131
+ ### Option C: External JSON via `--input` flag
132
+
133
+ Pass a local file or a remote URL:
134
+
135
+ ```bash
136
+ # From a local file
137
+ hbs-magic --hbs=my-gen --output=result.ts --input=./data.json
138
+
139
+ # From an API endpoint
140
+ hbs-magic --hbs=my-gen --output=result.ts --input=https://api.example.com/data.json
141
+ ```
142
+
143
+ ---
144
+
145
+ ## Custom Handlebars Helpers — `hbs-helpers.ts`
146
+
147
+ Export a default object whose keys are helper names and values are helper functions:
148
+
149
+ ```
150
+ my-gen/
151
+ template.hbs
152
+ input-data.json
153
+ hbs-helpers.ts ← automatically registered
154
+ ```
155
+
156
+ ```typescript
157
+ // hbs-helpers.ts
158
+ function shout(text: string) {
159
+ return text.toUpperCase() + "!!!";
160
+ }
161
+
162
+ function isEven(index: number) {
163
+ return index % 2 === 0;
164
+ }
165
+
166
+ export default { shout, isEven };
167
+ ```
168
+
169
+ Then use them in your template:
170
+
171
+ ```handlebars
172
+ {{#each items}}
173
+ {{shout this}}
174
+ {{/each}}
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Handlebars Partials
180
+
181
+ Any `.hbs` file in the input folder (other than `template.hbs`) is registered as a partial. The partial name is taken from the **third segment** of the filename, split by `_`:
182
+
183
+ ```
184
+ template_partial_node.hbs → partial name: "node"
185
+ template_partial_row.hbs → partial name: "row"
186
+ ```
187
+
188
+ Use them in your template with `{{> node}}` or `{{> row}}`.
189
+
190
+ Partials are great for recursive structures — like rendering a nested tree of routes (see the [Advanced Example](#3-advanced--c-url-helpers-with-partials-preparation-script-and-helpers) below).
191
+
192
+ ---
193
+
194
+ ## Auto-Formatting
195
+
196
+ hbs-magic automatically formats the generated output file based on its extension:
197
+
198
+ | Extension | Formatter |
199
+ |---|---|
200
+ | `.ts`, `.tsx`, `.js`, `.jsx` | [Prettier](https://prettier.io/) |
201
+ | `.cs` | [CSharpier](https://csharpier.com/) |
202
+
203
+ You can disable it with `--disable-formatting`.
204
+
205
+ ---
206
+
207
+ ## Examples
208
+
209
+ ### 1. Simple — Assets Helper (Preparation Script)
210
+
211
+ > Scans a folder of audio files and generates a typed TypeScript module with imports, an enum, and a record.
212
+
213
+ **Folder structure:**
214
+ ```
215
+ examples/simple_assets-helper/
216
+ external-input/
217
+ dummy_audio_1.mp3
218
+ dummy_audio_2.mp3
219
+ dummy_audio_3.mp3
220
+ input/
221
+ preparation-script.ts
222
+ template.hbs
223
+ ```
224
+
225
+ **Run:**
226
+ ```bash
227
+ hbs-magic --hbs=examples/simple_assets-helper/input --output=examples/simple_assets-helper/Result.gen.ts
228
+ ```
229
+
230
+ **Generated `Result.gen.ts`:**
231
+ ```typescript
232
+ import dummy_audio_1SFX from "examples/simple_assets-helper/external-input/dummy_audio_1.mp3";
233
+ import dummy_audio_2SFX from "examples/simple_assets-helper/external-input/dummy_audio_2.mp3";
234
+ import dummy_audio_3SFX from "examples/simple_assets-helper/external-input/dummy_audio_3.mp3";
235
+
236
+ export enum SoundEffect {
237
+ dummy_audio_1 = "dummy_audio_1",
238
+ dummy_audio_2 = "dummy_audio_2",
239
+ dummy_audio_3 = "dummy_audio_3",
240
+ }
241
+
242
+ export const SoundEffects: Record<SoundEffect, SoundSource> = {
243
+ [SoundEffect.dummy_audio_1]: {
244
+ src: dummy_audio_1SFX,
245
+ name: SoundEffect.dummy_audio_1,
246
+ },
247
+ [SoundEffect.dummy_audio_2]: {
248
+ src: dummy_audio_2SFX,
249
+ name: SoundEffect.dummy_audio_2,
250
+ },
251
+ [SoundEffect.dummy_audio_3]: {
252
+ src: dummy_audio_3SFX,
253
+ name: SoundEffect.dummy_audio_3,
254
+ },
255
+ };
256
+ ```
257
+
258
+ ---
259
+
260
+ ### 2. From API — TypeScript API Client (Helpers + External JSON)
261
+
262
+ > Fetches an OpenAPI spec from a URL and generates TypeScript functions for every endpoint.
263
+
264
+ **Folder structure:**
265
+ ```
266
+ examples/from-api_ts-api-client/
267
+ input/
268
+ template.hbs
269
+ hbs-helpers.ts
270
+ ```
271
+
272
+ **Run** (note the `--input` pointing to a live API):
273
+ ```bash
274
+ hbs-magic \
275
+ --input=https://petstore3.swagger.io/api/v3/openapi.json \
276
+ --hbs=examples/from-api_ts-api-client/input \
277
+ --output=examples/from-api_ts-api-client/Result.gen.ts
278
+ ```
279
+
280
+ **Generated `Result.gen.ts`** (excerpt):
281
+ ```typescript
282
+ export async function findPetsByStatus(status: string) {
283
+ console.log("Calling get /pet/findByStatus");
284
+ }
285
+
286
+ export async function getPetById(petId: number) {
287
+ console.log("Calling get /pet/{petId}");
288
+ }
289
+
290
+ export async function loginUser(username: string, password: string) {
291
+ console.log("Calling get /user/login");
292
+ }
293
+ // ... and every other endpoint from the Swagger Petstore
294
+ ```
295
+
296
+ ---
297
+
298
+ ### 3. Advanced — C# URL Helpers with Partials, Preparation Script, and Helpers
299
+
300
+ > Parses a TypeScript route definition file (using `ts-morph`), extracts route/param info, and generates a full C# helper class with nested static classes, query parameter models, and link-builder methods — using **partials** for recursive rendering.
301
+
302
+ **Folder structure:**
303
+ ```
304
+ examples/advanced_csharp-url-helpers/
305
+ external-input/
306
+ links.ts ← source routes file (react-router-url-params)
307
+ input/
308
+ preparation-script.ts ← parses links.ts via ts-morph AST
309
+ hbs-helpers.ts ← TS→C# type converters
310
+ template.hbs ← main template
311
+ template_partial_node.hbs ← recursive partial for nested route groups
312
+ input-data.json ← generated intermediate JSON (by prep script)
313
+ ```
314
+
315
+ **Run:**
316
+ ```bash
317
+ hbs-magic \
318
+ --hbs=examples/advanced_csharp-url-helpers/input \
319
+ --output=examples/advanced_csharp-url-helpers/Result.gen.cs
320
+ ```
321
+
322
+ **Generated `Result.gen.cs`** (excerpt):
323
+ ```csharp
324
+ public static class Routes
325
+ {
326
+ public static class Unauthorized
327
+ {
328
+ public static class Login
329
+ {
330
+ public static string Link(string siteUrl, LoginQueryParams queryParams) =>
331
+ siteUrl + "/login" + "?" + queryParams.GetQueryString();
332
+ }
333
+
334
+ public static class ConfirmEmail
335
+ {
336
+ public static string Link(string siteUrl, string userId, string token) =>
337
+ siteUrl + "/confirm-email/:userId/:token"
338
+ .Replace(":userId", userId.ToString())
339
+ .Replace(":token", token.ToString());
340
+ }
341
+ }
342
+
343
+ public static class Authorized
344
+ {
345
+ // ... deeply nested route groups with full C# link builders
346
+ }
347
+ }
348
+
349
+ public class LoginQueryParams : IRouteQueryParams
350
+ {
351
+ public string? Redirect { get; init; }
352
+
353
+ public string GetQueryString()
354
+ {
355
+ var queryParams = new List<string>();
356
+ if (!string.IsNullOrEmpty(Redirect))
357
+ queryParams.Add($"redirect={Redirect}");
358
+ return string.Join("&", queryParams);
359
+ }
360
+ }
361
+ ```
362
+
363
+ ---
364
+
365
+ ## Adding to `package.json` scripts
366
+
367
+ A convenient pattern is to add generation commands as npm scripts:
368
+
369
+ ```json
370
+ {
371
+ "scripts": {
372
+ "gen:assets": "hbs-magic --hbs=src/gen/assets/input --output=src/generated/assets.gen.ts",
373
+ "gen:api": "hbs-magic --input=https://api.example.com/openapi.json --hbs=src/gen/api/input --output=src/generated/api-client.gen.ts",
374
+ "gen:all": "npm run gen:assets && npm run gen:api"
375
+ }
376
+ }
377
+ ```
378
+
379
+ Then simply run `npm run gen:all` to regenerate everything.
380
+
381
+ ---
382
+
383
+ ## License
384
+
385
+ [MIT](LICENSE) © Ivan Kobtsev
386
+
package/bin/cli.ts ADDED
@@ -0,0 +1,48 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ getHbsHelpersAndTemplatePaths,
4
+ getInputDataPath,
5
+ runPreparationScript,
6
+ } from "../src/file-helpers.js";
7
+ import { formatSourceFile } from "../src/formatting-helpers.js";
8
+ import {
9
+ compileHbsTemplateAndWriteToFile,
10
+ registerHbsHelpersFromFile,
11
+ registerHbsPartials,
12
+ } from "../src/hbs-process-helpers.js";
13
+ import {
14
+ extractArgument,
15
+ extractArguments,
16
+ extractFlag,
17
+ getInputObject,
18
+ } from "../src/process-helpers.js";
19
+
20
+ const args = extractArguments(process, ["hbs", "output"]);
21
+ const hbsFolder = args.hbs as string;
22
+ const outputFile = args.output as string;
23
+ const formatOutput = !extractFlag(process, "disable-formatting");
24
+ const externalJson = extractArgument(process, "input");
25
+
26
+ async function main() {
27
+ const { preparationScriptPath, hbsHelpersPath, hbsPartials, templatePath } =
28
+ getHbsHelpersAndTemplatePaths(hbsFolder);
29
+
30
+ const inputObject = await getInputObject(
31
+ externalJson,
32
+ await runPreparationScript(preparationScriptPath),
33
+ getInputDataPath(hbsFolder),
34
+ );
35
+
36
+ if (hbsHelpersPath) await registerHbsHelpersFromFile(hbsHelpersPath);
37
+
38
+ if (hbsPartials.length > 0) await registerHbsPartials(hbsPartials);
39
+
40
+ await compileHbsTemplateAndWriteToFile(templatePath, inputObject, outputFile);
41
+
42
+ if (formatOutput) await formatSourceFile(outputFile);
43
+ }
44
+
45
+ main().catch((err) => {
46
+ console.error(err);
47
+ process.exit(1);
48
+ });
@@ -0,0 +1,25 @@
1
+ #!/usr/bin/env node
2
+ import { getHbsHelpersAndTemplatePaths, getInputDataPath, runPreparationScript, } from "../src/file-helpers.js";
3
+ import { formatSourceFile } from "../src/formatting-helpers.js";
4
+ import { compileHbsTemplateAndWriteToFile, registerHbsHelpersFromFile, registerHbsPartials, } from "../src/hbs-process-helpers.js";
5
+ import { extractArgument, extractArguments, extractFlag, getInputObject, } from "../src/process-helpers.js";
6
+ const args = extractArguments(process, ["hbs", "output"]);
7
+ const hbsFolder = args.hbs;
8
+ const outputFile = args.output;
9
+ const formatOutput = !extractFlag(process, "disable-formatting");
10
+ const externalJson = extractArgument(process, "input");
11
+ async function main() {
12
+ const { preparationScriptPath, hbsHelpersPath, hbsPartials, templatePath } = getHbsHelpersAndTemplatePaths(hbsFolder);
13
+ const inputObject = await getInputObject(externalJson, await runPreparationScript(preparationScriptPath), getInputDataPath(hbsFolder));
14
+ if (hbsHelpersPath)
15
+ await registerHbsHelpersFromFile(hbsHelpersPath);
16
+ if (hbsPartials.length > 0)
17
+ await registerHbsPartials(hbsPartials);
18
+ await compileHbsTemplateAndWriteToFile(templatePath, inputObject, outputFile);
19
+ if (formatOutput)
20
+ await formatSourceFile(outputFile);
21
+ }
22
+ main().catch((err) => {
23
+ console.error(err);
24
+ process.exit(1);
25
+ });
@@ -0,0 +1,84 @@
1
+ export const inputDataNotFound = `No input data found.
2
+
3
+ Please provide data using one of the following options:
4
+
5
+ 1. Use the "--input" flag with a path or URL to a JSON file
6
+ Example: hbs-magic --input=./data.json
7
+
8
+ 2. Add a preparation script:
9
+ - File name: preparation-script.ts or preparation-script.js
10
+ - Must export a default function that returns the data object
11
+ - Place it inside your .hbs template folder
12
+
13
+ 3. Add a default JSON file:
14
+ - File name: input-data.json
15
+ - Place it inside your .hbs template folder
16
+
17
+ Need help? Run: hbs-magic --help`;
18
+ export const multipleSourcesDetected = `Warning: Multiple input sources detected.
19
+
20
+ hbs-magic will use only one source based on the following priority:
21
+
22
+ 1. --input flag
23
+ 2. preparation-script.ts/js
24
+ 3. input-data.json
25
+
26
+ The highest-priority source will be used. All others will be ignored.
27
+
28
+ Tip: Remove unused inputs to make your setup clearer.`;
29
+ export const positionalArgumentsNotAllowed = `No positional arguments allowed. Use '--key=value' format.`;
30
+ export const hbsMagicCliUsage = `Usage: [--input=<json>] --hbs=<folder> --output=<file> [--disable-formatting]
31
+ --input: Optional JSON input file path. If not provided, the script will look for "input-data.json" in the specified hbs folder.
32
+ --hbs: Required folder containing the Handlebars template, optional helpers, partials, and preparation script.
33
+ --output: Required output file path where the generated source code will be written.
34
+ --disable-formatting: Optional flag to disable auto-formatting of the output file after generation.`;
35
+ export const hbsMagicHelp = `hbs-magic — source-code generation with Handlebars templates
36
+
37
+ Usage:
38
+ hbs-magic --hbs=<folder> --output=<file> [--input=<json>] [--disable-formatting]
39
+
40
+ Required flags:
41
+ --hbs=<folder> Folder containing your Handlebars template and optional
42
+ helpers, partials, and preparation script.
43
+ --output=<file> Path where the generated file will be written.
44
+
45
+ Optional flags:
46
+ --input=<json> External JSON data source — a local file path or a URL.
47
+ --disable-formatting Skip auto-formatting of the generated output.
48
+ --help Show this help message.
49
+
50
+ Input folder structure:
51
+ The --hbs folder can contain any combination of these files:
52
+
53
+ template.hbs (required) The Handlebars template to render.
54
+ input-data.json (optional) Static JSON data for the template.
55
+ preparation-script.ts (optional) Script exporting a default function
56
+ that returns the data object.
57
+ hbs-helpers.ts (optional) Custom Handlebars helpers. Must export
58
+ a default object: { helperName: fn }.
59
+ template_partial_*.hbs (optional) Partials, named by the part after the
60
+ second "_" (e.g. template_partial_row.hbs
61
+ registers a partial called "row").
62
+
63
+ Data source priority:
64
+ If multiple sources are provided, only one is used:
65
+ 1. --input flag (highest)
66
+ 2. preparation-script
67
+ 3. input-data.json (lowest)
68
+
69
+ Auto-formatting:
70
+ Output files are automatically formatted based on extension:
71
+ .ts .tsx .js .jsx → Prettier
72
+ .cs → CSharpier
73
+
74
+ Examples:
75
+ # Simple: static JSON + template
76
+ hbs-magic --hbs=gen/input --output=src/result.gen.ts
77
+
78
+ # From a remote API
79
+ hbs-magic --input=https://api.example.com/openapi.json --hbs=gen/input --output=src/client.gen.ts
80
+
81
+ # With formatting disabled
82
+ hbs-magic --hbs=gen/input --output=src/result.gen.ts --disable-formatting
83
+
84
+ Documentation: https://github.com/IvanKobtsev/hbs-magic#readme`;
@@ -0,0 +1,94 @@
1
+ import fs from "fs";
2
+ import fetch from "node-fetch";
3
+ import https from "https";
4
+ import path from "path";
5
+ import { pathToFileURL } from "url";
6
+ import { build } from "esbuild";
7
+ const agent = new https.Agent({ rejectUnauthorized: false });
8
+ export async function getJson(source) {
9
+ if (source.startsWith("http://") || source.startsWith("https://")) {
10
+ let response;
11
+ try {
12
+ response = await fetch(source, { agent });
13
+ }
14
+ catch (err) {
15
+ throw new Error(`Failed to fetch JSON from URL: ${err}`);
16
+ }
17
+ if (!response.ok)
18
+ throw new Error(`HTTP error: ${response.status}`);
19
+ return await response.json();
20
+ }
21
+ else {
22
+ return JSON.parse(fs.readFileSync(source, "utf8"));
23
+ }
24
+ }
25
+ export async function getDefaultExport(source) {
26
+ if (source.endsWith(".ts")) {
27
+ const tempFile = source.replace(/\.ts$/, ".temp.js");
28
+ await build({
29
+ entryPoints: [source],
30
+ outfile: tempFile,
31
+ bundle: true,
32
+ platform: "node",
33
+ format: "esm",
34
+ packages: "external",
35
+ banner: {
36
+ js: 'import { createRequire as __createRequire } from "module"; const require = __createRequire(import.meta.url);',
37
+ },
38
+ });
39
+ const defaultExport = (await import(pathToFileURL(tempFile).href)).default;
40
+ fs.unlinkSync(tempFile);
41
+ return defaultExport;
42
+ }
43
+ else {
44
+ return (await import(pathToFileURL(source).href)).default;
45
+ }
46
+ }
47
+ export async function runPreparationScript(fullPath) {
48
+ if (!fullPath)
49
+ return undefined;
50
+ const preparationScript = await getDefaultExport(fullPath);
51
+ if (typeof preparationScript === "function")
52
+ return await preparationScript();
53
+ else
54
+ throw new Error(`Failed to run preparation script: ${fullPath}. Default export is not a function.`);
55
+ }
56
+ export function getAllHbsPartialsInFolder(folder) {
57
+ const partials = [];
58
+ const files = fs.readdirSync(folder);
59
+ for (const file of files) {
60
+ if (file.endsWith(".hbs")) {
61
+ const partialFullName = path.basename(file, ".hbs");
62
+ if (partialFullName === "template")
63
+ continue; // skip main template file
64
+ const partialName = partialFullName.split("_")[2];
65
+ const partialPath = path.join(folder, file);
66
+ partials.push({
67
+ name: partialName,
68
+ content: fs.readFileSync(partialPath, "utf8"),
69
+ });
70
+ }
71
+ }
72
+ return partials;
73
+ }
74
+ export function getInputDataPath(hbsFolder) {
75
+ const inputPath = path.join(hbsFolder, "input-data.json");
76
+ return fs.existsSync(inputPath) ? inputPath : undefined;
77
+ }
78
+ export function getHbsHelpersAndTemplatePaths(hbsFolder) {
79
+ const preparationScriptPath = path.join(hbsFolder, "preparation-script.ts");
80
+ const helpersPath = path.join(hbsFolder, "hbs-helpers.ts");
81
+ const templatePath = path.join(hbsFolder, "template.hbs");
82
+ const partials = getAllHbsPartialsInFolder(hbsFolder);
83
+ if (!fs.existsSync(templatePath)) {
84
+ throw new Error(`Template file not found: ${templatePath}`);
85
+ }
86
+ return {
87
+ preparationScriptPath: fs.existsSync(preparationScriptPath)
88
+ ? preparationScriptPath
89
+ : undefined,
90
+ hbsHelpersPath: fs.existsSync(helpersPath) ? helpersPath : undefined,
91
+ templatePath: templatePath,
92
+ hbsPartials: partials,
93
+ };
94
+ }