@garyr/pt-cli 0.36.4 โ 0.39.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 +3 -1
- package/dist/commands/addCommand.js +98 -8
- package/dist/commands/configCommand.js +11 -4
- package/dist/commands/initCommand.js +65 -0
- package/dist/commands/learnCommand.js +78 -5
- package/dist/config.js +12 -2
- package/dist/index.js +6 -3
- package/dist/substitute.js +25 -4
- package/doc/configuration.md +70 -8
- package/doc/usage.md +71 -0
- package/doc/variable_substitution_example.md +64 -0
- package/package.json +1 -1
- package/src/commands/addCommand.ts +109 -8
- package/src/commands/configCommand.ts +11 -4
- package/src/commands/initCommand.ts +77 -0
- package/src/commands/learnCommand.ts +83 -8
- package/src/config.ts +14 -2
- package/src/index.ts +6 -3
- package/src/substitute.ts +29 -4
- package/tests/env-scanning.test.ts +330 -0
- package/tests/final-rst-verification.test.ts +173 -0
- package/tests/nested-variable-expansion.test.ts +242 -0
- package/tests/rst-env-example.test.ts +208 -0
- package/tests/substitute.test.ts +14 -6
|
@@ -0,0 +1,330 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// Force a temporary home directory for testing before importing anything from the CLI
|
|
7
|
+
const testHome = path.join(process.cwd(), '.test-home-env');
|
|
8
|
+
process.env.HOME = testHome;
|
|
9
|
+
|
|
10
|
+
// Import the init command to test the env scanning functionality
|
|
11
|
+
import { init } from '../src/commands/initCommand.js';
|
|
12
|
+
import { loadConfig, saveConfig, PtConfig, getConfigPath } from '../src/config.js';
|
|
13
|
+
|
|
14
|
+
// Helper to clean up test directories
|
|
15
|
+
function cleanup(...paths: string[]) {
|
|
16
|
+
for (const p of paths) {
|
|
17
|
+
if (fs.existsSync(p)) {
|
|
18
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Helper to set up a config with a template for testing
|
|
24
|
+
function setupTestConfig(templateName: string, template: any): PtConfig {
|
|
25
|
+
const config: PtConfig = {
|
|
26
|
+
version: '3.0',
|
|
27
|
+
templates: {
|
|
28
|
+
[templateName]: template
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
saveConfig(config);
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test('init scans parent directories for .env files and pre-fills variables', async () => {
|
|
36
|
+
const parentEnvDir = path.join(process.cwd(), 'test-parent-env');
|
|
37
|
+
const projectDest = path.join(parentEnvDir, 'test-env-project');
|
|
38
|
+
const templateRoot = path.join(process.cwd(), 'test-env-tpl-root');
|
|
39
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
40
|
+
|
|
41
|
+
// Create template root with a file containing variables
|
|
42
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
43
|
+
fs.writeFileSync(
|
|
44
|
+
path.join(templateRoot, 'README.md'),
|
|
45
|
+
'# {{ project_name }}\n\nBy {{ author }}\n'
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
// Set up config with template that has variables and copy_files
|
|
49
|
+
setupTestConfig('env-tpl', {
|
|
50
|
+
description: 'Template with variables',
|
|
51
|
+
templateRoot: templateRoot,
|
|
52
|
+
folders: [],
|
|
53
|
+
variables: [
|
|
54
|
+
{ name: 'project_name', prompt: 'Project name:', required: true },
|
|
55
|
+
{ name: 'author', prompt: 'Author:', default: 'Unknown' }
|
|
56
|
+
],
|
|
57
|
+
copy_files: [
|
|
58
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
59
|
+
]
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
// Create parent directory with .env file containing matching variables
|
|
63
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
64
|
+
fs.writeFileSync(
|
|
65
|
+
path.join(parentEnvDir, '.env'),
|
|
66
|
+
`project_name=EnvProject\nauthor=EnvAuthor\n`
|
|
67
|
+
);
|
|
68
|
+
|
|
69
|
+
// Run init from within the parent directory
|
|
70
|
+
await init('env-tpl', projectDest, {
|
|
71
|
+
yes: true,
|
|
72
|
+
skipPostConfig: true
|
|
73
|
+
});
|
|
74
|
+
|
|
75
|
+
// Verify .env variables were used
|
|
76
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
77
|
+
assert.ok(readme.includes('EnvProject'), 'README should contain project_name from .env');
|
|
78
|
+
assert.ok(readme.includes('EnvAuthor'), 'README should contain author from .env');
|
|
79
|
+
assert.ok(!readme.includes('{{ project_name }}'), 'README should NOT contain variable placeholder');
|
|
80
|
+
|
|
81
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
82
|
+
});
|
|
83
|
+
|
|
84
|
+
test('init --vars overrides .env variables', async () => {
|
|
85
|
+
const parentEnvDir = path.join(process.cwd(), 'test-parent-override');
|
|
86
|
+
const projectDest = path.join(parentEnvDir, 'test-override-project');
|
|
87
|
+
const templateRoot = path.join(process.cwd(), 'test-override-tpl-root');
|
|
88
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
89
|
+
|
|
90
|
+
// Create template root with a file containing variables
|
|
91
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
92
|
+
fs.writeFileSync(
|
|
93
|
+
path.join(templateRoot, 'config.txt'),
|
|
94
|
+
'name={{ project_name }}\n'
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
// Set up config with template that has variables and copy_files
|
|
98
|
+
setupTestConfig('override-tpl', {
|
|
99
|
+
description: 'Template with variables',
|
|
100
|
+
templateRoot: templateRoot,
|
|
101
|
+
folders: [],
|
|
102
|
+
variables: [
|
|
103
|
+
{ name: 'project_name', prompt: 'Project name:', required: true }
|
|
104
|
+
],
|
|
105
|
+
copy_files: [
|
|
106
|
+
{ src: 'config.txt', dest: 'config.txt', substitute_variables: true }
|
|
107
|
+
]
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
// Create parent directory with .env file
|
|
111
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
112
|
+
fs.writeFileSync(
|
|
113
|
+
path.join(parentEnvDir, '.env'),
|
|
114
|
+
`project_name=EnvProject\n`
|
|
115
|
+
);
|
|
116
|
+
|
|
117
|
+
// Run init with --vars to override .env value
|
|
118
|
+
await init('override-tpl', projectDest, {
|
|
119
|
+
yes: true,
|
|
120
|
+
skipPostConfig: true,
|
|
121
|
+
vars: 'project_name=CLIProject'
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
// Verify --vars value was used instead of .env value
|
|
125
|
+
const configContent = fs.readFileSync(path.join(projectDest, 'config.txt'), 'utf-8');
|
|
126
|
+
assert.ok(configContent.includes('CLIProject'), 'config.txt should contain --vars value');
|
|
127
|
+
assert.ok(!configContent.includes('EnvProject'), 'config.txt should NOT contain .env value');
|
|
128
|
+
|
|
129
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
130
|
+
});
|
|
131
|
+
|
|
132
|
+
test('init uses .env from immediate parent directory', async () => {
|
|
133
|
+
const parentEnvDir = path.join(process.cwd(), 'test-immediate-parent');
|
|
134
|
+
const projectDest = path.join(parentEnvDir, 'test-immediate-parent-project');
|
|
135
|
+
const templateRoot = path.join(process.cwd(), 'test-immediate-parent-tpl-root');
|
|
136
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
137
|
+
|
|
138
|
+
// Create template root with a file containing variables
|
|
139
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
140
|
+
fs.writeFileSync(
|
|
141
|
+
path.join(templateRoot, 'README.md'),
|
|
142
|
+
'# {{ project_name }}\n'
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
// Set up config with template that has variables and copy_files
|
|
146
|
+
setupTestConfig('immediate-parent-tpl', {
|
|
147
|
+
description: 'Template with variables',
|
|
148
|
+
templateRoot: templateRoot,
|
|
149
|
+
folders: [],
|
|
150
|
+
variables: [
|
|
151
|
+
{ name: 'project_name', prompt: 'Project name:', required: true }
|
|
152
|
+
],
|
|
153
|
+
copy_files: [
|
|
154
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
155
|
+
]
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
// Create immediate parent directory with .env file
|
|
159
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
160
|
+
fs.writeFileSync(
|
|
161
|
+
path.join(parentEnvDir, '.env'),
|
|
162
|
+
`project_name=ImmediateParent\n`
|
|
163
|
+
);
|
|
164
|
+
|
|
165
|
+
// Run init from within the parent directory
|
|
166
|
+
await init('immediate-parent-tpl', projectDest, {
|
|
167
|
+
yes: true,
|
|
168
|
+
skipPostConfig: true
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
// Verify .env variable was used
|
|
172
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
173
|
+
assert.ok(readme.includes('ImmediateParent'), 'README should contain project_name from immediate parent .env');
|
|
174
|
+
|
|
175
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
test('init scans multiple parent directories for .env files', async () => {
|
|
179
|
+
const topEnvDir = path.join(process.cwd(), 'test-multi-parent');
|
|
180
|
+
const midEnvDir = path.join(topEnvDir, 'test-mid-env');
|
|
181
|
+
const projectDest = path.join(midEnvDir, 'test-multi-parent-project');
|
|
182
|
+
const templateRoot = path.join(process.cwd(), 'test-multi-parent-tpl-root');
|
|
183
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
184
|
+
|
|
185
|
+
// Create template root with a file containing variables
|
|
186
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
187
|
+
fs.writeFileSync(
|
|
188
|
+
path.join(templateRoot, 'README.md'),
|
|
189
|
+
'# {{ project_name }}\n\nBy {{ author }}\n'
|
|
190
|
+
);
|
|
191
|
+
|
|
192
|
+
// Set up config with template that has variables and copy_files
|
|
193
|
+
setupTestConfig('multi-parent-tpl', {
|
|
194
|
+
description: 'Template with variables',
|
|
195
|
+
templateRoot: templateRoot,
|
|
196
|
+
folders: [],
|
|
197
|
+
variables: [
|
|
198
|
+
{ name: 'project_name', prompt: 'Project name:', required: true },
|
|
199
|
+
{ name: 'author', prompt: 'Author:', default: 'Unknown' }
|
|
200
|
+
],
|
|
201
|
+
copy_files: [
|
|
202
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
203
|
+
]
|
|
204
|
+
});
|
|
205
|
+
|
|
206
|
+
// Create nested directory structure with .env files at different levels
|
|
207
|
+
fs.mkdirSync(topEnvDir, { recursive: true });
|
|
208
|
+
fs.mkdirSync(midEnvDir, { recursive: true });
|
|
209
|
+
|
|
210
|
+
// .env file at the top level with project_name
|
|
211
|
+
fs.writeFileSync(
|
|
212
|
+
path.join(topEnvDir, '.env'),
|
|
213
|
+
`project_name=TopLevel\n`
|
|
214
|
+
);
|
|
215
|
+
|
|
216
|
+
// .env file at the middle level with author
|
|
217
|
+
fs.writeFileSync(
|
|
218
|
+
path.join(midEnvDir, '.env'),
|
|
219
|
+
`author=MidLevelAuthor\n`
|
|
220
|
+
);
|
|
221
|
+
|
|
222
|
+
// Run init from the deepest directory
|
|
223
|
+
await init('multi-parent-tpl', projectDest, {
|
|
224
|
+
yes: true,
|
|
225
|
+
skipPostConfig: true
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
// Verify .env variables from different levels were used
|
|
229
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
230
|
+
assert.ok(readme.includes('TopLevel'), 'README should contain project_name from top level .env');
|
|
231
|
+
assert.ok(readme.includes('MidLevelAuthor'), 'README should contain author from middle level .env');
|
|
232
|
+
|
|
233
|
+
cleanup(projectDest, templateRoot, topEnvDir, midEnvDir, testHome);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
test('init uses .env values with quoted strings', async () => {
|
|
237
|
+
const parentEnvDir = path.join(process.cwd(), 'test-quoted-parent');
|
|
238
|
+
const projectDest = path.join(parentEnvDir, 'test-quoted-strings-project');
|
|
239
|
+
const templateRoot = path.join(process.cwd(), 'test-quoted-strings-tpl-root');
|
|
240
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
241
|
+
|
|
242
|
+
// Create template root with a file containing variables
|
|
243
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
244
|
+
fs.writeFileSync(
|
|
245
|
+
path.join(templateRoot, 'README.md'),
|
|
246
|
+
'# {{ project_name }}\n\nBy {{ author }}\n'
|
|
247
|
+
);
|
|
248
|
+
|
|
249
|
+
// Set up config with template that has variables and copy_files
|
|
250
|
+
setupTestConfig('quoted-strings-tpl', {
|
|
251
|
+
description: 'Template with variables',
|
|
252
|
+
templateRoot: templateRoot,
|
|
253
|
+
folders: [],
|
|
254
|
+
variables: [
|
|
255
|
+
{ name: 'project_name', prompt: 'Project name:', required: true },
|
|
256
|
+
{ name: 'author', prompt: 'Author:', default: 'Unknown' }
|
|
257
|
+
],
|
|
258
|
+
copy_files: [
|
|
259
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
260
|
+
]
|
|
261
|
+
});
|
|
262
|
+
|
|
263
|
+
// Create parent directory with .env file containing quoted strings
|
|
264
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
265
|
+
fs.writeFileSync(
|
|
266
|
+
path.join(parentEnvDir, '.env'),
|
|
267
|
+
`project_name="My Quoted Project"\nauthor='Quoted Author'\n`
|
|
268
|
+
);
|
|
269
|
+
|
|
270
|
+
// Run init from within the parent directory
|
|
271
|
+
await init('quoted-strings-tpl', projectDest, {
|
|
272
|
+
yes: true,
|
|
273
|
+
skipPostConfig: true
|
|
274
|
+
});
|
|
275
|
+
|
|
276
|
+
// Verify quoted strings were parsed correctly
|
|
277
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
278
|
+
assert.ok(readme.includes('My Quoted Project'), 'README should contain project_name without quotes');
|
|
279
|
+
assert.ok(readme.includes('Quoted Author'), 'README should contain author without quotes');
|
|
280
|
+
assert.ok(!readme.includes('"My Quoted Project"'), 'README should NOT contain quotes around project_name');
|
|
281
|
+
assert.ok(!readme.includes("'Quoted Author'"), 'README should NOT contain quotes around author');
|
|
282
|
+
|
|
283
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
test('init uses .env values with comments and empty lines', async () => {
|
|
287
|
+
const parentEnvDir = path.join(process.cwd(), 'test-comments-parent');
|
|
288
|
+
const projectDest = path.join(parentEnvDir, 'test-comments-project');
|
|
289
|
+
const templateRoot = path.join(process.cwd(), 'test-comments-tpl-root');
|
|
290
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
291
|
+
|
|
292
|
+
// Create template root with a file containing variables
|
|
293
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
294
|
+
fs.writeFileSync(
|
|
295
|
+
path.join(templateRoot, 'README.md'),
|
|
296
|
+
'# {{ project_name }}\n'
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Set up config with template that has variables and copy_files
|
|
300
|
+
setupTestConfig('comments-tpl', {
|
|
301
|
+
description: 'Template with variables',
|
|
302
|
+
templateRoot: templateRoot,
|
|
303
|
+
folders: [],
|
|
304
|
+
variables: [
|
|
305
|
+
{ name: 'project_name', prompt: 'Project name:', required: true }
|
|
306
|
+
],
|
|
307
|
+
copy_files: [
|
|
308
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
309
|
+
]
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
// Create parent directory with .env file containing comments and empty lines
|
|
313
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
314
|
+
fs.writeFileSync(
|
|
315
|
+
path.join(parentEnvDir, '.env'),
|
|
316
|
+
`# This is a comment\n\nproject_name=CommentProject\n\n# Another comment\n`
|
|
317
|
+
);
|
|
318
|
+
|
|
319
|
+
// Run init from within the parent directory
|
|
320
|
+
await init('comments-tpl', projectDest, {
|
|
321
|
+
yes: true,
|
|
322
|
+
skipPostConfig: true
|
|
323
|
+
});
|
|
324
|
+
|
|
325
|
+
// Verify .env variable was used (comments and empty lines should be ignored)
|
|
326
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
327
|
+
assert.ok(readme.includes('CommentProject'), 'README should contain project_name from .env');
|
|
328
|
+
|
|
329
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
330
|
+
});
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import { test } from 'node:test';
|
|
2
|
+
import assert from 'node:assert';
|
|
3
|
+
import fs from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
|
|
6
|
+
// Force a temporary home directory for testing
|
|
7
|
+
const testHome = path.join(process.cwd(), '.test-home-final-verification');
|
|
8
|
+
process.env.HOME = testHome;
|
|
9
|
+
|
|
10
|
+
// Import the init command
|
|
11
|
+
import { init } from '../src/commands/initCommand.js';
|
|
12
|
+
import { loadConfig, saveConfig, PtConfig } from '../src/config.js';
|
|
13
|
+
|
|
14
|
+
// Helper to clean up test directories
|
|
15
|
+
function cleanup(...paths: string[]) {
|
|
16
|
+
for (const p of paths) {
|
|
17
|
+
if (fs.existsSync(p)) {
|
|
18
|
+
fs.rmSync(p, { recursive: true, force: true });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// Helper to set up a config with a template for testing
|
|
24
|
+
function setupTestConfig(templateName: string, template: any): PtConfig {
|
|
25
|
+
const config: PtConfig = {
|
|
26
|
+
version: '3.0',
|
|
27
|
+
templates: {
|
|
28
|
+
[templateName]: template
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
saveConfig(config);
|
|
32
|
+
return config;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
test('FINAL VERIFICATION: Exact scenario from /mnt/production/CLIENT/RST/.env', async () => {
|
|
36
|
+
console.log('\n๐ฏ FINAL VERIFICATION TEST - Exact scenario from user request');
|
|
37
|
+
const prefixVar = 'rst_' + '{{ project }}';
|
|
38
|
+
console.log('๐ Testing: prefix=' + prefixVar + ' with project value');
|
|
39
|
+
|
|
40
|
+
// Set up the exact scenario from the user's request
|
|
41
|
+
const parentEnvDir = path.join(process.cwd(), 'test-final-rst');
|
|
42
|
+
const projectDest = path.join(parentEnvDir, 'final-rst-project');
|
|
43
|
+
const templateRoot = path.join(process.cwd(), 'test-final-tpl-root');
|
|
44
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
45
|
+
|
|
46
|
+
// Create template with the exact structure from the user's request
|
|
47
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
48
|
+
fs.writeFileSync(
|
|
49
|
+
path.join(templateRoot, 'README.md'),
|
|
50
|
+
'# {{ prefix }}\n\nThis is a test project.\n'
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
// Set up config with template that has the nested variable example
|
|
54
|
+
setupTestConfig('final-rst-tpl', {
|
|
55
|
+
description: 'Final RST Template with nested variable expansion',
|
|
56
|
+
templateRoot: templateRoot,
|
|
57
|
+
folders: [],
|
|
58
|
+
variables: [
|
|
59
|
+
{ name: 'prefix', prompt: 'Project prefix:', required: true },
|
|
60
|
+
{ name: 'project', prompt: 'Project name:', default: 'default' }
|
|
61
|
+
],
|
|
62
|
+
copy_files: [
|
|
63
|
+
{ src: 'README.md', dest: 'README.md', substitute_variables: true }
|
|
64
|
+
]
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Create parent directory with .env file containing the EXACT example from the user's request
|
|
68
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
69
|
+
fs.writeFileSync(
|
|
70
|
+
path.join(parentEnvDir, '.env'),
|
|
71
|
+
`prefix='rst_{{ project }}'\nproject=MyProject\n`
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
console.log('๐ Running pt init with the exact scenario...');
|
|
75
|
+
// Run init from within the parent directory
|
|
76
|
+
await init('final-rst-tpl', projectDest, {
|
|
77
|
+
yes: true,
|
|
78
|
+
skipPostConfig: true
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
// Verify the nested variable expansion worked correctly
|
|
82
|
+
const readme = fs.readFileSync(path.join(projectDest, 'README.md'), 'utf-8');
|
|
83
|
+
|
|
84
|
+
console.log('๐ Test Results:');
|
|
85
|
+
console.log(' Input: prefix=rst_{{ project }}, project=MyProject');
|
|
86
|
+
console.log(' Expected: README should contain rst_MyProject');
|
|
87
|
+
console.log(' Actual: README contains ' + readme.trim());
|
|
88
|
+
|
|
89
|
+
// The prefix variable should be 'rst_MyProject' (after expanding {{ project }})
|
|
90
|
+
assert.ok(readme.includes('rst_MyProject'), 'โ
README should contain expanded prefix value');
|
|
91
|
+
assert.ok(!readme.includes('{{ prefix }}'), 'โ
README should NOT contain variable placeholder');
|
|
92
|
+
assert.ok(!readme.includes('{{ project }}'), 'โ
README should NOT contain nested variable placeholder');
|
|
93
|
+
assert.ok(!readme.includes('rst_{{ project }}'), 'โ
README should NOT contain unexpanded nested variable');
|
|
94
|
+
|
|
95
|
+
console.log('\n๐ SUCCESS: Nested variable expansion works exactly as requested!');
|
|
96
|
+
console.log(' - .env file was scanned in parent directory');
|
|
97
|
+
console.log(' - prefix variable was pre-filled from .env with value rst_{{ project }}');
|
|
98
|
+
console.log(' - Nested {{ project }} placeholder was expanded to MyProject');
|
|
99
|
+
console.log(' - Final result: prefix resolved to rst_MyProject');
|
|
100
|
+
console.log(' - No manual input needed - fully automated!');
|
|
101
|
+
|
|
102
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
test('FINAL VERIFICATION: Multiple nested variables with complex expansion', async () => {
|
|
106
|
+
console.log('\n๐งช BONUS TEST: Complex nested variable expansion scenario');
|
|
107
|
+
|
|
108
|
+
// Set up a more complex scenario with multiple levels of nesting
|
|
109
|
+
const parentEnvDir = path.join(process.cwd(), 'test-final-complex');
|
|
110
|
+
const projectDest = path.join(parentEnvDir, 'complex-project');
|
|
111
|
+
const templateRoot = path.join(process.cwd(), 'test-final-complex-tpl-root');
|
|
112
|
+
cleanup(projectDest, templateRoot, testHome);
|
|
113
|
+
|
|
114
|
+
// Create template with complex nested variables
|
|
115
|
+
fs.mkdirSync(templateRoot, { recursive: true });
|
|
116
|
+
fs.writeFileSync(
|
|
117
|
+
path.join(templateRoot, 'config.json'),
|
|
118
|
+
'{\n "name": "{{ prefix }}_{{ project }}",\n "version": "{{ version }}"\n}\n'
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
// Set up config with template that has multiple nested variables
|
|
122
|
+
setupTestConfig('complex-tpl', {
|
|
123
|
+
description: 'Complex nested variable test',
|
|
124
|
+
templateRoot: templateRoot,
|
|
125
|
+
folders: [],
|
|
126
|
+
variables: [
|
|
127
|
+
{ name: 'prefix', prompt: 'Prefix:', required: true },
|
|
128
|
+
{ name: 'project', prompt: 'Project:', default: 'default' },
|
|
129
|
+
{ name: 'version', prompt: 'Version:', default: '1.0' }
|
|
130
|
+
],
|
|
131
|
+
copy_files: [
|
|
132
|
+
{ src: 'config.json', dest: 'config.json', substitute_variables: true }
|
|
133
|
+
]
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Create parent directory with .env file containing complex nested variables
|
|
137
|
+
fs.mkdirSync(parentEnvDir, { recursive: true });
|
|
138
|
+
fs.writeFileSync(
|
|
139
|
+
path.join(parentEnvDir, '.env'),
|
|
140
|
+
`prefix='app_{{ env }}'\nenv=prod\nproject=MyApp\nversion=2.0\n`
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
console.log('๐ Running complex nested variable scenario...');
|
|
144
|
+
// Run init from within the parent directory
|
|
145
|
+
await init('complex-tpl', projectDest, {
|
|
146
|
+
yes: true,
|
|
147
|
+
skipPostConfig: true
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
// Verify complex nested variables were expanded correctly
|
|
151
|
+
const configContent = fs.readFileSync(path.join(projectDest, 'config.json'), 'utf-8');
|
|
152
|
+
|
|
153
|
+
console.log('๐ Complex Test Results:');
|
|
154
|
+
console.log(' Input: prefix=app_{{ env }}, env=prod, project=MyApp, version=2.0');
|
|
155
|
+
console.log(' Expected: name=app_prod_MyApp, version=2.0');
|
|
156
|
+
console.log(' Actual: ' + configContent.trim());
|
|
157
|
+
|
|
158
|
+
// The prefix variable should be 'app_prod' (after expanding {{ env }})
|
|
159
|
+
// The final name should be 'app_prod_MyApp'
|
|
160
|
+
assert.ok(configContent.includes('app_prod_MyApp'), 'โ
config.json should contain fully expanded name');
|
|
161
|
+
assert.ok(configContent.includes('"2.0"'), 'โ
config.json should contain version');
|
|
162
|
+
assert.ok(!configContent.includes('{{ prefix }}'), 'โ
config.json should NOT contain variable placeholders');
|
|
163
|
+
assert.ok(!configContent.includes('{{ env }}'), 'โ
config.json should NOT contain nested variable placeholders');
|
|
164
|
+
assert.ok(!configContent.includes('app_{{ env }}'), 'โ
config.json should NOT contain unexpanded nested variable');
|
|
165
|
+
|
|
166
|
+
console.log('\n๐ SUCCESS: Complex nested variables work perfectly!');
|
|
167
|
+
console.log(' - Multiple levels of nesting were resolved');
|
|
168
|
+
console.log(' - prefix=app_{{ env }} expanded to app_prod');
|
|
169
|
+
console.log(' - Final name resolved to app_prod_MyApp');
|
|
170
|
+
console.log(' - All variables expanded correctly in one pass!');
|
|
171
|
+
|
|
172
|
+
cleanup(projectDest, templateRoot, parentEnvDir, testHome);
|
|
173
|
+
});
|