timonel 2.11.0 → 2.12.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/CHANGELOG.md CHANGED
@@ -1,3 +1,20 @@
1
+ ## [2.12.1](https://github.com/KenkoGeek/timonel/compare/v2.12.0...v2.12.1) (2025-09-28)
2
+
3
+ ### Bug Fixes
4
+
5
+ - **cli:** new feature for cli ([a8c5326](https://github.com/KenkoGeek/timonel/commit/a8c532617616bfedada20d28bcc4fe94ea165321))
6
+
7
+ # [2.12.0](https://github.com/KenkoGeek/timonel/compare/v2.11.0...v2.12.0) (2025-09-28)
8
+
9
+ ### Bug Fixes
10
+
11
+ - **cli:** harden flag handling and path validation ([#130](https://github.com/KenkoGeek/timonel/issues/130)) ([2186d88](https://github.com/KenkoGeek/timonel/commit/2186d886428752025e7bf531c4a6541dade683a6))
12
+
13
+ ### Features
14
+
15
+ - **docs:** update references and CLI [skip ci] ([23704d3](https://github.com/KenkoGeek/timonel/commit/23704d3164cfbb92d183af40c70e27a32b566d06))
16
+ - **docs:** update references and CLI [skip ci] ([be4bcdc](https://github.com/KenkoGeek/timonel/commit/be4bcdca62cb3a9339e5ad70efc0ba31a6d9d5be))
17
+
1
18
  # [2.11.0](https://github.com/KenkoGeek/timonel/compare/v2.10.2...v2.11.0) (2025-09-26)
2
19
 
3
20
  ### Features
package/README.md CHANGED
@@ -38,9 +38,6 @@ npm install -g timonel
38
38
 
39
39
  # Or use with pnpm
40
40
  pnpm add -g timonel
41
-
42
- # Verify installation
43
- tl --version
44
41
  ```
45
42
 
46
43
  ### Basic Usage
@@ -140,6 +137,8 @@ export const umbrella = new UmbrellaChartTemplate(umbrellaConfig);
140
137
  patterns and practices
141
138
  - **[Contributing](https://github.com/KenkoGeek/timonel/wiki/Contributing)** - Development setup
142
139
  and guidelines
140
+ - **[Timonel Examples Repository](https://github.com/KenkoGeek/timonel-examples)** - Curated
141
+ collection of ready-to-run Timonel sample projects
143
142
 
144
143
  ## 🔧 Troubleshooting
145
144
 
@@ -157,10 +156,10 @@ If you get `Error: Cannot find module 'cdk8s'` when running `tl umbrella synth`:
157
156
  "version": "1.0.0",
158
157
  "type": "module",
159
158
  "dependencies": {
160
- "cdk8s": "^2.70.15",
161
- "cdk8s-plus-33": "^2.3.6",
159
+ "cdk8s": "^2.70.16",
160
+ "cdk8s-plus-33": "^2.3.8",
162
161
  "constructs": "^10.4.2",
163
- "timonel": "^2.9.2"
162
+ "timonel": "^2.11.0"
164
163
  },
165
164
  "devDependencies": {
166
165
  "@types/node": "^24.5.2",
@@ -176,45 +175,6 @@ npm install
176
175
  tl umbrella synth # Now it works!
177
176
  ```
178
177
 
179
- ### Version Display Issues
180
-
181
- If the CLI shows an incorrect version:
182
-
183
- **Problem**: The CLI might be using cached or hardcoded version information.
184
-
185
- **Solution**: Rebuild the project:
186
-
187
- ```bash
188
- # In the Timonel project directory
189
- pnpm build
190
- tl --version # Should show correct version
191
- ```
192
-
193
- ### TypeScript Compilation Errors
194
-
195
- If you encounter TypeScript errors when using umbrella charts:
196
-
197
- **Problem**: Type mismatches in subchart configurations.
198
-
199
- **Solution**: Ensure proper type casting for version and description fields:
200
-
201
- ```typescript
202
- // ✅ Correct
203
- const subchart = {
204
- name: 'my-service',
205
- version: '1.0.0' as string,
206
- description: 'My service' as string,
207
- chart: myChartFunction,
208
- };
209
-
210
- // ❌ Incorrect
211
- const subchart = {
212
- name: 'my-service',
213
- version: someUnknownValue, // This will cause TypeScript errors
214
- chart: myChartFunction,
215
- };
216
- ```
217
-
218
178
  ## 🤝 Contributing
219
179
 
220
180
  See our [Contributing Guide](https://github.com/KenkoGeek/timonel/wiki/Contributing) for development
package/dist/cli.js CHANGED
@@ -12,37 +12,20 @@ const UMBRELLA_FILE_NAME = 'umbrella.ts';
12
12
  const PACKAGE_JSON_FILE = 'package.json';
13
13
  function getVersion() {
14
14
  try {
15
- const possiblePaths = [
16
- path.resolve(__dirname, '..', PACKAGE_JSON_FILE),
17
- path.resolve(__dirname, '..', '..', PACKAGE_JSON_FILE),
18
- path.resolve(process.cwd(), PACKAGE_JSON_FILE),
19
- path.resolve(__dirname, PACKAGE_JSON_FILE),
20
- ];
21
- for (const packagePath of possiblePaths) {
22
- try {
23
- const validatedPath = SecurityUtils.validatePath(packagePath, process.cwd());
24
- if (fs.existsSync(validatedPath)) {
25
- try {
26
- const packageJson = JSON.parse(fs.readFileSync(validatedPath, 'utf8'));
27
- return packageJson.version || 'unknown';
28
- }
29
- catch {
30
- continue;
31
- }
32
- }
33
- }
34
- catch {
35
- continue;
36
- }
15
+ const packagePath = path.resolve(__dirname, '..', PACKAGE_JSON_FILE);
16
+ const allowedBase = path.resolve(__dirname, '..');
17
+ const validatedPath = SecurityUtils.validatePath(packagePath, allowedBase);
18
+ const packageJson = JSON.parse(fs.readFileSync(validatedPath, 'utf8'));
19
+ if (packageJson.version) {
20
+ return packageJson.version;
37
21
  }
38
- if (process.env.npm_package_version) {
39
- return process.env.npm_package_version;
40
- }
41
- return 'unknown';
42
22
  }
43
23
  catch {
44
- return 'unknown';
45
24
  }
25
+ if (process.env.npm_package_version) {
26
+ return process.env.npm_package_version;
27
+ }
28
+ return 'unknown';
46
29
  }
47
30
  const cliLogger = createLogger('cli');
48
31
  function log(msg, silent = false) {
@@ -81,6 +64,7 @@ function usageAndExit(msg, silent = false) {
81
64
  ' --silent Suppress output (useful for CI)',
82
65
  ' --env <environment> Use environment-specific values',
83
66
  ' --set <key=value> Override values (can be used multiple times)',
67
+ ' --mode <dependencies|inline> Umbrella synth mode (default: dependencies)',
84
68
  ' --help, -h Show this help message',
85
69
  '',
86
70
  'Examples:',
@@ -162,7 +146,23 @@ await import(pathToFileURL('${tempChartFile}').href);
162
146
  }
163
147
  }
164
148
  async function cmdValidate(flags) {
165
- const result = spawnSync('helm', ['lint', '.'], {
149
+ const lintArgs = ['lint', '.'];
150
+ if (flags?.env) {
151
+ try {
152
+ const sanitizedEnv = SecurityUtils.sanitizeEnvironmentName(flags.env);
153
+ lintArgs.push('-f', `values-${sanitizedEnv}.yaml`);
154
+ }
155
+ catch (error) {
156
+ console.error(SecurityUtils.sanitizeLogMessage(error.message));
157
+ process.exit(1);
158
+ }
159
+ }
160
+ if (flags?.set) {
161
+ for (const setValue of flags.set) {
162
+ lintArgs.push('--set', setValue);
163
+ }
164
+ }
165
+ const result = spawnSync('helm', lintArgs, {
166
166
  stdio: flags?.silent ? 'pipe' : 'inherit',
167
167
  encoding: 'utf8',
168
168
  });
@@ -180,6 +180,21 @@ async function cmdDeploy(release, namespace, flags) {
180
180
  if (namespace) {
181
181
  args.push('--namespace', namespace);
182
182
  }
183
+ if (flags?.env) {
184
+ try {
185
+ const sanitizedEnv = SecurityUtils.sanitizeEnvironmentName(flags.env);
186
+ args.push('-f', `values-${sanitizedEnv}.yaml`);
187
+ }
188
+ catch (error) {
189
+ console.error(SecurityUtils.sanitizeLogMessage(error.message));
190
+ process.exit(1);
191
+ }
192
+ }
193
+ if (flags?.set) {
194
+ for (const setValue of flags.set) {
195
+ args.push('--set', setValue);
196
+ }
197
+ }
183
198
  const result = spawnSync('helm', args.filter((arg) => Boolean(arg)), {
184
199
  stdio: flags?.silent ? 'pipe' : 'inherit',
185
200
  encoding: 'utf8',
@@ -220,18 +235,22 @@ async function cmdTemplates(flags) {
220
235
  });
221
236
  }
222
237
  }
238
+ const UMBRELLA_SYNTH_MODES = ['dependencies', 'inline'];
223
239
  async function cmdUmbrella(subcommand, args, flags) {
224
240
  if (!subcommand)
225
241
  usageAndExit('Missing umbrella subcommand');
242
+ const workingArgs = [...(args ?? [])];
243
+ const subcommandFlags = parseFlags(workingArgs);
244
+ const mergedFlags = mergeCliFlags(flags, subcommandFlags);
226
245
  switch (subcommand) {
227
246
  case 'init':
228
- await cmdUmbrellaInit(args?.[0], flags?.silent);
247
+ await cmdUmbrellaInit(workingArgs[0], mergedFlags.silent);
229
248
  break;
230
249
  case 'add':
231
- await cmdUmbrellaAdd(args?.[0], flags?.silent);
250
+ await cmdUmbrellaAdd(workingArgs[0], mergedFlags.silent);
232
251
  break;
233
252
  case 'synth':
234
- await cmdUmbrellaSynth(args?.[0], flags);
253
+ await cmdUmbrellaSynth(workingArgs[0], mergedFlags);
235
254
  break;
236
255
  default:
237
256
  usageAndExit(`Unknown umbrella subcommand: ${subcommand}`);
@@ -290,28 +309,54 @@ function addImportStatement(content, importStatement) {
290
309
  return lines.join('\n');
291
310
  }
292
311
  function buildSubchartsContent(subchartsContent, subchartEntry) {
293
- const hasExistingEntries = /\{\s*name:\s*['"]/.test(subchartsContent || '');
294
- if (!hasExistingEntries) {
295
- return `\n // Add your subcharts here:\n ${subchartEntry},\n `;
296
- }
297
- const trimmedContent = subchartsContent?.trimEnd() ?? '';
298
- const needsComma = !trimmedContent.endsWith(',');
299
- const comma = needsComma ? ',' : '';
300
- return trimmedContent + `${comma}\n ${subchartEntry}`;
312
+ const existingEntries = (subchartsContent || '')
313
+ .split('\n')
314
+ .map((line) => line.trim())
315
+ .filter((line) => line && !line.startsWith('//'))
316
+ .map((line) => line.replace(/,$/, ''));
317
+ if (existingEntries.includes(subchartEntry)) {
318
+ return subchartsContent ?? '';
319
+ }
320
+ const entries = [...existingEntries, subchartEntry];
321
+ const lines = [' // Add your subcharts here:'];
322
+ for (const entry of entries) {
323
+ lines.push(` ${entry},`);
324
+ }
325
+ return `\n${lines.join('\n')}\n`;
301
326
  }
302
327
  function addSubchartToArray(content, chartName, camelCaseName) {
303
- const subchartsRegex = /subcharts:\s*\[([\s\S]*?)\]/;
328
+ const subchartsRegex = /(const SUBCHARTS[\s\S]*?=\s*\[)([\s\S]*?)(\];)/;
304
329
  const match = content.match(subchartsRegex);
305
330
  if (!match) {
306
331
  return content;
307
332
  }
308
- const subchartsContent = match[1];
309
- if (subchartsContent?.includes(`name: '${chartName}'`)) {
333
+ const [, prefix, body, suffix] = match;
334
+ if (body?.includes(`name: '${chartName}'`)) {
310
335
  return content;
311
336
  }
312
- const subchartEntry = `{ name: '${chartName}', chart: ${camelCaseName} }`;
313
- const newSubchartsContent = buildSubchartsContent(subchartsContent, subchartEntry);
314
- return content.replace(subchartsRegex, `subcharts: [${newSubchartsContent}\n ]`);
337
+ const subchartEntry = `{ name: '${chartName}', factory: ${camelCaseName} }`;
338
+ const newBody = buildSubchartsContent(body, subchartEntry);
339
+ return content.replace(subchartsRegex, `${prefix}${newBody}${suffix}`);
340
+ }
341
+ function mergeCliFlags(base, override) {
342
+ const merged = { ...(base || {}) };
343
+ if (!override) {
344
+ return merged;
345
+ }
346
+ if (override.dryRun !== undefined)
347
+ merged.dryRun = override.dryRun;
348
+ if (override.silent !== undefined)
349
+ merged.silent = override.silent;
350
+ if (override.env !== undefined)
351
+ merged.env = override.env;
352
+ if (override.mode !== undefined)
353
+ merged.mode = override.mode;
354
+ const baseSet = base?.set ?? [];
355
+ const overrideSet = override.set ?? [];
356
+ if (baseSet.length || overrideSet.length) {
357
+ merged.set = [...baseSet, ...overrideSet];
358
+ }
359
+ return merged;
315
360
  }
316
361
  function updateUmbrellaTs(subchartPath, chartName) {
317
362
  const umbrellaFile = path.join(process.cwd(), UMBRELLA_FILE_NAME);
@@ -343,8 +388,19 @@ async function cmdUmbrellaAdd(subchartPath, silent = false) {
343
388
  }
344
389
  const config = JSON.parse(fs.readFileSync(configFile, 'utf8'));
345
390
  const subchartName = path.basename(validSubchartPath);
346
- const subchartDir = path.join(process.cwd(), 'charts', validSubchartPath);
391
+ const chartsRoot = path.join(process.cwd(), 'charts');
392
+ const targetSubchartPath = path.join(chartsRoot, validSubchartPath);
393
+ let subchartDir;
394
+ try {
395
+ subchartDir = SecurityUtils.validatePath(targetSubchartPath, chartsRoot);
396
+ }
397
+ catch (error) {
398
+ console.error(SecurityUtils.sanitizeLogMessage(error.message));
399
+ process.exit(1);
400
+ }
347
401
  fs.mkdirSync(subchartDir, { recursive: true });
402
+ const relativeSubchartPath = path.relative(chartsRoot, subchartDir) || subchartName;
403
+ const normalizedSubchartPath = relativeSubchartPath.split(path.sep).join('/');
348
404
  const chartFile = path.join(subchartDir, 'chart.ts');
349
405
  const { generateFlexibleSubchartTemplate } = await import('./lib/templates/flexible-subchart.js');
350
406
  const subchartContent = generateFlexibleSubchartTemplate(subchartName);
@@ -352,11 +408,11 @@ async function cmdUmbrellaAdd(subchartPath, silent = false) {
352
408
  config.subcharts.push({
353
409
  name: subchartName,
354
410
  version: getVersion(),
355
- path: `./charts/${validSubchartPath}/chart.ts`,
411
+ path: `./charts/${normalizedSubchartPath}/chart.ts`,
356
412
  });
357
413
  fs.writeFileSync(configFile, JSON.stringify(config, null, 2));
358
- updateUmbrellaTs(validSubchartPath, subchartName);
359
- log(`Subchart ${subchartName} added to umbrella at path '${validSubchartPath}'`, silent);
414
+ updateUmbrellaTs(normalizedSubchartPath, subchartName);
415
+ log(`Subchart ${subchartName} added to umbrella at path '${normalizedSubchartPath}'`, silent);
360
416
  }
361
417
  async function cmdUmbrellaSynth(outDir, flags) {
362
418
  const umbrellaFile = path.join(process.cwd(), UMBRELLA_FILE_NAME);
@@ -366,9 +422,13 @@ async function cmdUmbrellaSynth(outDir, flags) {
366
422
  process.exit(1);
367
423
  }
368
424
  const resolvedOutDir = outDir ? path.resolve(outDir) : defaultOutDir;
369
- await executeTypeScriptUmbrella(umbrellaFile, resolvedOutDir, flags);
425
+ const synthMode = flags?.mode ?? 'dependencies';
426
+ if (!UMBRELLA_SYNTH_MODES.includes(synthMode)) {
427
+ usageAndExit('Invalid mode. Use "dependencies" or "inline".', flags?.silent);
428
+ }
429
+ await executeTypeScriptUmbrella(umbrellaFile, resolvedOutDir, synthMode, flags);
370
430
  }
371
- async function executeTypeScriptUmbrella(resolvedPath, outDir, flags) {
431
+ async function executeTypeScriptUmbrella(resolvedPath, outDir, mode, flags) {
372
432
  const wrapperScript = `
373
433
  import { pathToFileURL } from 'url';
374
434
 
@@ -380,9 +440,10 @@ if (typeof runner !== 'function') {
380
440
  }
381
441
 
382
442
  const output = '${outDir}';
443
+ const synthOptions = { mode: '${mode}' };
383
444
  const fs = await import('fs');
384
445
  fs.mkdirSync(output, { recursive: true });
385
- await Promise.resolve(runner(output));
446
+ await Promise.resolve(runner(output, synthOptions));
386
447
  console.log('Umbrella chart written to ' + output);
387
448
  `;
388
449
  const wrapperFile = path.join(process.cwd(), '.timonel-umbrella-wrapper.mjs');
@@ -430,6 +491,14 @@ function parseFlags(args) {
430
491
  }
431
492
  break;
432
493
  }
494
+ case '--mode': {
495
+ const modeValue = args.shift();
496
+ if (!modeValue || !UMBRELLA_SYNTH_MODES.includes(modeValue)) {
497
+ usageAndExit('Invalid mode. Use "dependencies" or "inline".', flags.silent);
498
+ }
499
+ flags.mode = modeValue;
500
+ break;
501
+ }
433
502
  case '--help':
434
503
  case '-h':
435
504
  usageAndExit(undefined, flags.silent);
@@ -7,36 +7,152 @@ import { generateHelpersTemplate } from '../utils/helmHelpers.js';
7
7
  import { createFlexibleSubchart } from './flexible-subchart.js';
8
8
  export function generateUmbrellaChart(name) {
9
9
  return `import { App } from 'cdk8s';
10
- import { UmbrellaChart } from 'timonel';
10
+ import { Rutter } from 'timonel';
11
+ import { copyFileSync, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'fs';
12
+ import { join } from 'path';
13
+ import * as jsYaml from 'js-yaml';
11
14
  // Import subcharts - add your subchart imports here
12
15
 
13
- /**
14
- * Synthesizes the umbrella chart with all subcharts
15
- * @param outDir Output directory for generated charts
16
- * @since 2.11.0
17
- */
18
- export function synth(outDir: string) {
16
+ type SynthMode = 'dependencies' | 'inline';
17
+
18
+ interface SynthOptions {
19
+ mode?: SynthMode;
20
+ }
21
+
22
+ const DEFAULT_MODE: SynthMode = 'dependencies';
23
+
24
+ const SUBCHARTS: Array<{ name: string; factory: () => Rutter }> = [
25
+ // Add your subcharts here:
26
+ // { name: 'my-subchart', factory: mySubchart },
27
+ ];
28
+
29
+ function resolveMode(options?: SynthOptions): SynthMode {
30
+ const explicit = options?.mode;
31
+ if (explicit === 'dependencies' || explicit === 'inline') {
32
+ return explicit;
33
+ }
34
+ const envMode = process.env.TIMONEL_UMBRELLA_MODE;
35
+ if (envMode === 'dependencies' || envMode === 'inline') {
36
+ return envMode;
37
+ }
38
+ return DEFAULT_MODE;
39
+ }
40
+
41
+ function readYamlFile(filePath: string): Record<string, unknown> {
42
+ if (!existsSync(filePath)) {
43
+ return {};
44
+ }
45
+ const content = jsYaml.load(readFileSync(filePath, 'utf8'));
46
+ return content && typeof content === 'object' ? (content as Record<string, unknown>) : {};
47
+ }
48
+
49
+ export function synth(outDir: string, options?: SynthOptions) {
50
+ const mode = resolveMode(options);
19
51
  const app = new App({
20
52
  outdir: outDir,
21
53
  outputFileExtension: '.yaml',
22
- yamlOutputType: 'FILE_PER_RESOURCE'
54
+ yamlOutputType: 'FILE_PER_RESOURCE',
23
55
  });
24
56
 
25
- const chart = new UmbrellaChart(app, '${name}', {
26
- name: '${name}',
27
- version: '0.1.0',
28
- description: '${name} umbrella chart',
29
- services: [],
30
- subcharts: [
31
- // Add your subcharts here:
32
- ]
57
+ const umbrella = new Rutter({
58
+ meta: {
59
+ name: '${name}',
60
+ version: '0.1.0',
61
+ description: '${name} umbrella chart',
62
+ appVersion: '1.0.0',
63
+ type: 'application',
64
+ },
65
+ scope: app,
66
+ defaultValues: {
67
+ namespace: 'default',
68
+ createNamespace: false,
69
+ },
33
70
  });
34
71
 
35
- // Generate Helm chart files
36
- chart.writeHelmChart(outDir);
37
-
38
- // Also generate CDK8s YAML files
72
+ umbrella.addConditionalManifest(
73
+ {
74
+ apiVersion: 'v1',
75
+ kind: 'Namespace',
76
+ metadata: {
77
+ name: '{{ .Values.namespace | default .Release.Namespace }}',
78
+ },
79
+ },
80
+ 'createNamespace',
81
+ 'namespace',
82
+ );
83
+
84
+ umbrella.write(outDir);
85
+
86
+ const chartPath = join(outDir, 'Chart.yaml');
87
+ const valuesPath = join(outDir, 'values.yaml');
88
+ const templatesDir = join(outDir, 'templates');
89
+ mkdirSync(templatesDir, { recursive: true });
90
+
91
+ const chartDoc = readYamlFile(chartPath);
92
+ const valuesDoc = readYamlFile(valuesPath);
93
+
94
+ if (mode === 'dependencies') {
95
+ const chartsDir = join(outDir, 'charts');
96
+ mkdirSync(chartsDir, { recursive: true });
97
+
98
+ const dependencies: Array<{ name: string; version: string; repository: string }> = [];
99
+
100
+ SUBCHARTS.forEach((subchart) => {
101
+ const instance = subchart.factory();
102
+ const targetDir = join(chartsDir, subchart.name);
103
+ rmSync(targetDir, { recursive: true, force: true });
104
+ instance.write(targetDir);
105
+ const meta = instance.getMeta();
106
+ const version = meta.version ?? '0.1.0';
107
+ dependencies.push({
108
+ name: subchart.name,
109
+ version,
110
+ repository: 'file://./charts/' + subchart.name,
111
+ });
112
+ const subchartValues = readYamlFile(join(targetDir, 'values.yaml'));
113
+ if (Object.keys(subchartValues).length > 0) {
114
+ valuesDoc[subchart.name] = subchartValues;
115
+ }
116
+ });
117
+
118
+ chartDoc.dependencies = dependencies;
119
+ } else {
120
+ const chartsDir = join(outDir, 'charts');
121
+ if (existsSync(chartsDir)) {
122
+ rmSync(chartsDir, { recursive: true, force: true });
123
+ }
124
+ delete chartDoc.dependencies;
125
+
126
+ SUBCHARTS.forEach((subchart) => {
127
+ const instance = subchart.factory();
128
+ const tempDir = join(outDir, '.timonel-inline-' + subchart.name);
129
+ rmSync(tempDir, { recursive: true, force: true });
130
+ instance.write(tempDir);
131
+
132
+ const subTemplatesDir = join(tempDir, 'templates');
133
+ if (existsSync(subTemplatesDir)) {
134
+ const targetTemplatesDir = join(templatesDir, subchart.name);
135
+ mkdirSync(targetTemplatesDir, { recursive: true });
136
+ for (const file of readdirSync(subTemplatesDir)) {
137
+ copyFileSync(join(subTemplatesDir, file), join(targetTemplatesDir, file));
138
+ }
139
+ }
140
+
141
+ const subchartValues = readYamlFile(join(tempDir, 'values.yaml'));
142
+ if (Object.keys(subchartValues).length > 0) {
143
+ valuesDoc[subchart.name] = subchartValues;
144
+ }
145
+
146
+ rmSync(tempDir, { recursive: true, force: true });
147
+ });
148
+ }
149
+
150
+ writeFileSync(chartPath, jsYaml.dump(chartDoc));
151
+ writeFileSync(valuesPath, jsYaml.dump(valuesDoc));
152
+
39
153
  app.synth();
154
+
155
+ console.log('✅ Umbrella chart generated in ' + mode + ' mode!');
40
156
  }
41
157
 
42
158
  // Auto-execute when run directly
@@ -217,7 +217,7 @@ function isQuotesBalanced(str) {
217
217
  function validateFunctionCalls(_content) {
218
218
  }
219
219
  function checkCommonIssues(yaml, warnings) {
220
- const deprecatedFunctions = ['template', 'default'];
220
+ const deprecatedFunctions = ['template'];
221
221
  for (const func of deprecatedFunctions) {
222
222
  const pattern = new RegExp(`\\{\\{[^}]*\\b${func}\\b[^}]*\\}\\}`, 'g');
223
223
  let match;
@@ -232,7 +232,7 @@ function checkCommonIssues(yaml, warnings) {
232
232
  }
233
233
  }
234
234
  function checkQuotedExpressions(yaml, warnings) {
235
- const quotedPatterns = [/'\(\\{\\{[^}]+\\}\\}\)'/g, /"\(\\{\\{[^}]+\\}\\}\)"/g];
235
+ const quotedPatterns = [/'(\{\{[^}]+\}\})'/g, /"(\{\{[^}]+\}\})"/g];
236
236
  for (const pattern of quotedPatterns) {
237
237
  let match;
238
238
  pattern.lastIndex = 0;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "timonel",
3
3
  "type": "module",
4
- "version": "2.11.0",
4
+ "version": "2.12.1",
5
5
  "description": "Timonel: programmatic Helm chart generator using cdk8s (TypeScript)",
6
6
  "bin": {
7
7
  "timonel": "dist/cli.js",