@gitwand/core 2.0.1 → 2.2.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 (128) hide show
  1. package/README.md +58 -0
  2. package/dist/__tests__/bench.bench.js +39 -0
  3. package/dist/__tests__/bench.bench.js.map +1 -1
  4. package/dist/__tests__/corpus.d.ts.map +1 -1
  5. package/dist/__tests__/corpus.js +363 -0
  6. package/dist/__tests__/corpus.js.map +1 -1
  7. package/dist/__tests__/diff/block-move.test.d.ts +5 -0
  8. package/dist/__tests__/diff/block-move.test.d.ts.map +1 -0
  9. package/dist/__tests__/diff/block-move.test.js +132 -0
  10. package/dist/__tests__/diff/block-move.test.js.map +1 -0
  11. package/dist/__tests__/diff/histogram.test.d.ts +8 -0
  12. package/dist/__tests__/diff/histogram.test.d.ts.map +1 -0
  13. package/dist/__tests__/diff/histogram.test.js +150 -0
  14. package/dist/__tests__/diff/histogram.test.js.map +1 -0
  15. package/dist/__tests__/diff/parity.test.d.ts +17 -0
  16. package/dist/__tests__/diff/parity.test.d.ts.map +1 -0
  17. package/dist/__tests__/diff/parity.test.js +149 -0
  18. package/dist/__tests__/diff/parity.test.js.map +1 -0
  19. package/dist/__tests__/diff.test.js +6 -2
  20. package/dist/__tests__/diff.test.js.map +1 -1
  21. package/dist/__tests__/format-profiles/integration.test.d.ts +7 -0
  22. package/dist/__tests__/format-profiles/integration.test.d.ts.map +1 -0
  23. package/dist/__tests__/format-profiles/integration.test.js +193 -0
  24. package/dist/__tests__/format-profiles/integration.test.js.map +1 -0
  25. package/dist/__tests__/format-profiles/json-patch.test.d.ts +12 -0
  26. package/dist/__tests__/format-profiles/json-patch.test.d.ts.map +1 -0
  27. package/dist/__tests__/format-profiles/json-patch.test.js +222 -0
  28. package/dist/__tests__/format-profiles/json-patch.test.js.map +1 -0
  29. package/dist/__tests__/format-profiles/registry.test.d.ts +5 -0
  30. package/dist/__tests__/format-profiles/registry.test.d.ts.map +1 -0
  31. package/dist/__tests__/format-profiles/registry.test.js +124 -0
  32. package/dist/__tests__/format-profiles/registry.test.js.map +1 -0
  33. package/dist/__tests__/patterns/make-score.test.d.ts +9 -0
  34. package/dist/__tests__/patterns/make-score.test.d.ts.map +1 -0
  35. package/dist/__tests__/patterns/make-score.test.js +49 -0
  36. package/dist/__tests__/patterns/make-score.test.js.map +1 -0
  37. package/dist/diff/block-move.d.ts +53 -0
  38. package/dist/diff/block-move.d.ts.map +1 -0
  39. package/dist/diff/block-move.js +192 -0
  40. package/dist/diff/block-move.js.map +1 -0
  41. package/dist/diff/histogram.d.ts +45 -0
  42. package/dist/diff/histogram.d.ts.map +1 -0
  43. package/dist/diff/histogram.js +172 -0
  44. package/dist/diff/histogram.js.map +1 -0
  45. package/dist/diff/index.d.ts +30 -0
  46. package/dist/diff/index.d.ts.map +1 -0
  47. package/dist/diff/index.js +47 -0
  48. package/dist/diff/index.js.map +1 -0
  49. package/dist/diff/lcs.d.ts +34 -0
  50. package/dist/diff/lcs.d.ts.map +1 -0
  51. package/dist/diff/lcs.js +184 -0
  52. package/dist/diff/lcs.js.map +1 -0
  53. package/dist/diff/shared.d.ts +54 -0
  54. package/dist/diff/shared.d.ts.map +1 -0
  55. package/dist/diff/shared.js +164 -0
  56. package/dist/diff/shared.js.map +1 -0
  57. package/dist/diff.d.ts +6 -65
  58. package/dist/diff.d.ts.map +1 -1
  59. package/dist/diff.js +6 -324
  60. package/dist/diff.js.map +1 -1
  61. package/dist/format-profiles/index.d.ts +34 -0
  62. package/dist/format-profiles/index.d.ts.map +1 -0
  63. package/dist/format-profiles/index.js +86 -0
  64. package/dist/format-profiles/index.js.map +1 -0
  65. package/dist/format-profiles/json-patch.d.ts +61 -0
  66. package/dist/format-profiles/json-patch.d.ts.map +1 -0
  67. package/dist/format-profiles/json-patch.js +269 -0
  68. package/dist/format-profiles/json-patch.js.map +1 -0
  69. package/dist/format-profiles/merge-strategies.d.ts +54 -0
  70. package/dist/format-profiles/merge-strategies.d.ts.map +1 -0
  71. package/dist/format-profiles/merge-strategies.js +156 -0
  72. package/dist/format-profiles/merge-strategies.js.map +1 -0
  73. package/dist/format-profiles/profiles/composer.d.ts +18 -0
  74. package/dist/format-profiles/profiles/composer.d.ts.map +1 -0
  75. package/dist/format-profiles/profiles/composer.js +45 -0
  76. package/dist/format-profiles/profiles/composer.js.map +1 -0
  77. package/dist/format-profiles/profiles/helm-values.d.ts +21 -0
  78. package/dist/format-profiles/profiles/helm-values.d.ts.map +1 -0
  79. package/dist/format-profiles/profiles/helm-values.js +40 -0
  80. package/dist/format-profiles/profiles/helm-values.js.map +1 -0
  81. package/dist/format-profiles/profiles/kubernetes.d.ts +22 -0
  82. package/dist/format-profiles/profiles/kubernetes.d.ts.map +1 -0
  83. package/dist/format-profiles/profiles/kubernetes.js +60 -0
  84. package/dist/format-profiles/profiles/kubernetes.js.map +1 -0
  85. package/dist/format-profiles/profiles/package-json.d.ts +18 -0
  86. package/dist/format-profiles/profiles/package-json.d.ts.map +1 -0
  87. package/dist/format-profiles/profiles/package-json.js +36 -0
  88. package/dist/format-profiles/profiles/package-json.js.map +1 -0
  89. package/dist/format-profiles/profiles/tsconfig.d.ts +21 -0
  90. package/dist/format-profiles/profiles/tsconfig.d.ts.map +1 -0
  91. package/dist/format-profiles/profiles/tsconfig.js +47 -0
  92. package/dist/format-profiles/profiles/tsconfig.js.map +1 -0
  93. package/dist/format-profiles/types.d.ts +67 -0
  94. package/dist/format-profiles/types.d.ts.map +1 -0
  95. package/dist/format-profiles/types.js +9 -0
  96. package/dist/format-profiles/types.js.map +1 -0
  97. package/dist/index.d.ts +4 -0
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +5 -0
  100. package/dist/index.js.map +1 -1
  101. package/dist/patterns/insertion-at-boundary.d.ts.map +1 -1
  102. package/dist/patterns/insertion-at-boundary.js +15 -33
  103. package/dist/patterns/insertion-at-boundary.js.map +1 -1
  104. package/dist/patterns/utils.d.ts +11 -8
  105. package/dist/patterns/utils.d.ts.map +1 -1
  106. package/dist/patterns/utils.js +28 -10
  107. package/dist/patterns/utils.js.map +1 -1
  108. package/dist/resolver/format-dispatch.d.ts.map +1 -1
  109. package/dist/resolver/format-dispatch.js +3 -1
  110. package/dist/resolver/format-dispatch.js.map +1 -1
  111. package/dist/resolver/policy.d.ts.map +1 -1
  112. package/dist/resolver/policy.js +2 -0
  113. package/dist/resolver/policy.js.map +1 -1
  114. package/dist/resolvers/dispatcher.d.ts +5 -1
  115. package/dist/resolvers/dispatcher.d.ts.map +1 -1
  116. package/dist/resolvers/dispatcher.js +8 -3
  117. package/dist/resolvers/dispatcher.js.map +1 -1
  118. package/dist/resolvers/json.d.ts +11 -2
  119. package/dist/resolvers/json.d.ts.map +1 -1
  120. package/dist/resolvers/json.js +55 -7
  121. package/dist/resolvers/json.js.map +1 -1
  122. package/dist/resolvers/yaml.d.ts +8 -2
  123. package/dist/resolvers/yaml.d.ts.map +1 -1
  124. package/dist/resolvers/yaml.js +156 -2
  125. package/dist/resolvers/yaml.js.map +1 -1
  126. package/dist/types.d.ts +25 -0
  127. package/dist/types.d.ts.map +1 -1
  128. package/package.json +1 -1
