timonel 3.1.1 → 3.1.2

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.
Files changed (83) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +323 -695
  3. package/dist/cli.js +275 -15
  4. package/dist/index.d.ts +5 -1
  5. package/dist/index.js +12 -0
  6. package/dist/lib/helm.d.ts +471 -0
  7. package/dist/lib/helm.js +483 -0
  8. package/dist/lib/helmChartWriter.d.ts +157 -0
  9. package/dist/lib/helmChartWriter.js +171 -1
  10. package/dist/lib/policy/configurationLoader.d.ts +132 -0
  11. package/dist/lib/policy/configurationLoader.js +132 -0
  12. package/dist/lib/policy/errorContextGenerator.d.ts +89 -0
  13. package/dist/lib/policy/errorContextGenerator.js +99 -2
  14. package/dist/lib/policy/errors.d.ts +35 -0
  15. package/dist/lib/policy/errors.js +36 -0
  16. package/dist/lib/policy/index.d.ts +9 -0
  17. package/dist/lib/policy/index.js +16 -0
  18. package/dist/lib/policy/parallelExecutor.d.ts +90 -0
  19. package/dist/lib/policy/parallelExecutor.js +86 -3
  20. package/dist/lib/policy/pluginLoader.d.ts +92 -0
  21. package/dist/lib/policy/pluginLoader.js +92 -1
  22. package/dist/lib/policy/pluginRegistry.d.ts +54 -0
  23. package/dist/lib/policy/pluginRegistry.js +56 -0
  24. package/dist/lib/policy/policyEngine.d.ts +137 -0
  25. package/dist/lib/policy/policyEngine.js +191 -5
  26. package/dist/lib/policy/resultAggregator.d.ts +46 -0
  27. package/dist/lib/policy/resultAggregator.js +69 -1
  28. package/dist/lib/policy/resultFormatter.d.ts +88 -0
  29. package/dist/lib/policy/resultFormatter.js +101 -0
  30. package/dist/lib/policy/types.d.ts +136 -0
  31. package/dist/lib/policy/types.js +8 -0
  32. package/dist/lib/policy/validationCache.d.ts +146 -0
  33. package/dist/lib/policy/validationCache.js +142 -6
  34. package/dist/lib/resources/baseResourceProvider.d.ts +45 -0
  35. package/dist/lib/resources/baseResourceProvider.js +48 -1
  36. package/dist/lib/resources/cloud/aws/awsResources.d.ts +192 -0
  37. package/dist/lib/resources/cloud/aws/awsResources.js +163 -1
  38. package/dist/lib/resources/cloud/aws/karpenterResources.d.ts +131 -0
  39. package/dist/lib/resources/cloud/aws/karpenterResources.js +77 -0
  40. package/dist/lib/rutter.d.ts +381 -3
  41. package/dist/lib/rutter.js +439 -28
  42. package/dist/lib/security.d.ts +123 -0
  43. package/dist/lib/security.js +162 -4
  44. package/dist/lib/templates/flexible-subchart.d.ts +52 -0
  45. package/dist/lib/templates/flexible-subchart.js +70 -0
  46. package/dist/lib/templates/umbrella-chart.d.ts +27 -0
  47. package/dist/lib/templates/umbrella-chart.js +89 -0
  48. package/dist/lib/types.d.ts +26 -0
  49. package/dist/lib/umbrella.d.ts +23 -0
  50. package/dist/lib/umbrella.js +23 -0
  51. package/dist/lib/umbrellaRutter.d.ts +75 -0
  52. package/dist/lib/umbrellaRutter.js +82 -2
  53. package/dist/lib/utils/envVarsLoader.d.ts +49 -0
  54. package/dist/lib/utils/envVarsLoader.js +53 -0
  55. package/dist/lib/utils/helmConstructSerializer.d.ts +17 -0
  56. package/dist/lib/utils/helmConstructSerializer.js +22 -0
  57. package/dist/lib/utils/helmControlStructures.d.ts +194 -0
  58. package/dist/lib/utils/helmControlStructures.js +180 -0
  59. package/dist/lib/utils/helmHelpers/envHelpers.d.ts +13 -0
  60. package/dist/lib/utils/helmHelpers/envHelpers.js +13 -0
  61. package/dist/lib/utils/helmHelpers/gitopsHelpers.d.ts +13 -0
  62. package/dist/lib/utils/helmHelpers/gitopsHelpers.js +13 -0
  63. package/dist/lib/utils/helmHelpers/index.d.ts +74 -0
  64. package/dist/lib/utils/helmHelpers/index.js +85 -1
  65. package/dist/lib/utils/helmHelpers/observabilityHelpers.d.ts +13 -0
  66. package/dist/lib/utils/helmHelpers/observabilityHelpers.js +13 -0
  67. package/dist/lib/utils/helmHelpers/types.d.ts +23 -0
  68. package/dist/lib/utils/helmHelpers/types.js +4 -0
  69. package/dist/lib/utils/helmHelpers/validationHelpers.d.ts +13 -0
  70. package/dist/lib/utils/helmHelpers/validationHelpers.js +13 -0
  71. package/dist/lib/utils/helmHelpers.d.ts +62 -0
  72. package/dist/lib/utils/helmHelpers.js +77 -0
  73. package/dist/lib/utils/helmYamlSerializer.d.ts +77 -0
  74. package/dist/lib/utils/helmYamlSerializer.js +398 -21
  75. package/dist/lib/utils/logger.d.ts +153 -0
  76. package/dist/lib/utils/logger.js +170 -2
  77. package/dist/lib/utils/valuesRef.d.ts +181 -50
  78. package/dist/lib/utils/valuesRef.js +168 -170
  79. package/dist/lib/validation/inputValidator.d.ts +45 -0
  80. package/dist/lib/validation/inputValidator.js +67 -2
  81. package/dist/types/index.d.ts +34 -0
  82. package/dist/types/index.js +3 -0
  83. package/package.json +31 -38
