nubos-pilot 1.3.4 → 1.3.5
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/lib/template.cjs +20 -15
- package/lib/template.test.cjs +35 -0
- package/package.json +1 -1
package/lib/template.cjs
CHANGED
|
@@ -3,15 +3,14 @@ const path = require('node:path');
|
|
|
3
3
|
const { projectStateDir, NubosPilotError } = require('./core.cjs');
|
|
4
4
|
|
|
5
5
|
const PLACEHOLDER_RE = /\{\{\s*([a-zA-Z_][a-zA-Z0-9_]*)\s*\}\}/g;
|
|
6
|
+
const PACKAGE_TEMPLATES_DIR = path.resolve(__dirname, '..', 'templates');
|
|
6
7
|
|
|
7
8
|
function templatesDir(cwd) {
|
|
8
9
|
return path.join(projectStateDir(cwd), 'templates');
|
|
9
10
|
}
|
|
10
11
|
|
|
11
|
-
function
|
|
12
|
-
const dir = templatesDir(cwd);
|
|
12
|
+
function resolveInDir(dir, name) {
|
|
13
13
|
const filePath = path.resolve(dir, name + '.md');
|
|
14
|
-
|
|
15
14
|
const dirWithSep = dir.endsWith(path.sep) ? dir : dir + path.sep;
|
|
16
15
|
if (!filePath.startsWith(dirWithSep)) {
|
|
17
16
|
throw new NubosPilotError(
|
|
@@ -20,21 +19,27 @@ function loadTemplate(name, vars, cwd = process.cwd()) {
|
|
|
20
19
|
{ template: name, path: filePath },
|
|
21
20
|
);
|
|
22
21
|
}
|
|
22
|
+
return filePath;
|
|
23
|
+
}
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
25
|
+
function loadTemplate(name, vars, cwd = process.cwd()) {
|
|
26
|
+
const localPath = resolveInDir(templatesDir(cwd), name);
|
|
27
|
+
const packagePath = resolveInDir(PACKAGE_TEMPLATES_DIR, name);
|
|
28
|
+
|
|
29
|
+
let filePath = null;
|
|
30
|
+
if (fs.existsSync(localPath)) filePath = localPath;
|
|
31
|
+
else if (fs.existsSync(packagePath)) filePath = packagePath;
|
|
32
|
+
|
|
33
|
+
if (filePath === null) {
|
|
34
|
+
throw new NubosPilotError(
|
|
35
|
+
'template-not-found',
|
|
36
|
+
`Template "${name}" not found in project overlay (${localPath}) or package templates (${packagePath})`,
|
|
37
|
+
{ template: name, path: localPath, packagePath },
|
|
38
|
+
);
|
|
36
39
|
}
|
|
37
40
|
|
|
41
|
+
const raw = fs.readFileSync(filePath, 'utf-8');
|
|
42
|
+
|
|
38
43
|
return raw.replace(PLACEHOLDER_RE, (_match, key) => {
|
|
39
44
|
if (!(key in vars)) {
|
|
40
45
|
throw new NubosPilotError(
|
package/lib/template.test.cjs
CHANGED
|
@@ -144,6 +144,41 @@ test('TPL-12: listTemplates on sandbox without templates dir returns []', () =>
|
|
|
144
144
|
assert.deepEqual(list, []);
|
|
145
145
|
});
|
|
146
146
|
|
|
147
|
+
test('TPL-14: name absent in project overlay falls back to package template', () => {
|
|
148
|
+
const cwd = makeSandbox({});
|
|
149
|
+
const anyVars = new Proxy({}, { has: () => true, get: () => 'X' });
|
|
150
|
+
let out = null;
|
|
151
|
+
let thrown = null;
|
|
152
|
+
try {
|
|
153
|
+
out = tpl.loadTemplate('milestone/CONTEXT', anyVars, cwd);
|
|
154
|
+
} catch (err) {
|
|
155
|
+
thrown = err;
|
|
156
|
+
}
|
|
157
|
+
assert.equal(thrown, null, 'package fallback should resolve, not throw');
|
|
158
|
+
assert.equal(typeof out, 'string');
|
|
159
|
+
assert.ok(out.length > 0, 'package template rendered to non-empty output');
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
test('TPL-15: project overlay wins over package template of the same name', () => {
|
|
163
|
+
const cwd = makeSandbox({ RULES: 'LOCAL-OVERLAY {{x}}' });
|
|
164
|
+
const out = tpl.loadTemplate('RULES', { x: '1' }, cwd);
|
|
165
|
+
assert.equal(out, 'LOCAL-OVERLAY 1');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
test('TPL-16: name absent in BOTH overlay and package → template-not-found with both paths', () => {
|
|
169
|
+
const cwd = makeSandbox({});
|
|
170
|
+
let thrown = null;
|
|
171
|
+
try {
|
|
172
|
+
tpl.loadTemplate('definitely-missing-xyz', {}, cwd);
|
|
173
|
+
} catch (err) {
|
|
174
|
+
thrown = err;
|
|
175
|
+
}
|
|
176
|
+
assert.ok(thrown, 'expected throw');
|
|
177
|
+
assert.equal(thrown.code, 'template-not-found');
|
|
178
|
+
assert.ok(thrown.details.path.endsWith(path.join('templates', 'definitely-missing-xyz.md')));
|
|
179
|
+
assert.ok(thrown.details.packagePath.endsWith(path.join('templates', 'definitely-missing-xyz.md')));
|
|
180
|
+
});
|
|
181
|
+
|
|
147
182
|
test('TPL-13: cwd with no .nubos-pilot ancestor → projectStateDir throws not-in-project', () => {
|
|
148
183
|
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'nubos-pilot-tpl-noroot-'));
|
|
149
184
|
_sandboxes.push(root);
|
package/package.json
CHANGED