@@ -0,0 +1,269 @@
1
+ /**
2
+ * GitWand — RFC 6902 (JSON Patch) minimal
3
+ *
4
+ * Implémentation maison, pas de dep externe. Couvre `add`, `remove`, `replace`.
5
+ * `move` et `copy` non implémentées (gérées par séquences add/remove).
6
+ *
7
+ * Trois primitives :
8
+ * - `diffJson(base, target)` produit la séquence d'ops qui transforme base en target.
9
+ * - `applyJsonPatch(doc, ops)` applique séquentiellement, retourne le doc résultat
10
+ * (immutable — entrée non modifiée).
11
+ * - `mergeJsonPatches(oursOps, theirsOps)` concatène si les paths sont disjoints,
12
+ * `null` si conflit (au moins une op des deux côtés sur le même path).
13
+ *
14
+ * JSON Pointer (RFC 6901) avec escape `~0` → `~` et `~1` → `/`.
15
+ */
16
+ // ─── JSON Pointer (RFC 6901) ─────────────────────────────────
17
+ /**
18
+ * Parse un JSON Pointer en tableau de tokens. Le pointer racine `""` retourne
19
+ * `[]`. Chaque token est ré-échappé : `~0` → `~`, `~1` → `/`.
20
+ */
21
+ export function parseJsonPointer(pointer) {
22
+ if (pointer === "")
23
+ return [];
24
+ if (pointer[0] !== "/") {
25
+ throw new Error(`Invalid JSON pointer: ${pointer} (must start with '/')`);
26
+ }
27
+ return pointer
28
+ .slice(1)
29
+ .split("/")
30
+ .map((tok) => tok.replace(/~1/g, "/").replace(/~0/g, "~"));
31
+ }
32
+ /**
33
+ * Construit un JSON Pointer depuis un tableau de tokens. Échappe `~` et `/`.
34
+ */
35
+ export function buildJsonPointer(tokens) {
36
+ if (tokens.length === 0)
37
+ return "";
38
+ return ("/" +
39
+ tokens
40
+ .map((tok) => tok.replace(/~/g, "~0").replace(/\//g, "~1"))
41
+ .join("/"));
42
+ }
43
+ function isPlainObject(v) {
44
+ return typeof v === "object" && v !== null && !Array.isArray(v);
45
+ }
46
+ /** Clone superficiel d'un objet ou d'un tableau (immutabilité au niveau du parent). */
47
+ function shallowClone(v) {
48
+ if (Array.isArray(v))
49
+ return [...v];
50
+ if (isPlainObject(v))
51
+ return { ...v };
52
+ return v;
53
+ }
54
+ /**
55
+ * Applique une séquence d'opérations RFC 6902 à un document. Retourne le
56
+ * nouveau document (l'entrée n'est pas modifiée). Lance une `Error` si une
57
+ * opération réfère à un path inexistant (sauf `add` qui crée).
58
+ */
59
+ export function applyJsonPatch(doc, ops) {
60
+ let current = doc;
61
+ for (const op of ops) {
62
+ current = applyOp(current, op);
63
+ }
64
+ return current;
65
+ }
66
+ function applyOp(doc, op) {
67
+ const tokens = parseJsonPointer(op.path);
68
+ if (tokens.length === 0) {
69
+ // Path racine — replace ou add remplace tout le doc, remove vide.
70
+ if (op.op === "replace" || op.op === "add")
71
+ return op.value;
72
+ if (op.op === "remove")
73
+ return undefined;
74
+ }
75
+ return applyAt(doc, tokens, 0, op);
76
+ }
77
+ function applyAt(node, tokens, depth, op) {
78
+ if (depth === tokens.length - 1) {
79
+ const lastToken = tokens[depth];
80
+ if (Array.isArray(node)) {
81
+ const arr = [...node];
82
+ if (op.op === "add") {
83
+ if (lastToken === "-") {
84
+ arr.push(op.value);
85
+ }
86
+ else {
87
+ const idx = parseInt(lastToken, 10);
88
+ if (!Number.isInteger(idx) || idx < 0 || idx > arr.length) {
89
+ throw new Error(`Invalid array index: ${lastToken}`);
90
+ }
91
+ arr.splice(idx, 0, op.value);
92
+ }
93
+ return arr;
94
+ }
95
+ const idx = parseInt(lastToken, 10);
96
+ if (!Number.isInteger(idx) || idx < 0 || idx >= arr.length) {
97
+ throw new Error(`Invalid array index for ${op.op}: ${lastToken}`);
98
+ }
99
+ if (op.op === "remove") {
100
+ arr.splice(idx, 1);
101
+ }
102
+ else {
103
+ // replace
104
+ arr[idx] = op.value;
105
+ }
106
+ return arr;
107
+ }
108
+ if (isPlainObject(node)) {
109
+ const obj = { ...node };
110
+ if (op.op === "add" || op.op === "replace") {
111
+ obj[lastToken] = op.value;
112
+ }
113
+ else {
114
+ // remove
115
+ if (!(lastToken in obj)) {
116
+ throw new Error(`Cannot remove non-existent key: ${lastToken}`);
117
+ }
118
+ delete obj[lastToken];
119
+ }
120
+ return obj;
121
+ }
122
+ throw new Error(`Cannot apply ${op.op} to non-container at ${tokens.join("/")}`);
123
+ }
124
+ // Intermediate token — descend.
125
+ const token = tokens[depth];
126
+ if (Array.isArray(node)) {
127
+ const idx = parseInt(token, 10);
128
+ if (!Number.isInteger(idx) || idx < 0 || idx >= node.length) {
129
+ throw new Error(`Invalid array index: ${token}`);
130
+ }
131
+ const arr = [...node];
132
+ arr[idx] = applyAt(arr[idx], tokens, depth + 1, op);
133
+ return arr;
134
+ }
135
+ if (isPlainObject(node)) {
136
+ if (!(token in node)) {
137
+ throw new Error(`Path does not exist: ${tokens.slice(0, depth + 1).join("/")}`);
138
+ }
139
+ const obj = { ...node };
140
+ obj[token] = applyAt(obj[token], tokens, depth + 1, op);
141
+ return obj;
142
+ }
143
+ throw new Error(`Cannot descend into non-container at ${tokens.slice(0, depth).join("/")}`);
144
+ }
145
+ // ─── Diff ────────────────────────────────────────────────────
146
+ /**
147
+ * Calcule la séquence d'ops RFC 6902 qui transforme `base` en `target`.
148
+ *
149
+ * Stratégie : récursion structurelle. Sur les objets, on compare clé-par-clé
150
+ * (ajout / remove / récursion). Sur les tableaux, on émet `replace` global
151
+ * dès que les longueurs diffèrent ou qu'un élément à un index donné diffère —
152
+ * pas de LCS-on-arrays ici (c'est le rôle des stratégies `set` / `ordered-list`
153
+ * du registre, qui appellent `diffJson` à un niveau plus fin).
154
+ */
155
+ export function diffJson(base, target) {
156
+ const ops = [];
157
+ diffAt(base, target, [], ops);
158
+ return ops;
159
+ }
160
+ function diffAt(base, target, path, ops) {
161
+ if (jsonStructEqual(base, target))
162
+ return;
163
+ // Types divergents ou scalaires différents → replace.
164
+ const baseIsObj = isPlainObject(base);
165
+ const targetIsObj = isPlainObject(target);
166
+ const baseIsArr = Array.isArray(base);
167
+ const targetIsArr = Array.isArray(target);
168
+ if (baseIsObj && targetIsObj) {
169
+ const baseObj = base;
170
+ const targetObj = target;
171
+ const allKeys = new Set([...Object.keys(baseObj), ...Object.keys(targetObj)]);
172
+ for (const key of allKeys) {
173
+ const inBase = key in baseObj;
174
+ const inTarget = key in targetObj;
175
+ const childPath = [...path, key];
176
+ if (inBase && inTarget) {
177
+ diffAt(baseObj[key], targetObj[key], childPath, ops);
178
+ }
179
+ else if (!inBase && inTarget) {
180
+ ops.push({ op: "add", path: buildJsonPointer(childPath), value: targetObj[key] });
181
+ }
182
+ else {
183
+ // inBase && !inTarget
184
+ ops.push({ op: "remove", path: buildJsonPointer(childPath) });
185
+ }
186
+ }
187
+ return;
188
+ }
189
+ if (baseIsArr && targetIsArr) {
190
+ // Comparaison naïve : si même longueur et chaque index égal → no-op
191
+ // (déjà géré par le check d'égalité). Sinon replace global du tableau.
192
+ ops.push({ op: "replace", path: buildJsonPointer(path), value: target });
193
+ return;
194
+ }
195
+ // Type change ou scalaire différent.
196
+ ops.push({ op: "replace", path: buildJsonPointer(path), value: target });
197
+ }
198
+ /** Égalité structurelle (récursive) entre deux JSON values. */
199
+ export function jsonStructEqual(a, b) {
200
+ if (a === b)
201
+ return true;
202
+ if (a === null || b === null)
203
+ return false;
204
+ if (typeof a !== typeof b)
205
+ return false;
206
+ if (Array.isArray(a)) {
207
+ if (!Array.isArray(b) || a.length !== b.length)
208
+ return false;
209
+ for (let i = 0; i < a.length; i++) {
210
+ if (!jsonStructEqual(a[i], b[i]))
211
+ return false;
212
+ }
213
+ return true;
214
+ }
215
+ if (isPlainObject(a) && isPlainObject(b)) {
216
+ const aKeys = Object.keys(a);
217
+ const bKeys = Object.keys(b);
218
+ if (aKeys.length !== bKeys.length)
219
+ return false;
220
+ for (const k of aKeys) {
221
+ if (!(k in b))
222
+ return false;
223
+ if (!jsonStructEqual(a[k], b[k]))
224
+ return false;
225
+ }
226
+ return true;
227
+ }
228
+ return false;
229
+ }
230
+ // ─── Merge ───────────────────────────────────────────────────
231
+ /**
232
+ * Fusionne deux séquences d'ops. Si les paths sont disjoints (aucun path
233
+ * touché par les deux), on retourne la concaténation `[...ours, ...theirs]`.
234
+ * Sinon, on retourne `null` avec une liste des paths en conflit (utile pour
235
+ * la `DecisionTrace`).
236
+ *
237
+ * Disjoint = aucun path d'`ours` n'est égal ni préfixe d'un path de `theirs`,
238
+ * et vice versa. (Si `ours` modifie `/foo/bar` et `theirs` modifie `/foo`, ils
239
+ * sont en conflit même si les chaînes ne sont pas identiques.)
240
+ */
241
+ export function mergeJsonPatches(ours, theirs) {
242
+ const conflictingPaths = [];
243
+ for (const op1 of ours) {
244
+ for (const op2 of theirs) {
245
+ if (pathsConflict(op1.path, op2.path)) {
246
+ conflictingPaths.push(op1.path);
247
+ break;
248
+ }
249
+ }
250
+ }
251
+ if (conflictingPaths.length > 0) {
252
+ return { merged: null, conflictingPaths };
253
+ }
254
+ return { merged: [...ours, ...theirs], conflictingPaths: [] };
255
+ }
256
+ /**
257
+ * Vrai si les deux paths se chevauchent (égaux, ou l'un préfixe de l'autre).
258
+ */
259
+ function pathsConflict(a, b) {
260
+ if (a === b)
261
+ return true;
262
+ // a préfixe de b : b commence par a + "/"
263
+ if (b.startsWith(a + "/"))
264
+ return true;
265
+ if (a.startsWith(b + "/"))
266
+ return true;
267
+ return false;
268
+ }
269
+ //# sourceMappingURL=json-patch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"json-patch.js","sourceRoot":"","sources":["../../src/format-profiles/json-patch.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,54 @@
1
+ /**
2
+ * GitWand — Stratégies de merge appliquées par les profils
3
+ *
4
+ * Trois fonctions clés exportées :
5
+ * - mergeArrayAsSet : merge 3-way de tableaux comme des sets (par identité)
6
+ * - mergeOrderedListViaPatch : merge 3-way de tableaux via RFC 6902 add/remove
7
+ * - tryMergeWithProfile : helper de haut niveau qui route base/ours/theirs en
8
+ * fonction de la stratégie, retourne null si non résolvable.
9
+ *
10
+ * Les fonctions sont génériques sur unknown et peuvent être appelées tant pour
11
+ * des sous-arbres JSON que des sous-arbres YAML (le résolveur YAML les utilise
12
+ * après yaml.parse → représentation JS-native).
13
+ */
14
+ import type { JsonPatchOp, PathStrategy } from "./types.js";
15
+ /**
16
+ * Merge 3-way de deux tableaux interprétés comme des sets identifiés par
17
+ * `identity`. La sémantique :
18
+ *
19
+ * - Pour chaque item présent dans ours OU theirs, on regarde s'il était dans
20
+ * la base.
21
+ * - Item ajouté d'un seul côté → ajouté au résultat.
22
+ * - Item modifié d'un seul côté (même identité, valeur différente) → version
23
+ * modifiée gagne.
24
+ * - Item modifié des deux côtés différemment → conflit, retour null.
25
+ * - Item supprimé d'un côté + non modifié de l'autre → supprimé du résultat.
26
+ * - Item supprimé d'un côté + modifié de l'autre → conflit.
27
+ *
28
+ * L'ordre du résultat suit ours pour les items qu'il contient, puis ajoute
29
+ * en queue les nouveaux de theirs (sémantique "ours d'abord, theirs ensuite").
30
+ */
31
+ export declare function mergeArrayAsSet(base: unknown[], ours: unknown[], theirs: unknown[], identity: (item: unknown) => string): unknown[] | null;
32
+ /**
33
+ * Merge 3-way d'un sous-arbre via RFC 6902 (add/remove/replace). Si les
34
+ * deltas base→ours et base→theirs n'entrent pas en conflit (paths disjoints),
35
+ * on applique séquentiellement les deux. Sinon, retourne null.
36
+ */
37
+ export declare function mergeOrderedListViaPatch(base: unknown, ours: unknown, theirs: unknown): unknown | null;
38
+ /**
39
+ * Routeur de stratégie. Reçoit base/ours/theirs déjà parsés (JSON values) et
40
+ * la PathStrategy à appliquer. Retourne la valeur fusionnée ou null.
41
+ *
42
+ * Note : "merge-keys" et "opaque" ne sont **pas** gérés ici — ils sont
43
+ * délégués au pipeline existant (mergeObjects récursif côté json.ts) qui sait
44
+ * descendre dans la structure. Ce module gère uniquement les stratégies qui
45
+ * apportent quelque chose de nouveau en v2.2 (set, ordered-list).
46
+ */
47
+ export declare function applyStrategy(strategy: PathStrategy, base: unknown, ours: unknown, theirs: unknown): {
48
+ handled: true;
49
+ value: unknown | null;
50
+ } | {
51
+ handled: false;
52
+ };
53
+ export type { JsonPatchOp };
54
+ //# sourceMappingURL=merge-strategies.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-strategies.d.ts","sourceRoot":"","sources":["../../src/format-profiles/merge-strategies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAG5D;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,eAAe,CAC7B,IAAI,EAAE,OAAO,EAAE,EACf,IAAI,EAAE,OAAO,EAAE,EACf,MAAM,EAAE,OAAO,EAAE,EACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,MAAM,GAClC,OAAO,EAAE,GAAG,IAAI,CA2FlB;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,OAAO,GACd,OAAO,GAAG,IAAI,CAMhB;AAED;;;;;;;;GAQG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,YAAY,EACtB,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,OAAO,EACb,MAAM,EAAE,OAAO,GACd;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,OAAO,GAAG,IAAI,CAAA;CAAE,GAAG;IAAE,OAAO,EAAE,KAAK,CAAA;CAAE,CAa/D;AAED,YAAY,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,156 @@
1
+ /**
2
+ * GitWand — Stratégies de merge appliquées par les profils
3
+ *
4
+ * Trois fonctions clés exportées :
5
+ * - mergeArrayAsSet : merge 3-way de tableaux comme des sets (par identité)
6
+ * - mergeOrderedListViaPatch : merge 3-way de tableaux via RFC 6902 add/remove
7
+ * - tryMergeWithProfile : helper de haut niveau qui route base/ours/theirs en
8
+ * fonction de la stratégie, retourne null si non résolvable.
9
+ *
10
+ * Les fonctions sont génériques sur unknown et peuvent être appelées tant pour
11
+ * des sous-arbres JSON que des sous-arbres YAML (le résolveur YAML les utilise
12
+ * après yaml.parse → représentation JS-native).
13
+ */
14
+ import { diffJson, mergeJsonPatches, applyJsonPatch, jsonStructEqual } from "./json-patch.js";
15
+ /**
16
+ * Merge 3-way de deux tableaux interprétés comme des sets identifiés par
17
+ * `identity`. La sémantique :
18
+ *
19
+ * - Pour chaque item présent dans ours OU theirs, on regarde s'il était dans
20
+ * la base.
21
+ * - Item ajouté d'un seul côté → ajouté au résultat.
22
+ * - Item modifié d'un seul côté (même identité, valeur différente) → version
23
+ * modifiée gagne.
24
+ * - Item modifié des deux côtés différemment → conflit, retour null.
25
+ * - Item supprimé d'un côté + non modifié de l'autre → supprimé du résultat.
26
+ * - Item supprimé d'un côté + modifié de l'autre → conflit.
27
+ *
28
+ * L'ordre du résultat suit ours pour les items qu'il contient, puis ajoute
29
+ * en queue les nouveaux de theirs (sémantique "ours d'abord, theirs ensuite").
30
+ */
31
+ export function mergeArrayAsSet(base, ours, theirs, identity) {
32
+ const baseMap = new Map();
33
+ for (const item of base)
34
+ baseMap.set(identity(item), item);
35
+ const oursMap = new Map();
36
+ for (const item of ours)
37
+ oursMap.set(identity(item), item);
38
+ const theirsMap = new Map();
39
+ for (const item of theirs)
40
+ theirsMap.set(identity(item), item);
41
+ // Préserve l'ordre d'ours. Les items dans theirs absents d'ours sont append en fin.
42
+ const orderedKeys = [];
43
+ const seen = new Set();
44
+ for (const item of ours) {
45
+ const k = identity(item);
46
+ if (!seen.has(k)) {
47
+ orderedKeys.push(k);
48
+ seen.add(k);
49
+ }
50
+ }
51
+ for (const item of theirs) {
52
+ const k = identity(item);
53
+ if (!seen.has(k)) {
54
+ orderedKeys.push(k);
55
+ seen.add(k);
56
+ }
57
+ }
58
+ // Et les items présents en base mais ni dans ours ni dans theirs auraient
59
+ // été supprimés des deux côtés — pas besoin de les visiter.
60
+ const result = [];
61
+ for (const key of orderedKeys) {
62
+ const inBase = baseMap.has(key);
63
+ const inOurs = oursMap.has(key);
64
+ const inTheirs = theirsMap.has(key);
65
+ const baseVal = baseMap.get(key);
66
+ const oursVal = oursMap.get(key);
67
+ const theirsVal = theirsMap.get(key);
68
+ // Présent dans les deux branches
69
+ if (inOurs && inTheirs) {
70
+ if (jsonStructEqual(oursVal, theirsVal)) {
71
+ result.push(oursVal);
72
+ continue;
73
+ }
74
+ // Modifications divergentes
75
+ if (inBase) {
76
+ const oursChanged = !jsonStructEqual(baseVal, oursVal);
77
+ const theirsChanged = !jsonStructEqual(baseVal, theirsVal);
78
+ if (oursChanged && !theirsChanged) {
79
+ result.push(oursVal);
80
+ continue;
81
+ }
82
+ if (!oursChanged && theirsChanged) {
83
+ result.push(theirsVal);
84
+ continue;
85
+ }
86
+ // Les deux ont changé différemment → conflit
87
+ return null;
88
+ }
89
+ // Pas dans la base, ajouts différents des deux côtés → conflit
90
+ return null;
91
+ }
92
+ // Présent uniquement d'un côté
93
+ if (inOurs && !inTheirs) {
94
+ if (inBase) {
95
+ // theirs a supprimé ; ours a-t-il modifié ?
96
+ if (jsonStructEqual(baseVal, oursVal)) {
97
+ // Pas modifié des deux côtés (suppression nette par theirs) → skip
98
+ continue;
99
+ }
100
+ // ours a modifié, theirs a supprimé → conflit
101
+ return null;
102
+ }
103
+ // Ajout pur côté ours
104
+ result.push(oursVal);
105
+ continue;
106
+ }
107
+ if (!inOurs && inTheirs) {
108
+ if (inBase) {
109
+ if (jsonStructEqual(baseVal, theirsVal)) {
110
+ continue;
111
+ }
112
+ return null;
113
+ }
114
+ result.push(theirsVal);
115
+ continue;
116
+ }
117
+ }
118
+ return result;
119
+ }
120
+ /**
121
+ * Merge 3-way d'un sous-arbre via RFC 6902 (add/remove/replace). Si les
122
+ * deltas base→ours et base→theirs n'entrent pas en conflit (paths disjoints),
123
+ * on applique séquentiellement les deux. Sinon, retourne null.
124
+ */
125
+ export function mergeOrderedListViaPatch(base, ours, theirs) {
126
+ const oursOps = diffJson(base, ours);
127
+ const theirsOps = diffJson(base, theirs);
128
+ const merged = mergeJsonPatches(oursOps, theirsOps);
129
+ if (merged.merged === null)
130
+ return null;
131
+ return applyJsonPatch(base, merged.merged);
132
+ }
133
+ /**
134
+ * Routeur de stratégie. Reçoit base/ours/theirs déjà parsés (JSON values) et
135
+ * la PathStrategy à appliquer. Retourne la valeur fusionnée ou null.
136
+ *
137
+ * Note : "merge-keys" et "opaque" ne sont **pas** gérés ici — ils sont
138
+ * délégués au pipeline existant (mergeObjects récursif côté json.ts) qui sait
139
+ * descendre dans la structure. Ce module gère uniquement les stratégies qui
140
+ * apportent quelque chose de nouveau en v2.2 (set, ordered-list).
141
+ */
142
+ export function applyStrategy(strategy, base, ours, theirs) {
143
+ if (strategy.kind === "set") {
144
+ if (!Array.isArray(base) || !Array.isArray(ours) || !Array.isArray(theirs)) {
145
+ return { handled: false };
146
+ }
147
+ const identity = strategy.identity ?? ((item) => JSON.stringify(item));
148
+ return { handled: true, value: mergeArrayAsSet(base, ours, theirs, identity) };
149
+ }
150
+ if (strategy.kind === "ordered-list") {
151
+ return { handled: true, value: mergeOrderedListViaPatch(base, ours, theirs) };
152
+ }
153
+ // merge-keys et opaque : non gérés ici.
154
+ return { handled: false };
155
+ }
156
+ //# sourceMappingURL=merge-strategies.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"merge-strategies.js","sourceRoot":"","sources":["../../src/format-profiles/merge-strategies.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,QAAQ,EAAE,gBAAgB,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAE9F;;;;;;;;;;;;;;;GAeG;AACH,MAAM,UAAU,eAAe,CAC7B,IAAe,EACf,IAAe,EACf,MAAiB,EACjB,QAAmC;IAEnC,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC3C,KAAK,MAAM,IAAI,IAAI,IAAI;QAAE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAC3D,MAAM,SAAS,GAAG,IAAI,GAAG,EAAmB,CAAC;IAC7C,KAAK,MAAM,IAAI,IAAI,MAAM;QAAE,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,CAAC;IAE/D,oFAAoF;IACpF,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,MAAM,IAAI,GAAG,IAAI,GAAG,EAAU,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,IAAI,EAAE,CAAC;QACxB,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,MAAM,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC;YACjB,WAAW,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YACpB,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;QACd,CAAC;IACH,CAAC;IACD,0EAA0E;IAC1E,4DAA4D;IAE5D,MAAM,MAAM,GAAc,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,WAAW,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,QAAQ,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACpC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,OAAO,GAAG,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,MAAM,SAAS,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAErC,iCAAiC;QACjC,IAAI,MAAM,IAAI,QAAQ,EAAE,CAAC;YACvB,IAAI,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;gBACxC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;gBACrB,SAAS;YACX,CAAC;YACD,4BAA4B;YAC5B,IAAI,MAAM,EAAE,CAAC;gBACX,MAAM,WAAW,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;gBACvD,MAAM,aAAa,GAAG,CAAC,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;gBAC3D,IAAI,WAAW,IAAI,CAAC,aAAa,EAAE,CAAC;oBAClC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;oBACrB,SAAS;gBACX,CAAC;gBACD,IAAI,CAAC,WAAW,IAAI,aAAa,EAAE,CAAC;oBAClC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;oBACvB,SAAS;gBACX,CAAC;gBACD,6CAA6C;gBAC7C,OAAO,IAAI,CAAC;YACd,CAAC;YACD,+DAA+D;YAC/D,OAAO,IAAI,CAAC;QACd,CAAC;QAED,+BAA+B;QAC/B,IAAI,MAAM,IAAI,CAAC,QAAQ,EAAE,CAAC;YACxB,IAAI,MAAM,EAAE,CAAC;gBACX,4CAA4C;gBAC5C,IAAI,eAAe,CAAC,OAAO,EAAE,OAAO,CAAC,EAAE,CAAC;oBACtC,mEAAmE;oBACnE,SAAS;gBACX,CAAC;gBACD,8CAA8C;gBAC9C,OAAO,IAAI,CAAC;YACd,CAAC;YACD,sBAAsB;YACtB,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACrB,SAAS;QACX,CAAC;QACD,IAAI,CAAC,MAAM,IAAI,QAAQ,EAAE,CAAC;YACxB,IAAI,MAAM,EAAE,CAAC;gBACX,IAAI,eAAe,CAAC,OAAO,EAAE,SAAS,CAAC,EAAE,CAAC;oBACxC,SAAS;gBACX,CAAC;gBACD,OAAO,IAAI,CAAC;YACd,CAAC;YACD,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACvB,SAAS;QACX,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CACtC,IAAa,EACb,IAAa,EACb,MAAe;IAEf,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IACrC,MAAM,SAAS,GAAG,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,MAAM,MAAM,GAAG,gBAAgB,CAAC,OAAO,EAAE,SAAS,CAAC,CAAC;IACpD,IAAI,MAAM,CAAC,MAAM,KAAK,IAAI;QAAE,OAAO,IAAI,CAAC;IACxC,OAAO,cAAc,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,aAAa,CAC3B,QAAsB,EACtB,IAAa,EACb,IAAa,EACb,MAAe;IAEf,IAAI,QAAQ,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC5B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;YAC3E,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;QAC5B,CAAC;QACD,MAAM,QAAQ,GAAG,QAAQ,CAAC,QAAQ,IAAI,CAAC,CAAC,IAAa,EAAE,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QAChF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,eAAe,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,CAAC;IACjF,CAAC;IACD,IAAI,QAAQ,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;QACrC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,wBAAwB,CAAC,IAAI,EAAE,IAAI,EAAE,MAAM,CAAC,EAAE,CAAC;IAChF,CAAC;IACD,wCAAwC;IACxC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC;AAC5B,CAAC"}
@@ -0,0 +1,18 @@
1
+ /**
2
+ * GitWand — Profil "composer.json" (PHP)
3
+ *
4
+ * Match : tout fichier nommé composer.json (à n'importe quelle profondeur).
5
+ * Analogue à package.json côté PHP.
6
+ *
7
+ * Stratégies :
8
+ * - /require, /require-dev, /conflict, /provide, /replace, /suggest
9
+ * → merge-keys (objets clé-par-clé)
10
+ * - /autoload, /autoload-dev → merge-keys (sous-objets PSR-4 / classmap…)
11
+ * - /scripts → merge-keys
12
+ * - /keywords → set
13
+ * - /authors → set par "email" (objets {name, email}, identité = email)
14
+ * - défaut → merge-keys
15
+ */
16
+ import type { FormatProfile } from "../types.js";
17
+ export declare const composerProfile: FormatProfile;
18
+ //# sourceMappingURL=composer.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.d.ts","sourceRoot":"","sources":["../../../src/format-profiles/profiles/composer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,eAAO,MAAM,eAAe,EAAE,aA4B7B,CAAC"}
@@ -0,0 +1,45 @@
1
+ /**
2
+ * GitWand — Profil "composer.json" (PHP)
3
+ *
4
+ * Match : tout fichier nommé composer.json (à n'importe quelle profondeur).
5
+ * Analogue à package.json côté PHP.
6
+ *
7
+ * Stratégies :
8
+ * - /require, /require-dev, /conflict, /provide, /replace, /suggest
9
+ * → merge-keys (objets clé-par-clé)
10
+ * - /autoload, /autoload-dev → merge-keys (sous-objets PSR-4 / classmap…)
11
+ * - /scripts → merge-keys
12
+ * - /keywords → set
13
+ * - /authors → set par "email" (objets {name, email}, identité = email)
14
+ * - défaut → merge-keys
15
+ */
16
+ export const composerProfile = {
17
+ name: "composer.json",
18
+ matches: (filePath) => {
19
+ const basename = filePath.split("/").pop() ?? filePath;
20
+ return basename === "composer.json";
21
+ },
22
+ paths: {
23
+ "/require": { kind: "merge-keys" },
24
+ "/require-dev": { kind: "merge-keys" },
25
+ "/conflict": { kind: "merge-keys" },
26
+ "/provide": { kind: "merge-keys" },
27
+ "/replace": { kind: "merge-keys" },
28
+ "/suggest": { kind: "merge-keys" },
29
+ "/autoload": { kind: "merge-keys" },
30
+ "/autoload-dev": { kind: "merge-keys" },
31
+ "/scripts": { kind: "merge-keys" },
32
+ "/keywords": { kind: "set" },
33
+ "/authors": {
34
+ kind: "set",
35
+ identity: (item) => {
36
+ if (typeof item === "object" && item !== null && "email" in item) {
37
+ return String(item.email);
38
+ }
39
+ return JSON.stringify(item);
40
+ },
41
+ },
42
+ },
43
+ default: { kind: "merge-keys" },
44
+ };
45
+ //# sourceMappingURL=composer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"composer.js","sourceRoot":"","sources":["../../../src/format-profiles/profiles/composer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,CAAC,MAAM,eAAe,GAAkB;IAC5C,IAAI,EAAE,eAAe;IACrB,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;QACpB,MAAM,QAAQ,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,QAAQ,CAAC;QACvD,OAAO,QAAQ,KAAK,eAAe,CAAC;IACtC,CAAC;IACD,KAAK,EAAE;QACL,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAClC,cAAc,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QACtC,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QACnC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAClC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAClC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAClC,WAAW,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QACnC,eAAe,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QACvC,UAAU,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;QAClC,WAAW,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE;QAC5B,UAAU,EAAE;YACV,IAAI,EAAE,KAAK;YACX,QAAQ,EAAE,CAAC,IAAI,EAAE,EAAE;gBACjB,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,OAAO,IAAI,IAAI,EAAE,CAAC;oBACjE,OAAO,MAAM,CAAE,IAA2B,CAAC,KAAK,CAAC,CAAC;gBACpD,CAAC;gBACD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;YAC9B,CAAC;SACF;KACF;IACD,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;CAChC,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * GitWand — Profil "helm/values.yaml"
3
+ *
4
+ * Match : fichiers values.yaml ou values.<env>.yaml dans un répertoire
5
+ * "helm/" ou "charts/" (conventions Helm). Match large pour couvrir les
6
+ * monorepos avec sub-charts.
7
+ *
8
+ * Stratégies (s'appuient sur les conventions Kubernetes embarquées dans
9
+ * Helm) :
10
+ * - /spec/template/spec/containers → set par "name" (chaque container a un
11
+ * "name" unique selon les Pod specs Kubernetes)
12
+ * - /spec/template/spec/initContainers → set par "name"
13
+ * - /spec/template/spec/volumes → set par "name"
14
+ * - /spec/template/spec/containers/* /env → set par "name" (env vars)
15
+ * (note : à la profondeur du wildcard, on raisonne sur l'entité de la
16
+ * liste env, pas sur l'item individuel)
17
+ * - défaut → merge-keys
18
+ */
19
+ import type { FormatProfile } from "../types.js";
20
+ export declare const helmValuesProfile: FormatProfile;
21
+ //# sourceMappingURL=helm-values.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helm-values.d.ts","sourceRoot":"","sources":["../../../src/format-profiles/profiles/helm-values.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AASjD,eAAO,MAAM,iBAAiB,EAAE,aAa/B,CAAC"}
@@ -0,0 +1,40 @@
1
+ /**
2
+ * GitWand — Profil "helm/values.yaml"
3
+ *
4
+ * Match : fichiers values.yaml ou values.<env>.yaml dans un répertoire
5
+ * "helm/" ou "charts/" (conventions Helm). Match large pour couvrir les
6
+ * monorepos avec sub-charts.
7
+ *
8
+ * Stratégies (s'appuient sur les conventions Kubernetes embarquées dans
9
+ * Helm) :
10
+ * - /spec/template/spec/containers → set par "name" (chaque container a un
11
+ * "name" unique selon les Pod specs Kubernetes)
12
+ * - /spec/template/spec/initContainers → set par "name"
13
+ * - /spec/template/spec/volumes → set par "name"
14
+ * - /spec/template/spec/containers/* /env → set par "name" (env vars)
15
+ * (note : à la profondeur du wildcard, on raisonne sur l'entité de la
16
+ * liste env, pas sur l'item individuel)
17
+ * - défaut → merge-keys
18
+ */
19
+ const NAME_KEYED = (item) => {
20
+ if (typeof item === "object" && item !== null && "name" in item) {
21
+ return String(item.name);
22
+ }
23
+ return JSON.stringify(item);
24
+ };
25
+ export const helmValuesProfile = {
26
+ name: "helm/values.yaml",
27
+ matches: (filePath) => {
28
+ if (!/values(\.[^/]+)?\.ya?ml$/.test(filePath))
29
+ return false;
30
+ return /(^|\/)(helm|charts?)\//.test(filePath);
31
+ },
32
+ paths: {
33
+ "/spec/template/spec/containers": { kind: "set", identity: NAME_KEYED },
34
+ "/spec/template/spec/initContainers": { kind: "set", identity: NAME_KEYED },
35
+ "/spec/template/spec/volumes": { kind: "set", identity: NAME_KEYED },
36
+ "/spec/template/spec/imagePullSecrets": { kind: "set", identity: NAME_KEYED },
37
+ },
38
+ default: { kind: "merge-keys" },
39
+ };
40
+ //# sourceMappingURL=helm-values.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"helm-values.js","sourceRoot":"","sources":["../../../src/format-profiles/profiles/helm-values.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,MAAM,UAAU,GAAG,CAAC,IAAa,EAAU,EAAE;IAC3C,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;QAChE,OAAO,MAAM,CAAE,IAA0B,CAAC,IAAI,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;AAC9B,CAAC,CAAC;AAEF,MAAM,CAAC,MAAM,iBAAiB,GAAkB;IAC9C,IAAI,EAAE,kBAAkB;IACxB,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE;QACpB,IAAI,CAAC,0BAA0B,CAAC,IAAI,CAAC,QAAQ,CAAC;YAAE,OAAO,KAAK,CAAC;QAC7D,OAAO,wBAAwB,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACjD,CAAC;IACD,KAAK,EAAE;QACL,gCAAgC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;QACvE,oCAAoC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;QAC3E,6BAA6B,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;QACpE,sCAAsC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE;KAC9E;IACD,OAAO,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE;CAChC,CAAC"}