@intentius/chant-lexicon-helm 0.46.0 → 0.49.0

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 (118) hide show
  1. package/dist/archive-render.d.ts +94 -0
  2. package/dist/archive-render.d.ts.map +1 -0
  3. package/dist/commands.d.ts +54 -0
  4. package/dist/commands.d.ts.map +1 -0
  5. package/dist/config.d.ts +135 -0
  6. package/dist/config.d.ts.map +1 -0
  7. package/dist/deep-observe-hooks.d.ts +2 -0
  8. package/dist/deep-observe-hooks.d.ts.map +1 -0
  9. package/dist/deep-observe.d.ts +54 -0
  10. package/dist/deep-observe.d.ts.map +1 -0
  11. package/dist/describe-resources.d.ts +17 -0
  12. package/dist/describe-resources.d.ts.map +1 -0
  13. package/dist/index.d.ts +18 -2
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/integrity.json +5 -3
  16. package/dist/lint/audit-catalog.d.ts.map +1 -1
  17. package/dist/lint/post-synth/index.d.ts.map +1 -1
  18. package/dist/lint/post-synth/whm503.d.ts +34 -0
  19. package/dist/lint/post-synth/whm503.d.ts.map +1 -0
  20. package/dist/lint/post-synth/whm504.d.ts +20 -0
  21. package/dist/lint/post-synth/whm504.d.ts.map +1 -0
  22. package/dist/manifest.json +1 -1
  23. package/dist/okf/index.md +2 -0
  24. package/dist/okf/rules/WHM503.md +15 -0
  25. package/dist/okf/rules/WHM504.md +11 -0
  26. package/dist/okf/types/Values.md +1 -0
  27. package/dist/op/activities/cluster-probe.d.ts +44 -0
  28. package/dist/op/activities/cluster-probe.d.ts.map +1 -0
  29. package/dist/op/activities/helm.d.ts +179 -5
  30. package/dist/op/activities/helm.d.ts.map +1 -1
  31. package/dist/op/activities/index.d.ts +4 -2
  32. package/dist/op/activities/index.d.ts.map +1 -1
  33. package/dist/pinnability/actions.d.ts +76 -0
  34. package/dist/pinnability/actions.d.ts.map +1 -0
  35. package/dist/pinnability/classify.d.ts +129 -0
  36. package/dist/pinnability/classify.d.ts.map +1 -0
  37. package/dist/pinnability/conditions.d.ts +109 -0
  38. package/dist/pinnability/conditions.d.ts.map +1 -0
  39. package/dist/pinnability/index.d.ts +17 -0
  40. package/dist/pinnability/index.d.ts.map +1 -0
  41. package/dist/pinnability/localize.d.ts +124 -0
  42. package/dist/pinnability/localize.d.ts.map +1 -0
  43. package/dist/pinnability/render-stream.d.ts +27 -0
  44. package/dist/pinnability/render-stream.d.ts.map +1 -0
  45. package/dist/pinnability/values.d.ts +69 -0
  46. package/dist/pinnability/values.d.ts.map +1 -0
  47. package/dist/plugin.d.ts.map +1 -1
  48. package/dist/release-observe.d.ts +109 -0
  49. package/dist/release-observe.d.ts.map +1 -0
  50. package/dist/render-diff.d.ts +192 -0
  51. package/dist/render-diff.d.ts.map +1 -0
  52. package/dist/render-digest.d.ts +135 -0
  53. package/dist/render-digest.d.ts.map +1 -0
  54. package/dist/render-store.d.ts +310 -0
  55. package/dist/render-store.d.ts.map +1 -0
  56. package/dist/render-wrapper.d.ts +140 -0
  57. package/dist/render-wrapper.d.ts.map +1 -0
  58. package/dist/render.d.ts +81 -0
  59. package/dist/render.d.ts.map +1 -1
  60. package/dist/rules/whm503.ts +101 -0
  61. package/dist/rules/whm504.ts +52 -0
  62. package/dist/skills/chant-helm.md +7 -0
  63. package/dist/values-probe.d.ts +177 -0
  64. package/dist/values-probe.d.ts.map +1 -0
  65. package/dist/wrapper-chart.d.ts +61 -0
  66. package/dist/wrapper-chart.d.ts.map +1 -0
  67. package/package.json +10 -4
  68. package/src/archive-render.test.ts +201 -0
  69. package/src/archive-render.ts +119 -0
  70. package/src/commands.test.ts +487 -0
  71. package/src/commands.ts +445 -0
  72. package/src/config.test.ts +130 -0
  73. package/src/config.ts +220 -0
  74. package/src/deep-observe-hooks.ts +20 -0
  75. package/src/deep-observe.test.ts +165 -0
  76. package/src/deep-observe.ts +121 -0
  77. package/src/describe-resources.test.ts +255 -0
  78. package/src/describe-resources.ts +198 -0
  79. package/src/index.ts +98 -2
  80. package/src/lifecycle-integration.test.ts +289 -0
  81. package/src/lint/audit-catalog.ts +2 -0
  82. package/src/lint/post-synth/index.ts +4 -0
  83. package/src/lint/post-synth/whm503.test.ts +134 -0
  84. package/src/lint/post-synth/whm503.ts +101 -0
  85. package/src/lint/post-synth/whm504.test.ts +105 -0
  86. package/src/lint/post-synth/whm504.ts +52 -0
  87. package/src/op/activities/cluster-probe.test.ts +66 -0
  88. package/src/op/activities/cluster-probe.ts +148 -0
  89. package/src/op/activities/helm.test.ts +824 -0
  90. package/src/op/activities/helm.ts +628 -5
  91. package/src/op/activities/index.ts +17 -2
  92. package/src/pinnability/actions.ts +263 -0
  93. package/src/pinnability/classify.ts +579 -0
  94. package/src/pinnability/conditions.ts +0 -0
  95. package/src/pinnability/index.ts +77 -0
  96. package/src/pinnability/localize.test.ts +234 -0
  97. package/src/pinnability/localize.ts +644 -0
  98. package/src/pinnability/pinnability.test.ts +560 -0
  99. package/src/pinnability/render-stream.ts +59 -0
  100. package/src/pinnability/values.ts +205 -0
  101. package/src/plugin.test.ts +3 -1
  102. package/src/plugin.ts +47 -0
  103. package/src/release-observe.ts +392 -0
  104. package/src/render-diff.test.ts +366 -0
  105. package/src/render-diff.ts +407 -0
  106. package/src/render-digest.test.ts +186 -0
  107. package/src/render-digest.ts +207 -0
  108. package/src/render-store.test.ts +412 -0
  109. package/src/render-store.ts +621 -0
  110. package/src/render-wrapper.test.ts +259 -0
  111. package/src/render-wrapper.ts +274 -0
  112. package/src/render.test.ts +383 -4
  113. package/src/render.ts +319 -8
  114. package/src/skills/chant-helm.md +7 -0
  115. package/src/values-probe.test.ts +400 -0
  116. package/src/values-probe.ts +627 -0
  117. package/src/wrapper-chart.test.ts +110 -0
  118. package/src/wrapper-chart.ts +124 -0
