docvars 0.3.2 → 0.4.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/README.md +57 -28
- package/dist/application/use-cases/list-variables.d.ts +6 -1
- package/dist/application/use-cases/list-variables.js +3 -1
- package/dist/application/use-cases/rename-variable.js +2 -1
- package/dist/domain/value-objects/variables.d.ts +2 -2
- package/dist/domain/value-objects/variables.js +21 -7
- package/dist/presentation/cli/commands/main.js +19 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,25 +1,17 @@
|
|
|
1
1
|
# docvars
|
|
2
2
|
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
Supports any text-based files: Markdown, HTML, TXT, and more.
|
|
6
|
-
|
|
7
|
-
## Installation
|
|
3
|
+

|
|
8
4
|
|
|
9
|
-
|
|
10
|
-
npm install -g docvars
|
|
11
|
-
```
|
|
5
|
+
[日本語版 README はこちら](./README_ja.md)
|
|
12
6
|
|
|
13
|
-
|
|
7
|
+
A CLI tool to replace `{{variables}}` in document templates with values from a YAML file.
|
|
14
8
|
|
|
15
|
-
|
|
16
|
-
npx docvars ./templates ./output
|
|
17
|
-
```
|
|
9
|
+
Supports any text-based files: Markdown, HTML, TXT, and more.
|
|
18
10
|
|
|
19
11
|
## Usage
|
|
20
12
|
|
|
21
13
|
```bash
|
|
22
|
-
docvars <input> <output> [options]
|
|
14
|
+
npx docvars <input> <output> [options]
|
|
23
15
|
```
|
|
24
16
|
|
|
25
17
|
### Arguments
|
|
@@ -37,8 +29,8 @@ docvars <input> <output> [options]
|
|
|
37
29
|
| `--only` | `-o` | `**/*` | Glob pattern to filter files (e.g. **/*.md) |
|
|
38
30
|
| `--exclude` | `-e` | - | Glob pattern to exclude specific files |
|
|
39
31
|
| `--watch` | `-w` | `false` | Watch for file changes and rebuild automatically |
|
|
40
|
-
| `--rename-from` | `-
|
|
41
|
-
| `--rename-to` | `-
|
|
32
|
+
| `--rename-from` | `-F` | - | Variable name to rename from (use with --rename-to) |
|
|
33
|
+
| `--rename-to` | `-T` | - | Variable name to rename to (use with --rename-from) |
|
|
42
34
|
| `--list-vars` | `-l` | `false` | List all variables used in templates |
|
|
43
35
|
| `--dry-run` | `-d` | `false` | Preview changes without writing files |
|
|
44
36
|
|
|
@@ -47,29 +39,29 @@ docvars <input> <output> [options]
|
|
|
47
39
|
### Basic usage
|
|
48
40
|
|
|
49
41
|
```bash
|
|
50
|
-
docvars ./templates ./output
|
|
42
|
+
npx docvars ./templates ./output
|
|
51
43
|
```
|
|
52
44
|
|
|
53
45
|
### Custom variables file
|
|
54
46
|
|
|
55
47
|
```bash
|
|
56
|
-
docvars ./templates ./output --vars production.yaml
|
|
48
|
+
npx docvars ./templates ./output --vars production.yaml
|
|
57
49
|
```
|
|
58
50
|
|
|
59
51
|
### Filter files
|
|
60
52
|
|
|
61
53
|
```bash
|
|
62
54
|
# Process only markdown files
|
|
63
|
-
docvars ./templates ./output --only "**/*.md"
|
|
55
|
+
npx docvars ./templates ./output --only "**/*.md"
|
|
64
56
|
|
|
65
57
|
# Process multiple file types
|
|
66
|
-
docvars ./templates ./output --only "**/*.{md,html,txt}"
|
|
58
|
+
npx docvars ./templates ./output --only "**/*.{md,html,txt}"
|
|
67
59
|
|
|
68
60
|
# Process only files matching pattern
|
|
69
|
-
docvars ./templates ./output --only "api-*.md"
|
|
61
|
+
npx docvars ./templates ./output --only "api-*.md"
|
|
70
62
|
|
|
71
63
|
# Exclude files matching pattern
|
|
72
|
-
docvars ./templates ./output --exclude "draft-*.md"
|
|
64
|
+
npx docvars ./templates ./output --exclude "draft-*.md"
|
|
73
65
|
```
|
|
74
66
|
|
|
75
67
|
By default, all text files are processed (binary files like images are automatically excluded).
|
|
@@ -77,7 +69,7 @@ By default, all text files are processed (binary files like images are automatic
|
|
|
77
69
|
### Watch mode
|
|
78
70
|
|
|
79
71
|
```bash
|
|
80
|
-
docvars ./templates ./output --watch
|
|
72
|
+
npx docvars ./templates ./output --watch
|
|
81
73
|
```
|
|
82
74
|
|
|
83
75
|
Output:
|
|
@@ -111,26 +103,33 @@ Rename a variable across all template files and the variables YAML file:
|
|
|
111
103
|
|
|
112
104
|
```bash
|
|
113
105
|
# Simple rename
|
|
114
|
-
docvars ./templates ./output --rename-from "name" --rename-to "title"
|
|
106
|
+
npx docvars ./templates ./output --rename-from "name" --rename-to "title"
|
|
115
107
|
|
|
116
108
|
# Rename nested variable
|
|
117
|
-
docvars ./templates ./output --rename-from "database.host" --rename-to "db.host"
|
|
109
|
+
npx docvars ./templates ./output --rename-from "database.host" --rename-to "db.host"
|
|
110
|
+
|
|
111
|
+
# Prefix rename - renames all variables with matching prefix
|
|
112
|
+
# {{database}} → {{db}}
|
|
113
|
+
# {{database.host}} → {{db.host}}
|
|
114
|
+
# {{database.port}} → {{db.port}}
|
|
115
|
+
npx docvars ./templates ./output --rename-from "database" --rename-to "db"
|
|
118
116
|
```
|
|
119
117
|
|
|
120
118
|
Output:
|
|
121
119
|
|
|
122
120
|
```
|
|
123
121
|
✏️ Rename complete
|
|
124
|
-
database
|
|
122
|
+
database → db
|
|
125
123
|
|
|
126
124
|
┌────────────────┬───────────┐
|
|
127
125
|
│ File │ Status │
|
|
128
126
|
├────────────────┼───────────┤
|
|
129
127
|
│ variables.yaml │ ✓ updated │
|
|
130
128
|
│ README.md │ ✓ updated │
|
|
129
|
+
│ config.md │ ✓ updated │
|
|
131
130
|
└────────────────┴───────────┘
|
|
132
131
|
|
|
133
|
-
Updated:
|
|
132
|
+
Updated: 3 file(s)
|
|
134
133
|
```
|
|
135
134
|
|
|
136
135
|
### List variables
|
|
@@ -138,7 +137,7 @@ Updated: 2 file(s)
|
|
|
138
137
|
Show all variables used in templates and their status:
|
|
139
138
|
|
|
140
139
|
```bash
|
|
141
|
-
docvars ./templates ./output --list-vars
|
|
140
|
+
npx docvars ./templates ./output --list-vars
|
|
142
141
|
```
|
|
143
142
|
|
|
144
143
|
Output:
|
|
@@ -165,7 +164,7 @@ Summary: 1 defined · 1 undefined · 1 unused
|
|
|
165
164
|
Preview what files would be created or updated without actually writing them:
|
|
166
165
|
|
|
167
166
|
```bash
|
|
168
|
-
docvars ./templates ./output --dry-run
|
|
167
|
+
npx docvars ./templates ./output --dry-run
|
|
169
168
|
```
|
|
170
169
|
|
|
171
170
|
Output:
|
|
@@ -237,6 +236,36 @@ database:
|
|
|
237
236
|
Database: localhost:5432
|
|
238
237
|
```
|
|
239
238
|
|
|
239
|
+
### Array Variables
|
|
240
|
+
|
|
241
|
+
You can use arrays in your variables file and access them with index notation:
|
|
242
|
+
|
|
243
|
+
**Template:**
|
|
244
|
+
```markdown
|
|
245
|
+
## Features
|
|
246
|
+
|
|
247
|
+
1. {{features.0}}
|
|
248
|
+
2. {{features.1}}
|
|
249
|
+
3. {{features.2}}
|
|
250
|
+
```
|
|
251
|
+
|
|
252
|
+
**Variables (variables.yaml):**
|
|
253
|
+
```yaml
|
|
254
|
+
features:
|
|
255
|
+
- User authentication
|
|
256
|
+
- Data analytics
|
|
257
|
+
- API integration
|
|
258
|
+
```
|
|
259
|
+
|
|
260
|
+
**Output:**
|
|
261
|
+
```markdown
|
|
262
|
+
## Features
|
|
263
|
+
|
|
264
|
+
1. User authentication
|
|
265
|
+
2. Data analytics
|
|
266
|
+
3. API integration
|
|
267
|
+
```
|
|
268
|
+
|
|
240
269
|
## Error Handling
|
|
241
270
|
|
|
242
271
|
| Case | Behavior |
|
|
@@ -6,11 +6,16 @@ export interface ListVariablesOptions {
|
|
|
6
6
|
}
|
|
7
7
|
export interface VariableUsage {
|
|
8
8
|
name: string;
|
|
9
|
+
value?: string;
|
|
9
10
|
files: string[];
|
|
10
11
|
isDefined: boolean;
|
|
11
12
|
}
|
|
13
|
+
export interface UnusedVariable {
|
|
14
|
+
name: string;
|
|
15
|
+
value: string;
|
|
16
|
+
}
|
|
12
17
|
export interface ListVariablesResult {
|
|
13
18
|
variables: VariableUsage[];
|
|
14
|
-
unusedVariables:
|
|
19
|
+
unusedVariables: UnusedVariable[];
|
|
15
20
|
}
|
|
16
21
|
export declare function listVariables(options: ListVariablesOptions): Promise<ListVariablesResult>;
|
|
@@ -34,6 +34,7 @@ export async function listVariables(options) {
|
|
|
34
34
|
for (const [name, files] of variableUsageMap) {
|
|
35
35
|
variables.push({
|
|
36
36
|
name,
|
|
37
|
+
value: definedVars[name],
|
|
37
38
|
files: Array.from(files).sort(),
|
|
38
39
|
isDefined: definedVarNames.has(name),
|
|
39
40
|
});
|
|
@@ -43,6 +44,7 @@ export async function listVariables(options) {
|
|
|
43
44
|
// Find unused variables (defined but not used)
|
|
44
45
|
const unusedVariables = Array.from(definedVarNames)
|
|
45
46
|
.filter((name) => !usedVarNames.has(name))
|
|
46
|
-
.sort()
|
|
47
|
+
.sort()
|
|
48
|
+
.map((name) => ({ name, value: definedVars[name] }));
|
|
47
49
|
return { variables, unusedVariables };
|
|
48
50
|
}
|
|
@@ -16,7 +16,8 @@ export async function renameVariable(options) {
|
|
|
16
16
|
};
|
|
17
17
|
// Rename in template files
|
|
18
18
|
const templateFiles = await scanTemplates(input, { only, exclude });
|
|
19
|
-
|
|
19
|
+
// Match exact variable or prefix (e.g., "database" matches "{{database}}" and "{{database.host}}")
|
|
20
|
+
const pattern = new RegExp(`\\{\\{${escapeRegex(from)}(\\.|\\}\\}|\\|)`, "g");
|
|
20
21
|
for (const file of templateFiles) {
|
|
21
22
|
const content = readFileSync(file, "utf-8");
|
|
22
23
|
const newContent = content.replace(pattern, `{{${to}$1`);
|
|
@@ -2,8 +2,8 @@ import { z } from "zod";
|
|
|
2
2
|
declare const PrimitiveValueSchema: z.ZodUnion<[z.ZodString, z.ZodNumber, z.ZodBoolean]>;
|
|
3
3
|
type NestedValue = z.infer<typeof PrimitiveValueSchema> | {
|
|
4
4
|
[key: string]: NestedValue;
|
|
5
|
-
};
|
|
5
|
+
} | NestedValue[];
|
|
6
6
|
export declare const VariablesSchema: z.ZodRecord<z.ZodString, z.ZodType<NestedValue, z.ZodTypeDef, NestedValue>>;
|
|
7
7
|
export type Variables = Record<string, string>;
|
|
8
|
-
export declare function flattenVariables(obj: Record<string, NestedValue
|
|
8
|
+
export declare function flattenVariables(obj: Record<string, NestedValue> | NestedValue[], prefix?: string): Variables;
|
|
9
9
|
export {};
|
|
@@ -1,16 +1,30 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
const PrimitiveValueSchema = z.union([z.string(), z.number(), z.boolean()]);
|
|
3
|
-
const NestedValueSchema = z.lazy(() => z.union([PrimitiveValueSchema, z.record(z.string(), NestedValueSchema)]));
|
|
3
|
+
const NestedValueSchema = z.lazy(() => z.union([PrimitiveValueSchema, z.array(NestedValueSchema), z.record(z.string(), NestedValueSchema)]));
|
|
4
4
|
export const VariablesSchema = z.record(z.string(), NestedValueSchema);
|
|
5
5
|
export function flattenVariables(obj, prefix = "") {
|
|
6
6
|
const result = {};
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
if (Array.isArray(obj)) {
|
|
8
|
+
for (let i = 0; i < obj.length; i++) {
|
|
9
|
+
const value = obj[i];
|
|
10
|
+
const fullKey = prefix ? `${prefix}.${i}` : String(i);
|
|
11
|
+
if (typeof value === "object" && value !== null) {
|
|
12
|
+
Object.assign(result, flattenVariables(value, fullKey));
|
|
13
|
+
}
|
|
14
|
+
else {
|
|
15
|
+
result[fullKey] = String(value);
|
|
16
|
+
}
|
|
11
17
|
}
|
|
12
|
-
|
|
13
|
-
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
21
|
+
const fullKey = prefix ? `${prefix}.${key}` : key;
|
|
22
|
+
if (typeof value === "object" && value !== null) {
|
|
23
|
+
Object.assign(result, flattenVariables(value, fullKey));
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
result[fullKey] = String(value);
|
|
27
|
+
}
|
|
14
28
|
}
|
|
15
29
|
}
|
|
16
30
|
return result;
|
|
@@ -3,6 +3,11 @@ import { resolve } from "node:path";
|
|
|
3
3
|
import pc from "picocolors";
|
|
4
4
|
import Table from "cli-table3";
|
|
5
5
|
import { watch } from "chokidar";
|
|
6
|
+
function truncate(str, maxLength) {
|
|
7
|
+
if (str.length <= maxLength)
|
|
8
|
+
return str;
|
|
9
|
+
return str.slice(0, maxLength - 1) + "…";
|
|
10
|
+
}
|
|
6
11
|
import { processTemplates } from "../../../application/use-cases/process-templates.js";
|
|
7
12
|
import { renameVariable } from "../../../application/use-cases/rename-variable.js";
|
|
8
13
|
import { listVariables } from "../../../application/use-cases/list-variables.js";
|
|
@@ -111,12 +116,12 @@ export const mainCommand = defineCommand({
|
|
|
111
116
|
},
|
|
112
117
|
"rename-from": {
|
|
113
118
|
type: "string",
|
|
114
|
-
alias: "
|
|
119
|
+
alias: "F",
|
|
115
120
|
description: "Variable name to rename from (use with --rename-to)",
|
|
116
121
|
},
|
|
117
122
|
"rename-to": {
|
|
118
123
|
type: "string",
|
|
119
|
-
alias: "
|
|
124
|
+
alias: "T",
|
|
120
125
|
description: "Variable name to rename to (use with --rename-from)",
|
|
121
126
|
},
|
|
122
127
|
"list-vars": {
|
|
@@ -212,22 +217,29 @@ export const mainCommand = defineCommand({
|
|
|
212
217
|
}
|
|
213
218
|
if (result.variables.length > 0) {
|
|
214
219
|
const table = new Table({
|
|
215
|
-
head: [pc.bold("Variable"), pc.bold("
|
|
220
|
+
head: [pc.bold("Variable"), pc.bold("Value"), pc.bold("Used in")],
|
|
216
221
|
style: { head: [], border: [] },
|
|
217
222
|
wordWrap: true,
|
|
223
|
+
colWidths: [null, 30, null],
|
|
218
224
|
});
|
|
219
225
|
for (const v of result.variables) {
|
|
220
|
-
const
|
|
226
|
+
const value = v.isDefined ? pc.green(truncate(v.value || "", 25)) : pc.red("✗ undefined");
|
|
221
227
|
const files = v.files.map((f) => pc.gray(f)).join("\n");
|
|
222
|
-
table.push([v.name,
|
|
228
|
+
table.push([v.name, value, files]);
|
|
223
229
|
}
|
|
224
230
|
console.log(table.toString());
|
|
225
231
|
}
|
|
226
232
|
if (result.unusedVariables.length > 0) {
|
|
227
233
|
console.log(pc.bold(pc.yellow("\n⚠ Unused variables (defined but not used):\n")));
|
|
228
|
-
|
|
229
|
-
|
|
234
|
+
const unusedTable = new Table({
|
|
235
|
+
head: [pc.bold("Variable"), pc.bold("Value")],
|
|
236
|
+
style: { head: [], border: [] },
|
|
237
|
+
colWidths: [null, 40],
|
|
238
|
+
});
|
|
239
|
+
for (const v of result.unusedVariables) {
|
|
240
|
+
unusedTable.push([pc.gray(v.name), pc.gray(truncate(v.value, 35))]);
|
|
230
241
|
}
|
|
242
|
+
console.log(unusedTable.toString());
|
|
231
243
|
}
|
|
232
244
|
console.log();
|
|
233
245
|
const defined = result.variables.filter((v) => v.isDefined).length;
|
package/package.json
CHANGED