package/dist/lib/helm.js CHANGED
@@ -1,33 +1,152 @@
1
+ /**
2
+ * @fileoverview Helpers to embed Helm template expressions while staying type-safe in TypeScript.
3
+ * We treat Helm placeholders as opaque strings that will be preserved in YAML.
4
+ * @since 2.8.0+++
5
+ */
1
6
  import { SecurityUtils } from './security.js';
7
+ /**
8
+ * Creates a reference to a value in .Values of Helm
9
+ *
10
+ * Generates a Helm template expression that references a value
11
+ * in the chart's values.yaml file using dot notation.
12
+ *
13
+ * @param {string} path - Path to the value using dot notation (e.g., 'image.tag')
14
+ * @returns {string} Helm template expression (e.g., '{{ .Values.image.tag }}')
15
+ * @throws {Error} If the path is not valid for Helm templates
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * const imageTag = valuesRef('image.tag');
20
+ * // Returns: '{{ .Values.image.tag }}'
21
+ *
22
+ * const replicas = valuesRef('deployment.replicas');
23
+ * // Returns: '{{ .Values.deployment.replicas }}'
24
+ * ```
25
+ *
26
+ * @since 2.8.0+
27
+ */
2
28
  export function valuesRef(path) {
3
29
  if (!isValidHelmPath(path)) {
4
30
  throw new Error(`Invalid Helm template path: ${path}`);
5
31
  }
6
32
  return `{{ .Values.${path} }}`;
7
33
  }
34
+ /**
35
+ * Creates a required reference to a value in .Values of Helm
36
+ *
37
+ * Similar to valuesRef, but uses Helm's 'required' function to
38
+ * ensure the value is present, failing chart rendering if not provided.
39
+ *
40
+ * @param {string} path - Path to the value using dot notation
41
+ * @param {string} [message] - Custom error message if value is missing
42
+ * @returns {string} Helm template expression with required validation
43
+ * @throws {Error} If the path is not valid for Helm templates
44
+ *
45
+ * @example
46
+ * ```typescript
47
+ * const dbPassword = requiredValuesRef('database.password', 'Database password is required');
48
+ * // Returns: '{{ required "Database password is required" .Values.database.password }}'
49
+ *
50
+ * const apiKey = requiredValuesRef('api.key');
51
+ * // Returns: '{{ required "api.key is required" .Values.api.key }}'
52
+ * ```
53
+ *
54
+ * @since 2.8.0+
55
+ */
8
56
  export function requiredValuesRef(path, message) {
9
57
  if (!isValidHelmPath(path)) {
10
58
  throw new Error(`Invalid Helm template path: ${path}`);
11
59
  }
12
60
  const msg = message ?? `${path} is required`;
61
+ // Escape quotes and backslashes in message to prevent template injection
13
62
  const escapedMsg = msg.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
14
63
  return `{{ required "${escapedMsg}" .Values.${path} }}`;
15
64
  }