@@ -0,0 +1,263 @@
1
+ /**
2
+ * Go template action extraction and control-flow scoping (#1234, epic #1228).
3
+ *
4
+ * The pinnability gate inspects template ACTIONS (`{{ ... }}`), never raw
5
+ * text. That distinction is finding 9: cert-manager carries 52 textual
6
+ * "lookup" occurrences, all comment prose, and a real template-action count
7
+ * of 0 — a text-matching gate refuses a chart that is perfectly pinnable.
8
+ *
9
+ * Beyond extraction, this module reconstructs the control-flow structure of a
10
+ * template file — which `if` / `with` / `range` blocks enclose each action —
11
+ * so the classifier can ask whether a construct is REACHABLE under the
12
+ * supplied values, not merely present. Reachability is what separates
13
+ * "unpinnable" from "pinnable with a recorded conditional hazard": bundled
14
+ * grafana's control-flow `lookup` sits behind `persistence.enabled`, off by
15
+ * default, so a default-values render never consults the cluster.
16
+ */
17
+
18
+ export type ActionKind =
19
+ | "if"
20
+ | "elseif"
21
+ | "else"
22
+ | "with"
23
+ | "range"
24
+ | "define"
25
+ | "block"
26
+ | "end"
27
+ | "other";
28
+
29
+ export interface TemplateAction {
30
+ /** Path of the file the action was found in (as given by the caller). */
31
+ file: string;
32
+ /** 1-based line the action starts on. */
33
+ line: number;
34
+ /** The action body between `{{` and `}}`, trim markers stripped. */
35
+ body: string;
36
+ /** Structural role of the action, from its leading keyword. */
37
+ kind: ActionKind;
38
+ }
39
+
40
+ /**
41
+ * One enclosing control-flow frame for an action. `conditions` are the
42
+ * expressions that must hold for the frame's branch to run; `negatedConditions`
43
+ * are prior branch conditions that must NOT hold (an `else` / `else if`
44
+ * branch runs only when every earlier branch condition was false).
45
+ */
46
+ export interface ScopeFrame {
47
+ kind: "if" | "with" | "range" | "define" | "block" | "dependency-condition";
48
+ conditions: string[];
49
+ negatedConditions: string[];
50
+ /**
51
+ * When a `with` block pins the dot to a `.Values` subtree, the path of that
52
+ * subtree — so bare `.enabled` inside `with .Values.persistence` resolves
53
+ * to `persistence.enabled`. `undefined` means the dot is unresolvable
54
+ * (a `range` element, a non-values `with`, a `define` invoked from an
55
+ * unknown context).
56
+ */
57
+ dotValuesPath?: string[];
58
+ /** Dot is rebound to something we cannot resolve (range element etc.). */
59
+ dotUnresolvable?: boolean;
60
+ }
61
+
62
+ export interface ScopedAction {
63
+ action: TemplateAction;
64
+ /** Enclosing frames, outermost first. Empty for top-level actions. */
65
+ frames: ScopeFrame[];
66
+ }
67
+
68
+ const KIND_RE =
69
+ /^(if\b|else\s+if\b|else\b|with\b|range\b|define\b|block\b|end\b)/;
70
+
71
+ function kindOf(body: string): ActionKind {
72
+ const m = body.match(KIND_RE);
73
+ if (!m) return "other";
74
+ const kw = m[1].replace(/\s+/g, " ").trim();
75
+ if (kw === "else if") return "elseif";
76
+ return kw.replace(/\b\s.*$/, "") as ActionKind;
77
+ }
78
+
79
+ /**
80
+ * Extract template actions from a source file, skipping comment actions
81
+ * (`{{/* ... *\/}}`). Text outside actions — including YAML `#` comments,
82
+ * where finding 9's 52 false positives lived — is never inspected by any
83
+ * scan built on this.
84
+ */
85
+ export function extractActions(source: string, file: string): TemplateAction[] {
86
+ const actions: TemplateAction[] = [];
87
+ let i = 0;
88
+ let line = 1;
89
+ let lineScanPos = 0;
90
+ const lineAt = (pos: number): number => {
91
+ // Incremental line counting: `pos` is monotonically increasing.
92
+ for (; lineScanPos < pos; lineScanPos++) {
93
+ if (source[lineScanPos] === "\n") line += 1;
94
+ }
95
+ return line;
96
+ };
97
+ while (i < source.length) {
98
+ const open = source.indexOf("{{", i);
99
+ if (open === -1) break;
100
+ const actionLine = lineAt(open);
101
+ // Body starts after `{{` and an optional trim marker.
102
+ let bodyStart = open + 2;
103
+ if (source[bodyStart] === "-") bodyStart += 1;
104
+ const rest = source.slice(bodyStart);
105
+ // Comment action: {{/* ... */}} — skip to its closing */}}.
106
+ if (/^\s*\/\*/.test(rest)) {
107
+ const closeComment = source.indexOf("*/", bodyStart);
108
+ if (closeComment === -1) break;
109
+ const close = source.indexOf("}}", closeComment);
110
+ i = close === -1 ? source.length : close + 2;
111
+ continue;
112
+ }
113
+ const close = source.indexOf("}}", bodyStart);
114
+ if (close === -1) break;
115
+ let body = source.slice(bodyStart, close);
116
+ if (body.endsWith("-")) body = body.slice(0, -1);
117
+ body = body.trim();
118
+ actions.push({ file, line: actionLine, body, kind: kindOf(body) });
119
+ i = close + 2;
120
+ }
121
+ return actions;
122
+ }
123
+
124
+ /**
125
+ * The pipeline of an action, structural keyword and variable assignment
126
+ * stripped: `if X` → `X`, `range $i, $v := X` → `X`, `$pw := X` → `X`.
127
+ * This is what condition evaluation and call-reachability parse.
128
+ */
129
+ export function actionPipeline(action: TemplateAction): string {
130
+ let expr = action.body.replace(KIND_RE, "").trim();
131
+ // `range $i, $v := .Values.x` / `$pw := .Values.x` — the pipeline is what
132
+ // follows the assignment.
133
+ const assign = expr.match(/^\$[\w]*\s*(?:,\s*\$[\w]*\s*)?:?=\s*(.*)$/);
134
+ if (assign) expr = assign[1].trim();
135
+ return expr;
136
+ }
137
+
138
+
139
+ /** `.Values.a.b` (or `$.Values.a.b`) as a path array, else undefined. */
140
+ function valuesPathOf(expr: string): string[] | undefined {
141
+ const m = expr.match(/^\$?\.Values((?:\.[A-Za-z0-9_-]+)+)$/);
142
+ return m ? m[1].slice(1).split(".") : undefined;
143
+ }
144
+
145
+ interface BranchState {
146
+ frame: ScopeFrame;
147
+ /** All branch conditions seen so far in this if-chain. */
148
+ chain: string[];
149
+ }
150
+
151
+ /**
152
+ * Walk a file's actions and attach the enclosing control-flow frames to each.
153
+ * `else` / `else if` branches carry the prior branch conditions as
154
+ * `negatedConditions`. Structure that cannot be tracked (an unbalanced
155
+ * `end`, template text split across files) degrades to fewer frames — which
156
+ * only ever makes the classifier MORE conservative, never less: a missing
157
+ * frame means a gate we cannot prove closed.
158
+ */
159
+ export function scopeActions(actions: TemplateAction[]): ScopedAction[] {
160
+ const scoped: ScopedAction[] = [];
161
+ const stack: BranchState[] = [];
162
+
163
+ for (const action of actions) {
164
+ switch (action.kind) {
165
+ case "if": {
166
+ const cond = actionPipeline(action);
167
+ // The `if` action itself is evaluated in the ENCLOSING scope.
168
+ scoped.push({ action, frames: stack.map((s) => s.frame) });
169
+ stack.push({
170
+ frame: { kind: "if", conditions: [cond], negatedConditions: [] },
171
+ chain: [cond],
172
+ });
173
+ break;
174
+ }
175
+ case "elseif": {
176
+ scoped.push({
177
+ action,
178
+ frames: stack.slice(0, -1).map((s) => s.frame),
179
+ });
180
+ const top = stack[stack.length - 1];
181
+ const cond = action.body.replace(/^else\s+if\b/, "").trim();
182
+ if (top) {
183
+ top.frame = {
184
+ kind: "if",
185
+ conditions: [cond],
186
+ negatedConditions: [...top.chain],
187
+ };
188
+ top.chain.push(cond);
189
+ }
190
+ break;
191
+ }
192
+ case "else": {
193
+ scoped.push({
194
+ action,
195
+ frames: stack.slice(0, -1).map((s) => s.frame),
196
+ });
197
+ const top = stack[stack.length - 1];
198
+ if (top) {
199
+ top.frame = {
200
+ kind: top.frame.kind === "if" ? "if" : top.frame.kind,
201
+ conditions: [],
202
+ negatedConditions: [...top.chain],
203
+ };
204
+ }
205
+ break;
206
+ }
207
+ case "with": {
208
+ const expr = actionPipeline(action);
209
+ scoped.push({ action, frames: stack.map((s) => s.frame) });
210
+ const path = valuesPathOf(expr);
211
+ stack.push({
212
+ frame: {
213
+ kind: "with",
214
+ conditions: [expr],
215
+ negatedConditions: [],
216
+ dotValuesPath: path,
217
+ dotUnresolvable: path === undefined,
218
+ },
219
+ chain: [expr],
220
+ });
221
+ break;
222
+ }
223
+ case "range": {
224
+ const expr = actionPipeline(action);
225
+ scoped.push({ action, frames: stack.map((s) => s.frame) });
226
+ stack.push({
227
+ frame: {
228
+ kind: "range",
229
+ conditions: [expr],
230
+ negatedConditions: [],
231
+ dotUnresolvable: true,
232
+ },
233
+ chain: [expr],
234
+ });
235
+ break;
236
+ }
237
+ case "define":
238
+ case "block": {
239
+ scoped.push({ action, frames: stack.map((s) => s.frame) });
240
+ // A define body runs with whatever context `include`/`template`
241
+ // passes. Most charts pass the root context; the frame records
242
+ // nothing to gate on, so constructs inside a define are treated as
243
+ // reachable unless gated within the define itself.
244
+ stack.push({
245
+ frame: { kind: action.kind, conditions: [], negatedConditions: [] },
246
+ chain: [],
247
+ });
248
+ break;
249
+ }
250
+ case "end": {
251
+ scoped.push({
252
+ action,
253
+ frames: stack.slice(0, -1).map((s) => s.frame),
254
+ });
255
+ stack.pop();
256
+ break;
257
+ }
258
+ default:
259
+ scoped.push({ action, frames: stack.map((s) => s.frame) });
260
+ }
261
+ }
262
+ return scoped;
263
+ }