@podosoft/podokit-template-engine 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.
@@ -0,0 +1,27 @@
1
+ /** Variables available for token substitution in template files. */
2
+ export type TemplateVars = Record<string, string>;
3
+ /** Minimal JSON object shape used for package.json merging. */
4
+ export type JsonObject = Record<string, unknown>;
5
+ /**
6
+ * Replace `{{key}}` tokens in `content` with the matching value from `vars`.
7
+ * Unknown tokens are left untouched so unrelated braces are preserved.
8
+ */
9
+ export declare function renderTokens(content: string, vars: TemplateVars): string;
10
+ /**
11
+ * Map a template file name to its output name.
12
+ * A leading `dot-` becomes `.` so files like `dot-gitignore` are shipped
13
+ * inside npm packages (which strip real `.gitignore`) and restored on copy.
14
+ */
15
+ export declare function resolveOutputName(name: string): string;
16
+ /**
17
+ * Recursively copy a template directory to `destDir`, rendering tokens in
18
+ * text files and applying the `dot-` name convention. Directories are created
19
+ * as needed. Binary files are copied verbatim.
20
+ */
21
+ export declare function copyTemplate(srcDir: string, destDir: string, vars: TemplateVars): void;
22
+ /**
23
+ * Deep-merge `overlay` onto `base`. Objects merge recursively, arrays are
24
+ * concatenated and de-duplicated, and scalar overlay values win. Neither input
25
+ * is mutated. Used to combine a base package.json with module fragments.
26
+ */
27
+ export declare function mergePackageJson(base: JsonObject, overlay: JsonObject): JsonObject;
package/dist/index.js ADDED
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.renderTokens = renderTokens;
4
+ exports.resolveOutputName = resolveOutputName;
5
+ exports.copyTemplate = copyTemplate;
6
+ exports.mergePackageJson = mergePackageJson;
7
+ const node_fs_1 = require("node:fs");
8
+ const node_path_1 = require("node:path");
9
+ /**
10
+ * Replace `{{key}}` tokens in `content` with the matching value from `vars`.
11
+ * Unknown tokens are left untouched so unrelated braces are preserved.
12
+ */
13
+ function renderTokens(content, vars) {
14
+ return content.replace(/\{\{\s*([\w.-]+)\s*\}\}/g, (match, key) => {
15
+ const value = vars[key];
16
+ return value === undefined ? match : value;
17
+ });
18
+ }
19
+ /**
20
+ * Map a template file name to its output name.
21
+ * A leading `dot-` becomes `.` so files like `dot-gitignore` are shipped
22
+ * inside npm packages (which strip real `.gitignore`) and restored on copy.
23
+ */
24
+ function resolveOutputName(name) {
25
+ return name.startsWith("dot-") ? `.${name.slice("dot-".length)}` : name;
26
+ }
27
+ const TEXT_FILE = /\.(json|md|ts|js|mjs|cjs|css|html|yml|yaml|txt|env|example|gitignore|svelte)$/i;
28
+ function isTextFile(name) {
29
+ return name.startsWith("dot-") || TEXT_FILE.test(name);
30
+ }
31
+ /**
32
+ * Recursively copy a template directory to `destDir`, rendering tokens in
33
+ * text files and applying the `dot-` name convention. Directories are created
34
+ * as needed. Binary files are copied verbatim.
35
+ */
36
+ function copyTemplate(srcDir, destDir, vars) {
37
+ (0, node_fs_1.mkdirSync)(destDir, { recursive: true });
38
+ for (const entry of (0, node_fs_1.readdirSync)(srcDir)) {
39
+ const srcPath = (0, node_path_1.join)(srcDir, entry);
40
+ const outName = resolveOutputName(entry);
41
+ const destPath = (0, node_path_1.join)(destDir, outName);
42
+ if ((0, node_fs_1.statSync)(srcPath).isDirectory()) {
43
+ copyTemplate(srcPath, destPath, vars);
44
+ continue;
45
+ }
46
+ if (isTextFile(entry)) {
47
+ const rendered = renderTokens((0, node_fs_1.readFileSync)(srcPath, "utf8"), vars);
48
+ (0, node_fs_1.writeFileSync)(destPath, rendered);
49
+ }
50
+ else {
51
+ (0, node_fs_1.writeFileSync)(destPath, (0, node_fs_1.readFileSync)(srcPath));
52
+ }
53
+ }
54
+ }
55
+ function isPlainObject(value) {
56
+ return typeof value === "object" && value !== null && !Array.isArray(value);
57
+ }
58
+ /**
59
+ * Deep-merge `overlay` onto `base`. Objects merge recursively, arrays are
60
+ * concatenated and de-duplicated, and scalar overlay values win. Neither input
61
+ * is mutated. Used to combine a base package.json with module fragments.
62
+ */
63
+ function mergePackageJson(base, overlay) {
64
+ const result = { ...base };
65
+ for (const [key, overlayValue] of Object.entries(overlay)) {
66
+ const baseValue = result[key];
67
+ if (isPlainObject(baseValue) && isPlainObject(overlayValue)) {
68
+ result[key] = mergePackageJson(baseValue, overlayValue);
69
+ }
70
+ else if (Array.isArray(baseValue) && Array.isArray(overlayValue)) {
71
+ result[key] = [...new Set([...baseValue, ...overlayValue])];
72
+ }
73
+ else {
74
+ result[key] = overlayValue;
75
+ }
76
+ }
77
+ return result;
78
+ }
package/package.json ADDED
@@ -0,0 +1,26 @@
1
+ {
2
+ "name": "@podosoft/podokit-template-engine",
3
+ "version": "0.1.0",
4
+ "description": "Template rendering, copying, and package.json merge utilities for PodoKit.",
5
+ "license": "Apache-2.0",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/podosoft-dev/podokit.git",
9
+ "directory": "packages/template-engine"
10
+ },
11
+ "main": "dist/index.js",
12
+ "types": "dist/index.d.ts",
13
+ "files": ["dist"],
14
+ "engines": {
15
+ "node": ">=20"
16
+ },
17
+ "publishConfig": {
18
+ "access": "public",
19
+ "provenance": true
20
+ },
21
+ "scripts": {
22
+ "build": "tsc -p tsconfig.json",
23
+ "lint": "tsc -p tsconfig.json --noEmit",
24
+ "test": "vitest run"
25
+ }
26
+ }