65
+ /**
66
+ * Validates Helm template path syntax with enhanced security
67
+ *
68
+ * @private
69
+ * @param {string} path - Path to validate
70
+ * @returns {boolean} True if path is valid for Helm templates
71
+ * @since 2.8.0+
72
+ */
16
73
  function isValidHelmPath(path) {
74
+ // Use centralized validation from SecurityUtils
17
75
  return SecurityUtils.isValidHelmTemplatePath(path);
18
76
  }
77
+ /**
78
+ * Built-in Helm references for release and chart metadata
79
+ *
80
+ * Object containing the most common references to Helm's built-in
81
+ * variables for release and chart information.
82
+ *
83
+ * @namespace helm
84
+ * @since 2.8.0+
85
+ *
86
+ * @example
87
+ * ```typescript
88
+ * const deploymentName = `${helm.releaseName}-deployment`;
89
+ * // Uses: '{{ .Release.Name }}-deployment'
90
+ *
91
+ * const version = helm.chartVersion;
92
+ * // Uses: '{{ .Chart.Version }}'
93
+ * ```
94
+ */
19
95
  export const helm = {
96
+ /** Release name: {{ .Release.Name }} */
20
97
  releaseName: '{{ .Release.Name }}',
98
+ /** Chart name: {{ .Chart.Name }} */
21
99
  chartName: '{{ .Chart.Name }}',
100
+ /** Chart version: {{ .Chart.Version }} */
22
101
  chartVersion: '{{ .Chart.Version }}',
102
+ /** Release namespace: {{ .Release.Namespace }} */
23
103
  namespace: '{{ .Release.Namespace }}',
24
104
  };
105
+ /**
106
+ * Quotes a Helm template expression for safe YAML embedding
107
+ *
108
+ * Ensures Helm template expressions are properly quoted to avoid
109
+ * YAML parsing issues when the expression contains special characters.
110
+ *
111
+ * @param {string} expr - Helm template expression to quote
112
+ * @returns {string} Quoted expression if it's a Helm template, otherwise unchanged
113
+ *
114
+ * @example
115
+ * ```typescript
116
+ * const quoted = quote('{{ .Values.image.tag }}');
117
+ * // Returns: "'{{ .Values.image.tag }}'"
118
+ *
119
+ * const normal = quote('nginx:1.21');
120
+ * // Returns: "nginx:1.21"
121
+ * ```
122
+ *
123
+ * @since 2.8.0+
124
+ */
25
125
  export function quote(expr) {
126
+ // ensure Helm templates are quoted to avoid YAML parsing issues
26
127
  if (expr.startsWith('{{') && expr.endsWith('}}')) {
27
128
  return `'${expr}'`;
28
129
  }
29
130
  return expr;
30
131
  }
