md-template-vars 0.1.2 → 0.2.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.
- package/README.md +46 -5
- package/dist/domain/services/template-renderer.js +1 -1
- package/dist/domain/value-objects/variables.d.ts +7 -1
- package/dist/domain/value-objects/variables.js +16 -2
- package/dist/infrastructure/repositories/variables-repository.js +2 -2
- package/dist/presentation/cli/commands/main.d.ts +5 -0
- package/dist/presentation/cli/commands/main.js +63 -23
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -29,11 +29,12 @@ md-template-vars <input> <output> [options]
|
|
|
29
29
|
|
|
30
30
|
### Options
|
|
31
31
|
|
|
32
|
-
| Option | Default | Description
|
|
33
|
-
| ----------- | ---------------- |
|
|
34
|
-
| `--vars` | `variables.yaml` | Path to the variables YAML file
|
|
35
|
-
| `--include` | - | Glob pattern to include specific files
|
|
36
|
-
| `--exclude` | - | Glob pattern to exclude specific files
|
|
32
|
+
| Option | Default | Description |
|
|
33
|
+
| ----------- | ---------------- | ------------------------------------------------ |
|
|
34
|
+
| `--vars` | `variables.yaml` | Path to the variables YAML file |
|
|
35
|
+
| `--include` | - | Glob pattern to include specific files |
|
|
36
|
+
| `--exclude` | - | Glob pattern to exclude specific files |
|
|
37
|
+
| `--watch` | `false` | Watch for file changes and rebuild automatically |
|
|
37
38
|
|
|
38
39
|
## Examples
|
|
39
40
|
|
|
@@ -59,6 +60,18 @@ md-template-vars ./templates ./output --include "api-*.md"
|
|
|
59
60
|
md-template-vars ./templates ./output --exclude "draft-*.md"
|
|
60
61
|
```
|
|
61
62
|
|
|
63
|
+
### Watch mode
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
md-template-vars ./templates ./output --watch
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
This will watch for changes in:
|
|
70
|
+
- Template files in the input directory
|
|
71
|
+
- The variables YAML file
|
|
72
|
+
|
|
73
|
+
When changes are detected, templates are automatically rebuilt.
|
|
74
|
+
|
|
62
75
|
## Template Syntax
|
|
63
76
|
|
|
64
77
|
Use `{{variableName}}` syntax in your Markdown files:
|
|
@@ -83,6 +96,34 @@ project: My Project
|
|
|
83
96
|
Welcome to My Project!
|
|
84
97
|
```
|
|
85
98
|
|
|
99
|
+
### Nested Variables
|
|
100
|
+
|
|
101
|
+
You can use nested objects in your variables file and access them with dot notation:
|
|
102
|
+
|
|
103
|
+
**Template:**
|
|
104
|
+
```markdown
|
|
105
|
+
# {{app.name}}
|
|
106
|
+
|
|
107
|
+
Database: {{database.host}}:{{database.port}}
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
**Variables (variables.yaml):**
|
|
111
|
+
```yaml
|
|
112
|
+
app:
|
|
113
|
+
name: My App
|
|
114
|
+
|
|
115
|
+
database:
|
|
116
|
+
host: localhost
|
|
117
|
+
port: 5432
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
**Output:**
|
|
121
|
+
```markdown
|
|
122
|
+
# My App
|
|
123
|
+
|
|
124
|
+
Database: localhost:5432
|
|
125
|
+
```
|
|
126
|
+
|
|
86
127
|
## Error Handling
|
|
87
128
|
|
|
88
129
|
| Case | Behavior |
|
|
@@ -1,3 +1,9 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
|
|
2
|
+
declare const PrimitiveValueSchema: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
|
|
3
|
+
type NestedValue = z.infer<typeof PrimitiveValueSchema> | {
|
|
4
|
+
[key: string]: NestedValue;
|
|
5
|
+
};
|
|
6
|
+
export declare const VariablesSchema: z.ZodRecord<z.ZodString, z.ZodType<NestedValue, z.ZodTypeDef, NestedValue>>;
|
|
3
7
|
export type Variables = Record<string, string>;
|
|
8
|
+
export declare function flattenVariables(obj: Record<string, NestedValue>, prefix?: string): Variables;
|
|
9
|
+
export {};
|
|
@@ -1,3 +1,17 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
const
|
|
3
|
-
|
|
2
|
+
const PrimitiveValueSchema = z.union([z.string(), z.number(), z.boolean()]);
|
|
3
|
+
const NestedValueSchema = z.lazy(() => z.union([PrimitiveValueSchema, z.record(z.string(), NestedValueSchema)]));
|
|
4
|
+
export const VariablesSchema = z.record(z.string(), NestedValueSchema);
|
|
5
|
+
export function flattenVariables(obj, prefix = "") {
|
|
6
|
+
const result = {};
|
|
7
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
8
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
9
|
+
if (typeof value === "object" && value !== null) {
|
|
10
|
+
Object.assign(result, flattenVariables(value, fullKey));
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
result[fullKey] = String(value);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return result;
|
|
17
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { readFileSync, existsSync } from "node:fs";
|
|
2
2
|
import { parse } from "yaml";
|
|
3
|
-
import { VariablesSchema } from "../../domain/value-objects/variables.js";
|
|
3
|
+
import { VariablesSchema, flattenVariables } from "../../domain/value-objects/variables.js";
|
|
4
4
|
import { VariablesFileNotFoundError, InvalidVariablesError } from "../../shared/errors.js";
|
|
5
5
|
export function loadVariables(filePath) {
|
|
6
6
|
if (!existsSync(filePath)) {
|
|
@@ -12,5 +12,5 @@ export function loadVariables(filePath) {
|
|
|
12
12
|
if (!result.success) {
|
|
13
13
|
throw new InvalidVariablesError(result.error.message);
|
|
14
14
|
}
|
|
15
|
-
return result.data;
|
|
15
|
+
return flattenVariables(result.data);
|
|
16
16
|
}
|
|
@@ -1,6 +1,49 @@
|
|
|
1
1
|
import { defineCommand } from "citty";
|
|
2
|
+
import { watch } from "node:fs";
|
|
3
|
+
import { resolve } from "node:path";
|
|
2
4
|
import { processTemplates } from "../../../application/use-cases/process-templates.js";
|
|
3
|
-
import { VariablesFileNotFoundError, SameInputOutputError, InvalidVariablesError
|
|
5
|
+
import { VariablesFileNotFoundError, SameInputOutputError, InvalidVariablesError } from "../../../shared/errors.js";
|
|
6
|
+
async function runProcess(options) {
|
|
7
|
+
try {
|
|
8
|
+
const result = await processTemplates(options);
|
|
9
|
+
for (const warning of result.warnings) {
|
|
10
|
+
console.warn(warning);
|
|
11
|
+
}
|
|
12
|
+
console.log(`Processed ${result.processedFiles.length} file(s)`);
|
|
13
|
+
for (const file of result.processedFiles) {
|
|
14
|
+
console.log(` - ${file}`);
|
|
15
|
+
}
|
|
16
|
+
return true;
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
if (error instanceof VariablesFileNotFoundError ||
|
|
20
|
+
error instanceof SameInputOutputError ||
|
|
21
|
+
error instanceof InvalidVariablesError) {
|
|
22
|
+
console.error(`Error: ${error.message}`);
|
|
23
|
+
return false;
|
|
24
|
+
}
|
|
25
|
+
throw error;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function startWatch(options) {
|
|
29
|
+
const inputPath = resolve(options.input);
|
|
30
|
+
const varsPath = resolve(options.vars);
|
|
31
|
+
let debounceTimer = null;
|
|
32
|
+
const handleChange = () => {
|
|
33
|
+
if (debounceTimer) {
|
|
34
|
+
clearTimeout(debounceTimer);
|
|
35
|
+
}
|
|
36
|
+
debounceTimer = setTimeout(async () => {
|
|
37
|
+
console.log("\n--- Change detected, rebuilding... ---\n");
|
|
38
|
+
await runProcess(options);
|
|
39
|
+
}, 100);
|
|
40
|
+
};
|
|
41
|
+
console.log(`\nWatching for changes...`);
|
|
42
|
+
console.log(` - Templates: ${inputPath}`);
|
|
43
|
+
console.log(` - Variables: ${varsPath}\n`);
|
|
44
|
+
watch(inputPath, { recursive: true }, handleChange);
|
|
45
|
+
watch(varsPath, handleChange);
|
|
46
|
+
}
|
|
4
47
|
export const mainCommand = defineCommand({
|
|
5
48
|
meta: {
|
|
6
49
|
name: "md-template-vars",
|
|
@@ -30,32 +73,29 @@ export const mainCommand = defineCommand({
|
|
|
30
73
|
type: "string",
|
|
31
74
|
description: "Glob pattern to exclude files",
|
|
32
75
|
},
|
|
76
|
+
watch: {
|
|
77
|
+
type: "boolean",
|
|
78
|
+
description: "Watch for file changes and rebuild automatically",
|
|
79
|
+
default: false,
|
|
80
|
+
},
|
|
33
81
|
},
|
|
34
82
|
async run({ args }) {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
console.log(`Processed ${result.processedFiles.length} file(s)`);
|
|
47
|
-
for (const file of result.processedFiles) {
|
|
48
|
-
console.log(` - ${file}`);
|
|
83
|
+
const options = {
|
|
84
|
+
input: args.input,
|
|
85
|
+
output: args.output,
|
|
86
|
+
vars: args.vars,
|
|
87
|
+
include: args.include,
|
|
88
|
+
exclude: args.exclude,
|
|
89
|
+
};
|
|
90
|
+
const success = await runProcess(options);
|
|
91
|
+
if (args.watch) {
|
|
92
|
+
if (!success) {
|
|
93
|
+
console.log("\nFix errors and save to retry...\n");
|
|
49
94
|
}
|
|
95
|
+
startWatch(options);
|
|
50
96
|
}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
error instanceof SameInputOutputError ||
|
|
54
|
-
error instanceof InvalidVariablesError) {
|
|
55
|
-
console.error(`Error: ${error.message}`);
|
|
56
|
-
process.exit(1);
|
|
57
|
-
}
|
|
58
|
-
throw error;
|
|
97
|
+
else if (!success) {
|
|
98
|
+
process.exit(1);
|
|
59
99
|
}
|
|
60
100
|
},
|
|
61
101
|
});
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "md-template-vars",
|
|
3
3
|
"author": "Shunta Toda",
|
|
4
|
-
"version": "0.1
|
|
4
|
+
"version": "0.2.1",
|
|
5
5
|
"description": "Replace {{variables}} in markdown templates with YAML values",
|
|
6
6
|
"type": "module",
|
|
7
7
|
"main": "./dist/application/use-cases/process-templates.js",
|