Skip to content

Commit 41ae1b9

Browse files
committed
test: add integration tests for args and $varname template variables
- args: [name] consumes CLI positional args as template vars - Body with only {{ name }} effectively becomes the CLI arg - $varname: Default provides defaults, --varname overrides - Missing template variable detection
1 parent c916d95 commit 41ae1b9

1 file changed

Lines changed: 170 additions & 0 deletions

File tree

src/args.test.ts

Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
import { expect, test, describe } from "bun:test";
2+
import { parseFrontmatter } from "./parse";
3+
import { substituteTemplateVars, extractTemplateVars } from "./template";
4+
5+
/**
6+
* Tests for the args system:
7+
* - args: [varname] in frontmatter defines positional arguments
8+
* - CLI positional args fill template variables in the body
9+
* - {{ varname }} in body gets replaced with the CLI arg value
10+
*/
11+
12+
describe("args positional argument flow", () => {
13+
test("args field defines template variables consumed from CLI", () => {
14+
const content = `---
15+
args: [message]
16+
---
17+
Say: {{ message }}`;
18+
19+
const { frontmatter, body } = parseFrontmatter(content);
20+
21+
// Simulate CLI: ma file.md "Hello World"
22+
const cliArgs = ["Hello World"];
23+
const templateVars: Record<string, string> = {};
24+
25+
// Consume positional args (same logic as index.ts)
26+
if (frontmatter.args && Array.isArray(frontmatter.args)) {
27+
for (let i = 0; i < frontmatter.args.length; i++) {
28+
if (i < cliArgs.length) {
29+
templateVars[frontmatter.args[i]] = cliArgs[i];
30+
}
31+
}
32+
}
33+
34+
expect(templateVars).toEqual({ message: "Hello World" });
35+
36+
// Apply substitution
37+
const result = substituteTemplateVars(body, templateVars);
38+
expect(result).toBe("Say: Hello World");
39+
});
40+
41+
test("multiple args consume multiple positional CLI arguments", () => {
42+
const content = `---
43+
args: [name, action]
44+
---
45+
{{ name }} will {{ action }}`;
46+
47+
const { frontmatter, body } = parseFrontmatter(content);
48+
49+
// Simulate CLI: ma file.md "Alice" "run"
50+
const cliArgs = ["Alice", "run"];
51+
const templateVars: Record<string, string> = {};
52+
53+
if (frontmatter.args && Array.isArray(frontmatter.args)) {
54+
for (let i = 0; i < frontmatter.args.length; i++) {
55+
if (i < cliArgs.length) {
56+
templateVars[frontmatter.args[i]] = cliArgs[i];
57+
}
58+
}
59+
}
60+
61+
expect(templateVars).toEqual({ name: "Alice", action: "run" });
62+
63+
const result = substituteTemplateVars(body, templateVars);
64+
expect(result).toBe("Alice will run");
65+
});
66+
67+
test("body consisting only of template var becomes the CLI arg", () => {
68+
const content = `---
69+
args: [prompt]
70+
---
71+
{{ prompt }}`;
72+
73+
const { frontmatter, body } = parseFrontmatter(content);
74+
75+
// Simulate CLI: ma file.md "Write me a haiku about coding"
76+
const cliArgs = ["Write me a haiku about coding"];
77+
const templateVars: Record<string, string> = {};
78+
79+
if (frontmatter.args && Array.isArray(frontmatter.args)) {
80+
for (let i = 0; i < frontmatter.args.length; i++) {
81+
if (i < cliArgs.length) {
82+
templateVars[frontmatter.args[i]] = cliArgs[i];
83+
}
84+
}
85+
}
86+
87+
const result = substituteTemplateVars(body, templateVars);
88+
expect(result).toBe("Write me a haiku about coding");
89+
});
90+
91+
test("missing template variables are detected", () => {
92+
const body = "Hello {{ name }}, welcome to {{ place }}";
93+
const requiredVars = extractTemplateVars(body);
94+
95+
expect(requiredVars).toContain("name");
96+
expect(requiredVars).toContain("place");
97+
98+
// If only one is provided, the other is "missing"
99+
const templateVars = { name: "Alice" };
100+
const missingVars = requiredVars.filter(v => !(v in templateVars));
101+
102+
expect(missingVars).toEqual(["place"]);
103+
});
104+
});
105+
106+
describe("$varname fields with defaults", () => {
107+
test("$varname field with default value", () => {
108+
const content = `---
109+
$feature_name: Authentication
110+
---
111+
Build {{ feature_name }}`;
112+
113+
const { frontmatter, body } = parseFrontmatter(content);
114+
115+
// Extract $varname fields
116+
const namedVarFields = Object.keys(frontmatter)
117+
.filter(key => key.startsWith("$") && !/^\$\d+$/.test(key));
118+
119+
const templateVars: Record<string, string> = {};
120+
121+
// Use frontmatter default (no CLI override)
122+
for (const key of namedVarFields) {
123+
const varName = key.slice(1);
124+
const defaultValue = frontmatter[key];
125+
if (defaultValue !== undefined && defaultValue !== null && defaultValue !== "") {
126+
templateVars[varName] = String(defaultValue);
127+
}
128+
}
129+
130+
expect(templateVars).toEqual({ feature_name: "Authentication" });
131+
132+
const result = substituteTemplateVars(body, templateVars);
133+
expect(result).toBe("Build Authentication");
134+
});
135+
136+
test("CLI flag overrides $varname default", () => {
137+
const content = `---
138+
$feature_name: Authentication
139+
---
140+
Build {{ feature_name }}`;
141+
142+
const { frontmatter, body } = parseFrontmatter(content);
143+
144+
// Simulate CLI: ma file.md --feature_name "Payments"
145+
const cliArgs = ["--feature_name", "Payments"];
146+
147+
const namedVarFields = Object.keys(frontmatter)
148+
.filter(key => key.startsWith("$") && !/^\$\d+$/.test(key));
149+
150+
const templateVars: Record<string, string> = {};
151+
152+
for (const key of namedVarFields) {
153+
const varName = key.slice(1);
154+
const defaultValue = frontmatter[key];
155+
156+
// Look for --varname in CLI args
157+
const flagIndex = cliArgs.findIndex(arg => arg === `--${varName}`);
158+
if (flagIndex !== -1 && flagIndex + 1 < cliArgs.length) {
159+
templateVars[varName] = cliArgs[flagIndex + 1];
160+
} else if (defaultValue !== undefined && defaultValue !== null && defaultValue !== "") {
161+
templateVars[varName] = String(defaultValue);
162+
}
163+
}
164+
165+
expect(templateVars).toEqual({ feature_name: "Payments" });
166+
167+
const result = substituteTemplateVars(body, templateVars);
168+
expect(result).toBe("Build Payments");
169+
});
170+
});

0 commit comments

Comments
 (0)