132
+ /**
133
+ * Indents text by specified number of spaces
134
+ *
135
+ * Helper function that matches Helm's indent function behavior,
136
+ * adding the specified number of spaces to each non-empty line.
137
+ *
138
+ * @param {number} n - Number of spaces to indent
139
+ * @param {string} expr - Text to indent
140
+ * @returns {string} Indented text
141
+ *
142
+ * @example
143
+ * ```typescript
144
+ * const indented = indent(4, 'line1\nline2');
145
+ * // Returns: " line1\n line2"
146
+ * ```
147
+ *
148
+ * @since 2.8.0+
149
+ */
31
150
  export function indent(n, expr) {
32
151
  const spaces = ' '.repeat(n);
33
152
  return expr
@@ -35,6 +154,21 @@ export function indent(n, expr) {
35
154
  .map((l) => (l.trim().length ? spaces + l : l))
36
155
  .join('\n');
37
156
  }
157
+ /**
158
+ * Inserts a call to a named Helm template using template function
159
+ *
160
+ * @param {string} name - Name of the template to call
161
+ * @param {string} [context='.'] - Context to pass to the template
162
+ * @returns {string} Helm template expression
163
+ *
164
+ * @example
165
+ * ```typescript
166
+ * const tmpl = template('myapp.labels');
167
+ * // Returns: '{{ template "myapp.labels" . }}'
168
+ * ```
169
+ *
170
+ * @since 2.8.0+
171
+ */
38
172
  export function template(name, context = '.') {
39
173
  if (!isValidHelmPath(name)) {
40
174
  throw new Error(`Invalid template name: ${name}`);
@@ -44,14 +178,41 @@ export function template(name, context = '.') {
44
178
  }
45
179
  return `{{ template "${name}" ${context} }}`;
46
180
  }
181
+ /**
182
+ * Inserts a call to a named Helm template using include function
183
+ *
184
+ * Preferred over template() as include allows piping and better error handling.
185
+ *
186
+ * @param {string} name - Name of the template to include
187
+ * @param {string} [context='.'] - Context to pass to the template
188
+ * @returns {string} Helm template expression
189
+ *
190
+ * @example
191
+ * ```typescript
192
+ * const tmpl = include('myapp.labels');
193
+ * // Returns: '{{ include "myapp.labels" . }}'
194
+ * ```
195
+ *
196
+ * @since 2.8.0+
197
+ */
47
198
  export function include(name, context = '.') {
48
199
  return `{{ include "${name}" ${context} }}`;
49
200
  }
201
+ /**
202
+ * Factory function to create typed Helm value references with reduced code duplication
203
+ * @param path - The path to the value in the Helm values
204
+ * @param type - The expected type of the value
205
+ * @param options - Additional options for reference creation
206
+ * @returns A string that can be used in Helm templates
207
+ * @throws {Error} If the path is invalid
208
+ * @since 2.8.0+
209
+ */
50
210
  export function createTypedRef(path, type, options = {}) {
51
211
  if (!isValidHelmPath(path)) {
52
212
  throw new Error(`Invalid Helm template path: ${path}`);
53
213
  }
54
214
  let template = `{{ .Values.${path}`;
215
+ // Apply type casting based on type
55
216
  switch (type) {
56
217
  case 'number':
57
218
  template += ' | int';
@@ -66,31 +227,119 @@ export function createTypedRef(path, type, options = {}) {
66
227
  template += ' | float64';
67
228
  break;
68
229
  }
230
+ // Handle default values following Helm best practices
69
231
  if (options.withDefault && options.defaultValue !== undefined) {
70
232
  const defaultVal = typeof options.defaultValue === 'string' && options.quote
71
233
  ? `"${options.defaultValue}"`
72
234
  : String(options.defaultValue);
73
235
  template += ` | default ${defaultVal}`;
74
236
  }
237
+ // Handle string quoting for security
75
238
  if (type === 'string' && options.quote && !options.withDefault) {
76
239
  template += ' | quote';
77
240
  }
78
241
  template += ' }}';
79
242
  return template;
80
243
  }
244
+ /**
245
+ * Creates a numeric reference from .Values with int cast
246
+ *
247
+ * Generates a Helm template expression that casts the value to integer,
248
+ * truncating any decimal places.
249
+ *
250
+ * @param {string} path - Path to the value using dot notation
251
+ * @param {TypedRefOptions} [options] - Additional options for reference creation
252
+ * @returns {string} Helm template expression with int cast
253
+ * @throws {Error} If the path is not valid for Helm templates
254
+ *
255
+ * @example
256
+ * ```typescript
257
+ * const replicas = numberRef('deployment.replicas');
258
+ * // Returns: '{{ .Values.deployment.replicas | int }}'
259
+ * ```
260
+ *
261
+ * @since 2.8.0+
262
+ */
81
263
  export function numberRef(path, options) {
82
264
  return createTypedRef(path, 'number', options);
83
265
  }
266
+ /**
267
+ * Creates a boolean reference from .Values with toBool cast
268
+ *
269
+ * @param {string} path - Path to the value using dot notation
270
+ * @param {TypedRefOptions} [options] - Additional options for reference creation
271
+ * @returns {string} Helm template expression with toBool cast
272
+ * @throws {Error} If the path is not valid for Helm templates
273
+ *
274
+ * @example
275
+ * ```typescript
276
+ * const enabled = boolRef('feature.enabled');
277
+ * // Returns: '{{ .Values.feature.enabled | toBool }}'
278
+ * ```
279
+ *
280
+ * @since 2.8.0+
281
+ */
84
282
  export function boolRef(path, options) {
85
283
  return createTypedRef(path, 'boolean', options);
86
284
  }
285
+ /**
286
+ * Creates a string reference from .Values with toString cast
287
+ *
288
+ * @param {string} path - Path to the value using dot notation
289
+ * @param {TypedRefOptions} [options] - Additional options for reference creation
290
+ * @returns {string} Helm template expression with toString cast
291
+ * @throws {Error} If the path is not valid for Helm templates
292
+ *
293
+ * @example
294
+ * ```typescript
295
+ * const version = stringRef('app.version');
296
+ * // Returns: '{{ .Values.app.version | toString }}'
297
+ * ```
298
+ *
299
+ * @since 2.8.0+
300
+ */
87
301
  export function stringRef(path, options) {
88
302
  const defaultOptions = { quote: true, ...options };
89
303
  return createTypedRef(path, 'string', defaultOptions);
90
304
  }
305
+ /**
306
+ * Creates a float reference from .Values with float64 cast
307
+ *
308
+ * @param {string} path - Path to the value using dot notation
309
+ * @param {TypedRefOptions} [options] - Additional options for reference creation
310
+ * @returns {string} Helm template expression with float64 cast
311
+ * @throws {Error} If the path is not valid for Helm templates
312
+ *
313
+ * @example
314
+ * ```typescript
315
+ * const ratio = floatRef('scaling.ratio');
316
+ * // Returns: '{{ .Values.scaling.ratio | float64 }}'
317
+ * ```
318
+ *
319
+ * @since 2.8.0+
320
+ */
91
321
  export function floatRef(path, options) {
92
322
  return createTypedRef(path, 'float', options);
93
323
  }
324
+ /**
325
+ * Creates a conditional reference to a value in .Values
326
+ *
327
+ * Generates a Helm template expression that conditionally renders
328
+ * the value only if the condition is truthy.
329
+ *
330
+ * @param {string} path - Path to the value using dot notation
331
+ * @param {string} condition - Path to the condition value
332
+ * @returns {string} Helm template expression with conditional logic
333
+ * @throws {Error} If the path or condition is not valid for Helm templates
334
+ *
335
+ * @example
336
+ * ```typescript
337
+ * const secretName = conditionalRef('database.secretName', 'database.enabled');
338
+ * // Returns: '{{ if .Values.database.enabled }}{{ .Values.database.secretName }}{{ end }}'
339
+ * ```
340
+ *
341
+ * @since 2.8.0+
342
+ */
94
343
  export function conditionalRef(path, condition) {
95
344
  if (!isValidHelmPath(path)) {
96
345
  throw new Error(`Invalid Helm template path: ${path}`);
@@ -100,38 +349,165 @@ export function conditionalRef(path, condition) {
100
349
  }
101
350
  return `{{ if .Values.${condition} }}{{ .Values.${path} }}{{ end }}`;
102
351
  }
352
+ /**
353
+ * Wraps a complete YAML manifest in a Helm conditional
354
+ *
355
+ * Generates a Helm template that conditionally renders an entire
356
+ * Kubernetes manifest based on a values condition.
357
+ *
358
+ * @param {string} yamlContent - Complete YAML manifest content
359
+ * @param {string} condition - Path to the condition value
360
+ * @returns {string} YAML content wrapped in Helm conditional
361
+ * @throws {Error} If the condition path is not valid for Helm templates
362
+ *
363
+ * @example
364
+ * ```typescript
365
+ * const namespaceYaml = `
366
+ * apiVersion: v1
367
+ * kind: Namespace
368
+ * metadata:
369
+ * name: my-namespace
370
+ * `;
371
+ * const conditionalNamespace = conditionalManifest(namespaceYaml, 'createNamespace');
372
+ * // Returns: '{{ if .Values.createNamespace }}\napiVersion: v1\nkind: Namespace...{{ end }}'
373
+ * ```
374
+ *
375
+ * @since 2.8.0+
376
+ */
103
377
  export function conditionalManifest(yamlContent, condition) {
104
378
  if (!isValidHelmPath(condition)) {
105
379
  throw new Error(`Invalid Helm template condition path: ${condition}`);
106
380
  }
381
+ // Remove leading/trailing whitespace and ensure proper formatting
107
382
  const cleanYaml = yamlContent.trim();
108
383
  return `{{ if .Values.${condition} }}
109
384
  ${cleanYaml}
110
385
  {{ end }}`;
111
386
  }
387
+ /**
388
+ * Creates a reference to a value in .Values with a default fallback
389
+ *
390
+ * Generates a Helm template expression that uses the default filter
391
+ * to provide a fallback value when the path is not set.
392
+ *
393
+ * @param {string} path - Path to the value using dot notation
394
+ * @param {string} defaultValue - Default value to use if path is not set
395
+ * @returns {string} Helm template expression with default fallback
396
+ * @throws {Error} If the path is not valid for Helm templates
397
+ *
398
+ * @example
399
+ * ```typescript
400
+ * const image = defaultRef('image.tag', 'latest');
401
+ * // Returns: '{{ .Values.image.tag | default "latest" }}'
402
+ * ```
403
+ *
404
+ * @since 2.8.0+
405
+ */
112
406
  export function defaultRef(path, defaultValue) {
113
407
  if (!isValidHelmPath(path)) {
114
408
  throw new Error(`Invalid Helm template path: ${path}`);
115
409
  }
410
+ // Escape quotes and backslashes in defaultValue to prevent template injection
116
411
  const escapedValue = defaultValue.replace(/\\/g, '\\\\').replace(/"/g, '\\"');
117
412
  return `{{ .Values.${path} | default "${escapedValue}" }}`;
118
413
  }
414
+ /**
415
+ * Creates a base64-encoded reference to a value in .Values
416
+ *
417
+ * Generates a Helm template expression that encodes the value
418
+ * using base64 encoding, useful for secrets and certificates.
419
+ *
420
+ * @param {string} path - Path to the value using dot notation
421
+ * @returns {string} Helm template expression with base64 encoding
422
+ * @throws {Error} If the path is not valid for Helm templates
423
+ *
424
+ * @example
425
+ * ```typescript
426
+ * const encodedSecret = base64Ref('secrets.apiKey');
427
+ * // Returns: '{{ .Values.secrets.apiKey | b64enc }}'
428
+ * ```
429
+ *
430
+ * @since 2.8.0+
431
+ */
119
432
  export function base64Ref(path) {
120
433
  if (!isValidHelmPath(path)) {
121
434
  throw new Error(`Invalid Helm template path: ${path}`);
122
435
  }
123
436
  return `{{ .Values.${path} | b64enc }}`;
124
437
  }
438
+ /**
439
+ * Creates a JSON-serialized reference to a value in .Values
440
+ *
441
+ * Generates a Helm template expression that serializes the value
442
+ * to JSON format, useful for complex configuration objects.
443
+ *
444
+ * @param {string} path - Path to the value using dot notation
445
+ * @returns {string} Helm template expression with JSON serialization
446
+ * @throws {Error} If the path is not valid for Helm templates
447
+ *
448
+ * @example
449
+ * ```typescript
450
+ * const configJson = jsonRef('app.config');
451
+ * // Returns: '{{ .Values.app.config | toJson }}'
452
+ * ```
453
+ *
454
+ * @since 2.6.0
455
+ */
125
456
  export function jsonRef(path) {
126
457
  if (!isValidHelmPath(path)) {
127
458
  throw new Error(`Invalid Helm template path: ${path}`);
128
459
  }
129
460
  return `{{ .Values.${path} | toJson }}`;
130
461
  }
462
+ /**
463
+ * Flow Control Functions for Helm Templates
464
+ *
465
+ * These functions provide programmatic access to Helm's flow control structures:
466
+ * if/else, with, and range for conditional logic and iteration.
467
+ *
468
+ * @since 2.8.0+
469
+ */
470
+ /**
471
+ * Creates a conditional if block in Helm templates
472
+ *
473
+ * Generates Helm template expressions for conditional logic using if/else/end.
474
+ * Supports complex conditions with comparison operators and pipeline expressions.
475
+ *
476
+ * @param {string} condition - The condition to evaluate (e.g., 'eq .Values.env "production"')
477
+ * @param {string} content - Content to include when condition is true
478
+ * @param {string} [elseContent] - Optional content for else block
479
+ * @returns {string} Complete Helm if/else template block
480
+ * @throws {Error} If condition contains potentially unsafe template expressions
481
+ *
482
+ * @example
483
+ * ```typescript
484
+ * const conditionalConfig = helmIf(
485
+ * 'eq .Values.environment "production"',
486
+ * 'replicas: 3\nresources:\n limits:\n memory: "1Gi"',
487
+ * 'replicas: 1\nresources:\n limits:\n memory: "512Mi"'
488
+ * );
489
+ * // Returns:
490
+ * // {{- if eq .Values.environment "production" }}
491
+ * // replicas: 3
492
+ * // resources:
493
+ * // limits:
494
+ * // memory: "1Gi"
495
+ * // {{- else }}
496
+ * // replicas: 1
497
+ * // resources:
498
+ * // limits:
499
+ * // memory: "512Mi"
500
+ * // {{- end }}
501
+ * ```
502
+ *
503
+ * @since 2.8.0
504
+ */
131
505
  export function helmIf(condition, content, elseContent) {
506
+ // Validate condition for basic security
132
507
  if (!condition || condition.trim().length === 0) {
133
508
  throw new Error('Condition cannot be empty');
134
509
  }
510
+ // Basic validation to prevent template injection
135
511
  if (condition.includes('{{') || condition.includes('}}')) {
136
512
  throw new Error('Condition should not contain template delimiters');
137
513
  }
@@ -142,10 +518,44 @@ export function helmIf(condition, content, elseContent) {
142
518
  result += `\n{{- end }}`;
143
519
  return result;
144
520
  }
521
+ /**
522
+ * Creates a with block for scoped template context
523
+ *
524
+ * Generates Helm template expressions using 'with' to change the template context.
525
+ * Useful for accessing nested values without repeating the full path.
526
+ *
527
+ * @param {string} path - Path to set as new context (e.g., '.Values.database')
528
+ * @param {string} content - Content to render within the new context
529
+ * @param {string} [elseContent] - Optional content when path is empty/nil
530
+ * @returns {string} Complete Helm with/else/end template block
531
+ * @throws {Error} If path is not valid for Helm templates
532
+ *
533
+ * @example
534
+ * ```typescript
535
+ * const dbConfig = helmWith(
536
+ * '.Values.database',
537
+ * 'host: {{ .host }}\nport: {{ .port }}\nname: {{ .name }}',
538
+ * 'host: "localhost"\nport: 5432\nname: "defaultdb"'
539
+ * );
540
+ * // Returns:
541
+ * // {{- with .Values.database }}
542
+ * // host: {{ .host }}
543
+ * // port: {{ .port }}
544
+ * // name: {{ .name }}
545
+ * // {{- else }}
546
+ * // host: "localhost"
547
+ * // port: 5432
548
+ * // name: "defaultdb"
549
+ * // {{- end }}
550
+ * ```
551
+ *
552
+ * @since 2.8.0
553
+ */
145
554
  export function helmWith(path, content, elseContent) {
146
555
  if (!path || path.trim().length === 0) {
147
556
  throw new Error('Path cannot be empty');
148
557
  }
558
+ // Validate path format
149
559
  if (!path.startsWith('.')) {
150
560
  throw new Error('Path must start with "." (e.g., ".Values.config")');
151
561
  }
@@ -156,6 +566,48 @@ export function helmWith(path, content, elseContent) {
156
566
  result += `\n{{- end }}`;
157
567
  return result;
158
568
  }
569
+ /**
570
+ * Creates a range loop for iterating over collections
571
+ *
572
+ * Generates Helm template expressions using 'range' to iterate over lists, maps, or other collections.
573
+ * Supports both simple iteration and key-value iteration for maps.
574
+ *
575
+ * @param {string} collection - Collection to iterate over (e.g., '.Values.items')
576
+ * @param {string} content - Content template for each iteration
577
+ * @param {object} [options] - Configuration options for the range loop
578
+ * @param {boolean} [options.keyValue=false] - Whether to iterate with key-value pairs
579
+ * @param {string} [options.keyVar='$key'] - Variable name for keys in key-value iteration
580
+ * @param {string} [options.valueVar='$value'] - Variable name for values in key-value iteration
581
+ * @param {string} [options.indexVar='$index'] - Variable name for index in indexed iteration
582
+ * @param {string} [options.itemVar='$item'] - Variable name for items in simple iteration
583
+ * @returns {string} Complete Helm range/end template block
584
+ * @throws {Error} If collection path is not valid
585
+ *
586
+ * @example
587
+ * ```typescript
588
+ * // Simple list iteration
589
+ * const serviceList = helmRange(
590
+ * '.Values.services',
591
+ * '- name: {{ .name }}\n port: {{ .port }}'
592
+ * );
593
+ *
594
+ * // Key-value map iteration
595
+ * const envVars = helmRange(
596
+ * '.Values.env',
597
+ * '- name: {{ $key }}\n value: {{ $value | quote }}',
598
+ * { keyValue: true }
599
+ * );
600
+ *
601
+ * // Indexed iteration
602
+ * const indexedItems = helmRange(
603
+ * '.Values.items',
604
+ * '{{ $index }}: {{ $item }}',
605
+ * { indexVar: '$i', itemVar: '$val' }
606
+ * );
607
+ * ```
608
+ *
609
+ * @since 2.8.0
610
+ */
159
611
  export function helmRange(collection, content, options = {}) {
160
612
  if (!collection || collection.trim().length === 0) {
161
613
  throw new Error('Collection cannot be empty');
@@ -163,10 +615,12 @@ export function helmRange(collection, content, options = {}) {
163
615
  if (!collection.startsWith('.')) {
164
616
  throw new Error('Collection path must start with "." (e.g., ".Values.items")');
165
617
  }
618
+ // Validate collection path to prevent template injection
166
619
  if (!isValidHelmPath(collection)) {
167
620
  throw new Error(`Invalid collection path: ${collection}`);
168
621
  }
169
622
  const { keyValue = false, keyVar = '$key', valueVar = '$value', indexVar = '$index', itemVar = '$item', } = options;
623
+ // Validate variable names to prevent injection
170
624
  const validateVarName = (varName, varType) => {
171
625
  if (!varName.startsWith('$')) {
172
626
  throw new Error(`${varType} must start with $ (e.g., $key, $value)`);
@@ -175,6 +629,7 @@ export function helmRange(collection, content, options = {}) {
175
629
  throw new Error(`Invalid ${varType}: ${varName}`);
176
630
  }
177
631
  };
632
+ // Validate all variable names that will be used
178
633
  if (keyValue) {
179
634
  validateVarName(keyVar, 'keyVar');
180
635
  validateVarName(valueVar, 'valueVar');
@@ -197,6 +652,33 @@ export function helmRange(collection, content, options = {}) {
197
652
  }
198
653
  return `${rangeExpression}\n${content}\n{{- end }}`;
199
654
  }
655
+ /**
656
+ * Creates a complex conditional with multiple else-if branches
657
+ *
658
+ * Generates Helm template expressions for complex conditional logic with multiple branches.
659
+ * Useful for handling multiple environment configurations or feature flags.
660
+ *
661
+ * @param {Array<{condition: string, content: string}>} branches - Array of condition-content pairs
662
+ * @param {string} [defaultContent] - Default content when no conditions match
663
+ * @returns {string} Complete Helm if/else-if/else/end template block
664
+ * @throws {Error} If branches array is empty or contains invalid conditions
665
+ *
666
+ * @example
667
+ * ```typescript
668
+ * const envConfig = helmIfElseIf([
669
+ * {
670
+ * condition: 'eq .Values.environment "production"',
671
+ * content: 'replicas: 5\nresources.limits.memory: "2Gi"'
672
+ * },
673
+ * {
674
+ * condition: 'eq .Values.environment "staging"',
675
+ * content: 'replicas: 2\nresources.limits.memory: "1Gi"'
676
+ * }
677
+ * ], 'replicas: 1\nresources.limits.memory: "512Mi"');
678
+ * ```
679
+ *
680
+ * @since 2.8.0
681
+ */
200
682
  export function helmIfElseIf(branches, defaultContent) {
201
683
  if (!branches || branches.length === 0) {
202
684
  throw new Error('At least one branch is required');
@@ -206,6 +688,7 @@ export function helmIfElseIf(branches, defaultContent) {
206
688
  if (!branch.condition || branch.condition.trim().length === 0) {
207
689
  throw new Error(`Branch ${index} condition cannot be empty`);
208
690
  }
691
+ // Basic validation to prevent template injection
209
692
  if (branch.condition.includes('{{') || branch.condition.includes('}}')) {
210
693
  throw new Error(`Branch ${index} condition should not contain template delimiters`);
211
694
  }