@gitwand/core 2.0.1 → 2.3.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.
- package/README.md +58 -0
- package/dist/__tests__/bench.bench.js +39 -0
- package/dist/__tests__/bench.bench.js.map +1 -1
- package/dist/__tests__/corpus.d.ts.map +1 -1
- package/dist/__tests__/corpus.js +363 -0
- package/dist/__tests__/corpus.js.map +1 -1
- package/dist/__tests__/diff/block-move.test.d.ts +5 -0
- package/dist/__tests__/diff/block-move.test.d.ts.map +1 -0
- package/dist/__tests__/diff/block-move.test.js +132 -0
- package/dist/__tests__/diff/block-move.test.js.map +1 -0
- package/dist/__tests__/diff/histogram.test.d.ts +8 -0
- package/dist/__tests__/diff/histogram.test.d.ts.map +1 -0
- package/dist/__tests__/diff/histogram.test.js +150 -0
- package/dist/__tests__/diff/histogram.test.js.map +1 -0
- package/dist/__tests__/diff/parity.test.d.ts +17 -0
- package/dist/__tests__/diff/parity.test.d.ts.map +1 -0
- package/dist/__tests__/diff/parity.test.js +149 -0
- package/dist/__tests__/diff/parity.test.js.map +1 -0
- package/dist/__tests__/diff.test.js +6 -2
- package/dist/__tests__/diff.test.js.map +1 -1
- package/dist/__tests__/format-profiles/integration.test.d.ts +7 -0
- package/dist/__tests__/format-profiles/integration.test.d.ts.map +1 -0
- package/dist/__tests__/format-profiles/integration.test.js +193 -0
- package/dist/__tests__/format-profiles/integration.test.js.map +1 -0
- package/dist/__tests__/format-profiles/json-patch.test.d.ts +12 -0
- package/dist/__tests__/format-profiles/json-patch.test.d.ts.map +1 -0
- package/dist/__tests__/format-profiles/json-patch.test.js +222 -0
- package/dist/__tests__/format-profiles/json-patch.test.js.map +1 -0
- package/dist/__tests__/format-profiles/registry.test.d.ts +5 -0
- package/dist/__tests__/format-profiles/registry.test.d.ts.map +1 -0
- package/dist/__tests__/format-profiles/registry.test.js +124 -0
- package/dist/__tests__/format-profiles/registry.test.js.map +1 -0
- package/dist/__tests__/patterns/make-score.test.d.ts +9 -0
- package/dist/__tests__/patterns/make-score.test.d.ts.map +1 -0
- package/dist/__tests__/patterns/make-score.test.js +49 -0
- package/dist/__tests__/patterns/make-score.test.js.map +1 -0
- package/dist/__tests__/structural/grandeur-nature.test.d.ts +31 -0
- package/dist/__tests__/structural/grandeur-nature.test.d.ts.map +1 -0
- package/dist/__tests__/structural/grandeur-nature.test.js +264 -0
- package/dist/__tests__/structural/grandeur-nature.test.js.map +1 -0
- package/dist/__tests__/structural/languages.test.d.ts +5 -0
- package/dist/__tests__/structural/languages.test.d.ts.map +1 -0
- package/dist/__tests__/structural/languages.test.js +74 -0
- package/dist/__tests__/structural/languages.test.js.map +1 -0
- package/dist/__tests__/structural/matching.test.d.ts +6 -0
- package/dist/__tests__/structural/matching.test.d.ts.map +1 -0
- package/dist/__tests__/structural/matching.test.js +113 -0
- package/dist/__tests__/structural/matching.test.js.map +1 -0
- package/dist/__tests__/structural/merge.test.d.ts +6 -0
- package/dist/__tests__/structural/merge.test.d.ts.map +1 -0
- package/dist/__tests__/structural/merge.test.js +117 -0
- package/dist/__tests__/structural/merge.test.js.map +1 -0
- package/dist/__tests__/structural/reconstruct.test.d.ts +6 -0
- package/dist/__tests__/structural/reconstruct.test.d.ts.map +1 -0
- package/dist/__tests__/structural/reconstruct.test.js +104 -0
- package/dist/__tests__/structural/reconstruct.test.js.map +1 -0
- package/dist/__tests__/structural/structural-index.test.d.ts +14 -0
- package/dist/__tests__/structural/structural-index.test.d.ts.map +1 -0
- package/dist/__tests__/structural/structural-index.test.js +108 -0
- package/dist/__tests__/structural/structural-index.test.js.map +1 -0
- package/dist/diff/block-move.d.ts +53 -0
- package/dist/diff/block-move.d.ts.map +1 -0
- package/dist/diff/block-move.js +192 -0
- package/dist/diff/block-move.js.map +1 -0
- package/dist/diff/histogram.d.ts +45 -0
- package/dist/diff/histogram.d.ts.map +1 -0
- package/dist/diff/histogram.js +172 -0
- package/dist/diff/histogram.js.map +1 -0
- package/dist/diff/index.d.ts +30 -0
- package/dist/diff/index.d.ts.map +1 -0
- package/dist/diff/index.js +47 -0
- package/dist/diff/index.js.map +1 -0
- package/dist/diff/lcs.d.ts +34 -0
- package/dist/diff/lcs.d.ts.map +1 -0
- package/dist/diff/lcs.js +184 -0
- package/dist/diff/lcs.js.map +1 -0
- package/dist/diff/shared.d.ts +54 -0
- package/dist/diff/shared.d.ts.map +1 -0
- package/dist/diff/shared.js +164 -0
- package/dist/diff/shared.js.map +1 -0
- package/dist/diff.d.ts +6 -65
- package/dist/diff.d.ts.map +1 -1
- package/dist/diff.js +6 -324
- package/dist/diff.js.map +1 -1
- package/dist/format-profiles/index.d.ts +34 -0
- package/dist/format-profiles/index.d.ts.map +1 -0
- package/dist/format-profiles/index.js +86 -0
- package/dist/format-profiles/index.js.map +1 -0
- package/dist/format-profiles/json-patch.d.ts +61 -0
- package/dist/format-profiles/json-patch.d.ts.map +1 -0
- package/dist/format-profiles/json-patch.js +269 -0
- package/dist/format-profiles/json-patch.js.map +1 -0
- package/dist/format-profiles/merge-strategies.d.ts +54 -0
- package/dist/format-profiles/merge-strategies.d.ts.map +1 -0
- package/dist/format-profiles/merge-strategies.js +156 -0
- package/dist/format-profiles/merge-strategies.js.map +1 -0
- package/dist/format-profiles/profiles/composer.d.ts +18 -0
- package/dist/format-profiles/profiles/composer.d.ts.map +1 -0
- package/dist/format-profiles/profiles/composer.js +45 -0
- package/dist/format-profiles/profiles/composer.js.map +1 -0
- package/dist/format-profiles/profiles/helm-values.d.ts +21 -0
- package/dist/format-profiles/profiles/helm-values.d.ts.map +1 -0
- package/dist/format-profiles/profiles/helm-values.js +40 -0
- package/dist/format-profiles/profiles/helm-values.js.map +1 -0
- package/dist/format-profiles/profiles/kubernetes.d.ts +22 -0
- package/dist/format-profiles/profiles/kubernetes.d.ts.map +1 -0
- package/dist/format-profiles/profiles/kubernetes.js +60 -0
- package/dist/format-profiles/profiles/kubernetes.js.map +1 -0
- package/dist/format-profiles/profiles/package-json.d.ts +18 -0
- package/dist/format-profiles/profiles/package-json.d.ts.map +1 -0
- package/dist/format-profiles/profiles/package-json.js +36 -0
- package/dist/format-profiles/profiles/package-json.js.map +1 -0
- package/dist/format-profiles/profiles/tsconfig.d.ts +21 -0
- package/dist/format-profiles/profiles/tsconfig.d.ts.map +1 -0
- package/dist/format-profiles/profiles/tsconfig.js +47 -0
- package/dist/format-profiles/profiles/tsconfig.js.map +1 -0
- package/dist/format-profiles/types.d.ts +67 -0
- package/dist/format-profiles/types.d.ts.map +1 -0
- package/dist/format-profiles/types.js +9 -0
- package/dist/format-profiles/types.js.map +1 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +10 -1
- package/dist/index.js.map +1 -1
- package/dist/patterns/insertion-at-boundary.d.ts.map +1 -1
- package/dist/patterns/insertion-at-boundary.js +15 -33
- package/dist/patterns/insertion-at-boundary.js.map +1 -1
- package/dist/patterns/utils.d.ts +11 -8
- package/dist/patterns/utils.d.ts.map +1 -1
- package/dist/patterns/utils.js +28 -10
- package/dist/patterns/utils.js.map +1 -1
- package/dist/resolver/format-dispatch.d.ts.map +1 -1
- package/dist/resolver/format-dispatch.js +3 -1
- package/dist/resolver/format-dispatch.js.map +1 -1
- package/dist/resolver/index.d.ts +14 -0
- package/dist/resolver/index.d.ts.map +1 -1
- package/dist/resolver/index.js +29 -0
- package/dist/resolver/index.js.map +1 -1
- package/dist/resolver/policy.d.ts.map +1 -1
- package/dist/resolver/policy.js +2 -0
- package/dist/resolver/policy.js.map +1 -1
- package/dist/resolvers/dispatcher.d.ts +22 -2
- package/dist/resolvers/dispatcher.d.ts.map +1 -1
- package/dist/resolvers/dispatcher.js +8 -3
- package/dist/resolvers/dispatcher.js.map +1 -1
- package/dist/resolvers/json.d.ts +11 -2
- package/dist/resolvers/json.d.ts.map +1 -1
- package/dist/resolvers/json.js +55 -7
- package/dist/resolvers/json.js.map +1 -1
- package/dist/resolvers/yaml.d.ts +8 -2
- package/dist/resolvers/yaml.d.ts.map +1 -1
- package/dist/resolvers/yaml.js +156 -2
- package/dist/resolvers/yaml.js.map +1 -1
- package/dist/structural/entities.d.ts +44 -0
- package/dist/structural/entities.d.ts.map +1 -0
- package/dist/structural/entities.js +315 -0
- package/dist/structural/entities.js.map +1 -0
- package/dist/structural/index.d.ts +48 -0
- package/dist/structural/index.d.ts.map +1 -0
- package/dist/structural/index.js +177 -0
- package/dist/structural/index.js.map +1 -0
- package/dist/structural/matching.d.ts +46 -0
- package/dist/structural/matching.d.ts.map +1 -0
- package/dist/structural/matching.js +83 -0
- package/dist/structural/matching.js.map +1 -0
- package/dist/structural/merge.d.ts +45 -0
- package/dist/structural/merge.d.ts.map +1 -0
- package/dist/structural/merge.js +127 -0
- package/dist/structural/merge.js.map +1 -0
- package/dist/structural/parsers/adapters/browser.d.ts +22 -0
- package/dist/structural/parsers/adapters/browser.d.ts.map +1 -0
- package/dist/structural/parsers/adapters/browser.js +27 -0
- package/dist/structural/parsers/adapters/browser.js.map +1 -0
- package/dist/structural/parsers/adapters/node.d.ts +18 -0
- package/dist/structural/parsers/adapters/node.d.ts.map +1 -0
- package/dist/structural/parsers/adapters/node.js +42 -0
- package/dist/structural/parsers/adapters/node.js.map +1 -0
- package/dist/structural/parsers/adapters/tauri.d.ts +26 -0
- package/dist/structural/parsers/adapters/tauri.d.ts.map +1 -0
- package/dist/structural/parsers/adapters/tauri.js +34 -0
- package/dist/structural/parsers/adapters/tauri.js.map +1 -0
- package/dist/structural/parsers/grammars/languages.d.ts +32 -0
- package/dist/structural/parsers/grammars/languages.d.ts.map +1 -0
- package/dist/structural/parsers/grammars/languages.js +73 -0
- package/dist/structural/parsers/grammars/languages.js.map +1 -0
- package/dist/structural/parsers/grammars/ts.d.ts +26 -0
- package/dist/structural/parsers/grammars/ts.d.ts.map +1 -0
- package/dist/structural/parsers/grammars/ts.js +46 -0
- package/dist/structural/parsers/grammars/ts.js.map +1 -0
- package/dist/structural/parsers/loader.d.ts +74 -0
- package/dist/structural/parsers/loader.d.ts.map +1 -0
- package/dist/structural/parsers/loader.js +181 -0
- package/dist/structural/parsers/loader.js.map +1 -0
- package/dist/structural/reconstruct.d.ts +28 -0
- package/dist/structural/reconstruct.d.ts.map +1 -0
- package/dist/structural/reconstruct.js +63 -0
- package/dist/structural/reconstruct.js.map +1 -0
- package/dist/types.d.ts +25 -0
- package/dist/types.d.ts.map +1 -1
- package/package.json +16 -2
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand — Registre de profils de format
|
|
3
|
+
*
|
|
4
|
+
* Le registre centralise les FormatProfile reconnus. Les consommateurs
|
|
5
|
+
* (tryResolveJsonConflict, tryResolveYamlConflict) appellent profileForFile()
|
|
6
|
+
* pour obtenir, le cas échéant, un profil applicable au filePath courant.
|
|
7
|
+
*
|
|
8
|
+
* Les profils sont essayés dans l'ordre d'enregistrement — le premier dont
|
|
9
|
+
* matches(filePath) retourne true gagne. Les built-ins sont enregistrés ici ;
|
|
10
|
+
* les consommateurs externes peuvent ajouter les leurs via registerFormatProfile.
|
|
11
|
+
*/
|
|
12
|
+
import { packageJsonProfile } from "./profiles/package-json.js";
|
|
13
|
+
import { tsconfigProfile } from "./profiles/tsconfig.js";
|
|
14
|
+
import { composerProfile } from "./profiles/composer.js";
|
|
15
|
+
import { helmValuesProfile } from "./profiles/helm-values.js";
|
|
16
|
+
import { kubernetesProfile } from "./profiles/kubernetes.js";
|
|
17
|
+
const PROFILES = [
|
|
18
|
+
packageJsonProfile,
|
|
19
|
+
tsconfigProfile,
|
|
20
|
+
composerProfile,
|
|
21
|
+
// YAML profiles : helm avant kubernetes (helm/values.yaml peut matcher les
|
|
22
|
+
// deux, on veut le plus spécifique en premier).
|
|
23
|
+
helmValuesProfile,
|
|
24
|
+
kubernetesProfile,
|
|
25
|
+
];
|
|
26
|
+
/**
|
|
27
|
+
* Cherche un profil applicable au filePath. Retourne null si aucun match.
|
|
28
|
+
*/
|
|
29
|
+
export function profileForFile(filePath) {
|
|
30
|
+
for (const profile of PROFILES) {
|
|
31
|
+
if (profile.matches(filePath))
|
|
32
|
+
return profile;
|
|
33
|
+
}
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Enregistre un profil custom. Inséré en tête (priorité sur les built-ins
|
|
38
|
+
* pour les filePath qu'il match), pratique pour qu'une extension VS Code ou
|
|
39
|
+
* un consommateur monorepo override un built-in.
|
|
40
|
+
*
|
|
41
|
+
* @returns une fonction d'unregister (pour cleanup propre dans les tests).
|
|
42
|
+
*/
|
|
43
|
+
export function registerFormatProfile(profile) {
|
|
44
|
+
PROFILES.unshift(profile);
|
|
45
|
+
return () => {
|
|
46
|
+
const idx = PROFILES.indexOf(profile);
|
|
47
|
+
if (idx >= 0)
|
|
48
|
+
PROFILES.splice(idx, 1);
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Résout la stratégie applicable à un chemin JSON Pointer dans un profil.
|
|
53
|
+
*
|
|
54
|
+
* Recherche : exact match d'abord, puis fallback à la stratégie par défaut
|
|
55
|
+
* du profil. Les wildcards "*" dans les paths du profil matchent un segment
|
|
56
|
+
* unique du pointer.
|
|
57
|
+
*/
|
|
58
|
+
export function strategyForPath(profile, pointer) {
|
|
59
|
+
// Match exact
|
|
60
|
+
if (profile.paths[pointer])
|
|
61
|
+
return profile.paths[pointer];
|
|
62
|
+
// Match avec wildcards : on convertit chaque path-clé du profil en regex
|
|
63
|
+
// (segments-by-segments, "*" → tout sauf "/").
|
|
64
|
+
for (const [pathKey, strategy] of Object.entries(profile.paths)) {
|
|
65
|
+
if (!pathKey.includes("*"))
|
|
66
|
+
continue;
|
|
67
|
+
if (matchesWildcardPath(pathKey, pointer))
|
|
68
|
+
return strategy;
|
|
69
|
+
}
|
|
70
|
+
return profile.default;
|
|
71
|
+
}
|
|
72
|
+
/** Match un JSON pointer contre un pattern à wildcards "*" (segment unique). */
|
|
73
|
+
function matchesWildcardPath(pattern, pointer) {
|
|
74
|
+
const patternSegs = pattern.split("/");
|
|
75
|
+
const pointerSegs = pointer.split("/");
|
|
76
|
+
if (patternSegs.length !== pointerSegs.length)
|
|
77
|
+
return false;
|
|
78
|
+
for (let i = 0; i < patternSegs.length; i++) {
|
|
79
|
+
if (patternSegs[i] === "*")
|
|
80
|
+
continue;
|
|
81
|
+
if (patternSegs[i] !== pointerSegs[i])
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
return true;
|
|
85
|
+
}
|
|
86
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/format-profiles/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,kBAAkB,EAAE,MAAM,4BAA4B,CAAC;AAChE,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7D,MAAM,QAAQ,GAAoB;IAChC,kBAAkB;IAClB,eAAe;IACf,eAAe;IACf,2EAA2E;IAC3E,gDAAgD;IAChD,iBAAiB;IACjB,iBAAiB;CAClB,CAAC;AAEF;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,QAAgB;IAC7C,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;QAC/B,IAAI,OAAO,CAAC,OAAO,CAAC,QAAQ,CAAC;YAAE,OAAO,OAAO,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,qBAAqB,CAAC,OAAsB;IAC1D,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IAC1B,OAAO,GAAG,EAAE;QACV,MAAM,GAAG,GAAG,QAAQ,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;QACtC,IAAI,GAAG,IAAI,CAAC;YAAE,QAAQ,CAAC,MAAM,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC;IACxC,CAAC,CAAC;AACJ,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,eAAe,CAC7B,OAAsB,EACtB,OAAe;IAEf,cAAc;IACd,IAAI,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC;QAAE,OAAO,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IAC1D,yEAAyE;IACzE,+CAA+C;IAC/C,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC;QAChE,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC;YAAE,SAAS;QACrC,IAAI,mBAAmB,CAAC,OAAO,EAAE,OAAO,CAAC;YAAE,OAAO,QAAQ,CAAC;IAC7D,CAAC;IACD,OAAO,OAAO,CAAC,OAAO,CAAC;AACzB,CAAC;AAED,gFAAgF;AAChF,SAAS,mBAAmB,CAAC,OAAe,EAAE,OAAe;IAC3D,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACvC,IAAI,WAAW,CAAC,MAAM,KAAK,WAAW,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC5D,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,WAAW,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QAC5C,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,GAAG;YAAE,SAAS;QACrC,IAAI,WAAW,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC;YAAE,OAAO,KAAK,CAAC;IACtD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,61 @@
|
|
|
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
|
+
import type { JsonPatchOp } from "./types.js";
|
|
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 declare function parseJsonPointer(pointer: string): string[];
|
|
22
|
+
/**
|
|
23
|
+
* Construit un JSON Pointer depuis un tableau de tokens. Échappe `~` et `/`.
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildJsonPointer(tokens: ReadonlyArray<string>): string;
|
|
26
|
+
/** Type minimum pour parcourir un JSON. `null` est une valeur valide (pas une absence). */
|
|
27
|
+
type JsonValue = unknown;
|
|
28
|
+
/**
|
|
29
|
+
* Applique une séquence d'opérations RFC 6902 à un document. Retourne le
|
|
30
|
+
* nouveau document (l'entrée n'est pas modifiée). Lance une `Error` si une
|
|
31
|
+
* opération réfère à un path inexistant (sauf `add` qui crée).
|
|
32
|
+
*/
|
|
33
|
+
export declare function applyJsonPatch(doc: JsonValue, ops: ReadonlyArray<JsonPatchOp>): JsonValue;
|
|
34
|
+
/**
|
|
35
|
+
* Calcule la séquence d'ops RFC 6902 qui transforme `base` en `target`.
|
|
36
|
+
*
|
|
37
|
+
* Stratégie : récursion structurelle. Sur les objets, on compare clé-par-clé
|
|
38
|
+
* (ajout / remove / récursion). Sur les tableaux, on émet `replace` global
|
|
39
|
+
* dès que les longueurs diffèrent ou qu'un élément à un index donné diffère —
|
|
40
|
+
* pas de LCS-on-arrays ici (c'est le rôle des stratégies `set` / `ordered-list`
|
|
41
|
+
* du registre, qui appellent `diffJson` à un niveau plus fin).
|
|
42
|
+
*/
|
|
43
|
+
export declare function diffJson(base: JsonValue, target: JsonValue): JsonPatchOp[];
|
|
44
|
+
/** Égalité structurelle (récursive) entre deux JSON values. */
|
|
45
|
+
export declare function jsonStructEqual(a: JsonValue, b: JsonValue): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Fusionne deux séquences d'ops. Si les paths sont disjoints (aucun path
|
|
48
|
+
* touché par les deux), on retourne la concaténation `[...ours, ...theirs]`.
|
|
49
|
+
* Sinon, on retourne `null` avec une liste des paths en conflit (utile pour
|
|
50
|
+
* la `DecisionTrace`).
|
|
51
|
+
*
|
|
52
|
+
* Disjoint = aucun path d'`ours` n'est égal ni préfixe d'un path de `theirs`,
|
|
53
|
+
* et vice versa. (Si `ours` modifie `/foo/bar` et `theirs` modifie `/foo`, ils
|
|
54
|
+
* sont en conflit même si les chaînes ne sont pas identiques.)
|
|
55
|
+
*/
|
|
56
|
+
export declare function mergeJsonPatches(ours: ReadonlyArray<JsonPatchOp>, theirs: ReadonlyArray<JsonPatchOp>): {
|
|
57
|
+
merged: JsonPatchOp[] | null;
|
|
58
|
+
conflictingPaths: string[];
|
|
59
|
+
};
|
|
60
|
+
export {};
|
|
61
|
+
//# sourceMappingURL=json-patch.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"json-patch.d.ts","sourceRoot":"","sources":["../../src/format-profiles/json-patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAI9C;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAS1D;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,GAAG,MAAM,CAQtE;AAID,2FAA2F;AAC3F,KAAK,SAAS,GAAG,OAAO,CAAC;AAazB;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,SAAS,EAAE,GAAG,EAAE,aAAa,CAAC,WAAW,CAAC,GAAG,SAAS,CAMzF;AAiFD;;;;;;;;GAQG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,GAAG,WAAW,EAAE,CAI1E;AA0CD,+DAA+D;AAC/D,wBAAgB,eAAe,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE,SAAS,GAAG,OAAO,CAsBnE;AAID;;;;;;;;;GASG;AACH,wBAAgB,gBAAgB,CAC9B,IAAI,EAAE,aAAa,CAAC,WAAW,CAAC,EAChC,MAAM,EAAE,aAAa,CAAC,WAAW,CAAC,GACjC;IAAE,MAAM,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;IAAC,gBAAgB,EAAE,MAAM,EAAE,CAAA;CAAE,CAc9D"}
|
|
@@ -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":"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"}
|