@gitwand/core 2.5.0 → 2.6.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/dist/__tests__/refactoring/refactoring-pipeline.test.d.ts +14 -0
- package/dist/__tests__/refactoring/refactoring-pipeline.test.d.ts.map +1 -0
- package/dist/__tests__/refactoring/refactoring-pipeline.test.js +359 -0
- package/dist/__tests__/refactoring/refactoring-pipeline.test.js.map +1 -0
- package/dist/classifier.d.ts.map +1 -1
- package/dist/classifier.js +2 -0
- package/dist/classifier.js.map +1 -1
- package/dist/config.d.ts +20 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -1
- package/dist/patterns/refactoring-aware-merge.d.ts +52 -0
- package/dist/patterns/refactoring-aware-merge.d.ts.map +1 -0
- package/dist/patterns/refactoring-aware-merge.js +131 -0
- package/dist/patterns/refactoring-aware-merge.js.map +1 -0
- package/dist/refactoring/detect.d.ts +54 -0
- package/dist/refactoring/detect.d.ts.map +1 -0
- package/dist/refactoring/detect.js +389 -0
- package/dist/refactoring/detect.js.map +1 -0
- package/dist/refactoring/index.d.ts +13 -0
- package/dist/refactoring/index.d.ts.map +1 -0
- package/dist/refactoring/index.js +12 -0
- package/dist/refactoring/index.js.map +1 -0
- package/dist/refactoring/invert.d.ts +53 -0
- package/dist/refactoring/invert.d.ts.map +1 -0
- package/dist/refactoring/invert.js +180 -0
- package/dist/refactoring/invert.js.map +1 -0
- package/dist/refactoring/orchestration.d.ts +65 -0
- package/dist/refactoring/orchestration.d.ts.map +1 -0
- package/dist/refactoring/orchestration.js +174 -0
- package/dist/refactoring/orchestration.js.map +1 -0
- package/dist/refactoring/replay.d.ts +74 -0
- package/dist/refactoring/replay.d.ts.map +1 -0
- package/dist/refactoring/replay.js +200 -0
- package/dist/refactoring/replay.js.map +1 -0
- package/dist/resolver/assemble.d.ts.map +1 -1
- package/dist/resolver/assemble.js +21 -0
- package/dist/resolver/assemble.js.map +1 -1
- package/dist/resolver/index.d.ts.map +1 -1
- package/dist/resolver/index.js +9 -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/types.d.ts +59 -1
- package/dist/types.d.ts.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Module refactoring (point d'entrée)
|
|
3
|
+
*
|
|
4
|
+
* Exporte le pipeline RefMerge et ses composants publics.
|
|
5
|
+
* Les exports internes (`detect`, `invert`, `replay`) sont volontairement
|
|
6
|
+
* exposés pour permettre des tests unitaires granulaires.
|
|
7
|
+
*/
|
|
8
|
+
export { detectRefactorings } from "./detect.js";
|
|
9
|
+
export { invertRefactorings } from "./invert.js";
|
|
10
|
+
export { replayRefactorings, mergeRefactorings } from "./replay.js";
|
|
11
|
+
export { tryRefMerge } from "./orchestration.js";
|
|
12
|
+
export type { RefMergeResult } from "./orchestration.js";
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/refactoring/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,YAAY,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Module refactoring (point d'entrée)
|
|
3
|
+
*
|
|
4
|
+
* Exporte le pipeline RefMerge et ses composants publics.
|
|
5
|
+
* Les exports internes (`detect`, `invert`, `replay`) sont volontairement
|
|
6
|
+
* exposés pour permettre des tests unitaires granulaires.
|
|
7
|
+
*/
|
|
8
|
+
export { detectRefactorings } from "./detect.js";
|
|
9
|
+
export { invertRefactorings } from "./invert.js";
|
|
10
|
+
export { replayRefactorings, mergeRefactorings } from "./replay.js";
|
|
11
|
+
export { tryRefMerge } from "./orchestration.js";
|
|
12
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/refactoring/index.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AACjD,OAAO,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACpE,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Inversion de refactorings (expérimental)
|
|
3
|
+
*
|
|
4
|
+
* Inverse les refactorings détectés par `detect.ts` pour ramener une branche
|
|
5
|
+
* à la nomenclature de la version de base avant la résolution textuelle.
|
|
6
|
+
*
|
|
7
|
+
* ## Rôle dans le pipeline RefMerge
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* base ──────────────────────────────────────────────────────┐
|
|
11
|
+
* ↘ (refactorings ours) │
|
|
12
|
+
* ours ──→ invertRefactorings(ours, refs_ours) ──→ ours' ├─→ merge textuel → merged'
|
|
13
|
+
* ↘ (refactorings theirs) │
|
|
14
|
+
* theirs → invertRefactorings(theirs, refs_theirs) → theirs' ┘
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Après inversion, `ours'` et `theirs'` utilisent la même nomenclature que
|
|
18
|
+
* `base`, ce qui rend le merge textuel robuste aux conflits de renommage.
|
|
19
|
+
*
|
|
20
|
+
* ## Algorithme
|
|
21
|
+
*
|
|
22
|
+
* Pour chaque `Refactoring` dans la liste :
|
|
23
|
+
* - `rename-local` : remplacer `newName` → `oldName` dans la portée (`scope`)
|
|
24
|
+
* - `rename-top-level` : remplacer `newName` → `oldName` dans tout le fichier
|
|
25
|
+
* - `move-method` : aucune inversion textuelle possible à ce stade
|
|
26
|
+
* (la méthode est déjà dans la classe cible — on laisse)
|
|
27
|
+
*
|
|
28
|
+
* ## Garanties
|
|
29
|
+
* - Retourne les lignes inchangées si la liste de refactorings est vide.
|
|
30
|
+
* - Retourne les lignes inchangées en cas d'erreur (safe by default).
|
|
31
|
+
* - Zéro import Node.js — compatible browser, Node.js, Tauri WebView.
|
|
32
|
+
*/
|
|
33
|
+
import type { Refactoring } from "../types.js";
|
|
34
|
+
/**
|
|
35
|
+
* Inverse une liste de refactorings dans les lignes d'une branche.
|
|
36
|
+
*
|
|
37
|
+
* Applique les inversions dans l'ordre inverse de la liste (le dernier
|
|
38
|
+
* refactoring détecté est inversé en premier) pour gérer correctement
|
|
39
|
+
* les chaînes de renommage.
|
|
40
|
+
*
|
|
41
|
+
* @param branchLines - Lignes de la branche (ours ou theirs) à inverser
|
|
42
|
+
* @param refactorings - Liste des refactorings détectés sur cette branche
|
|
43
|
+
* @returns Lignes avec les refactorings inversés, prêtes pour le merge textuel
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```ts
|
|
47
|
+
* const refs = detectRefactorings(baseLines, oursLines);
|
|
48
|
+
* const oursInverted = invertRefactorings(oursLines, refs);
|
|
49
|
+
* // oursInverted utilise maintenant la nomenclature de base
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare function invertRefactorings(branchLines: string[], refactorings: Refactoring[]): string[];
|
|
53
|
+
//# sourceMappingURL=invert.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invert.d.ts","sourceRoot":"","sources":["../../src/refactoring/invert.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAiI/C;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,YAAY,EAAE,WAAW,EAAE,GAC1B,MAAM,EAAE,CAgBV"}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Inversion de refactorings (expérimental)
|
|
3
|
+
*
|
|
4
|
+
* Inverse les refactorings détectés par `detect.ts` pour ramener une branche
|
|
5
|
+
* à la nomenclature de la version de base avant la résolution textuelle.
|
|
6
|
+
*
|
|
7
|
+
* ## Rôle dans le pipeline RefMerge
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* base ──────────────────────────────────────────────────────┐
|
|
11
|
+
* ↘ (refactorings ours) │
|
|
12
|
+
* ours ──→ invertRefactorings(ours, refs_ours) ──→ ours' ├─→ merge textuel → merged'
|
|
13
|
+
* ↘ (refactorings theirs) │
|
|
14
|
+
* theirs → invertRefactorings(theirs, refs_theirs) → theirs' ┘
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* Après inversion, `ours'` et `theirs'` utilisent la même nomenclature que
|
|
18
|
+
* `base`, ce qui rend le merge textuel robuste aux conflits de renommage.
|
|
19
|
+
*
|
|
20
|
+
* ## Algorithme
|
|
21
|
+
*
|
|
22
|
+
* Pour chaque `Refactoring` dans la liste :
|
|
23
|
+
* - `rename-local` : remplacer `newName` → `oldName` dans la portée (`scope`)
|
|
24
|
+
* - `rename-top-level` : remplacer `newName` → `oldName` dans tout le fichier
|
|
25
|
+
* - `move-method` : aucune inversion textuelle possible à ce stade
|
|
26
|
+
* (la méthode est déjà dans la classe cible — on laisse)
|
|
27
|
+
*
|
|
28
|
+
* ## Garanties
|
|
29
|
+
* - Retourne les lignes inchangées si la liste de refactorings est vide.
|
|
30
|
+
* - Retourne les lignes inchangées en cas d'erreur (safe by default).
|
|
31
|
+
* - Zéro import Node.js — compatible browser, Node.js, Tauri WebView.
|
|
32
|
+
*/
|
|
33
|
+
// ─── Utilitaires ──────────────────────────────────────────────────────────────
|
|
34
|
+
/** Échappe les caractères spéciaux pour une utilisation dans un RegExp. */
|
|
35
|
+
function escapeRegex(s) {
|
|
36
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Remplace toutes les occurrences d'un identifiant dans un texte,
|
|
40
|
+
* en respectant les limites de mots (`\b`) pour éviter les substitutions partielles.
|
|
41
|
+
*
|
|
42
|
+
* @param text - Texte source
|
|
43
|
+
* @param oldName - Identifiant à remplacer
|
|
44
|
+
* @param newName - Identifiant de remplacement
|
|
45
|
+
* @returns Texte avec les substitutions appliquées
|
|
46
|
+
*/
|
|
47
|
+
function replaceIdentifier(text, oldName, newName) {
|
|
48
|
+
const pattern = new RegExp(`\\b${escapeRegex(oldName)}\\b`, "g");
|
|
49
|
+
return text.replace(pattern, newName);
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Détermine si une ligne fait partie de la portée d'une fonction donnée.
|
|
53
|
+
*
|
|
54
|
+
* Heuristique : la portée commence à la dernière occurrence de la déclaration
|
|
55
|
+
* de `scope` avant la ligne, et s'étend jusqu'à ce que la profondeur des
|
|
56
|
+
* accolades revienne au niveau d'entrée.
|
|
57
|
+
*
|
|
58
|
+
* Cette implémentation opère sur le texte complet (join des lignes) et retourne
|
|
59
|
+
* une paire `[start, end]` d'indices de caractères délimitant la portée.
|
|
60
|
+
*
|
|
61
|
+
* Retourne `null` si la portée ne peut pas être localisée.
|
|
62
|
+
*/
|
|
63
|
+
function findScopeRange(text, scope) {
|
|
64
|
+
// Chercher la déclaration de la portée
|
|
65
|
+
const scopePattern = new RegExp(`(?:async\\s+)?function\\s+${escapeRegex(scope)}\\s*\\(` +
|
|
66
|
+
`|(?:const|let|var)\\s+${escapeRegex(scope)}\\s*=`, "g");
|
|
67
|
+
const match = scopePattern.exec(text);
|
|
68
|
+
if (!match)
|
|
69
|
+
return null;
|
|
70
|
+
const start = match.index;
|
|
71
|
+
let depth = 0;
|
|
72
|
+
let inScope = false;
|
|
73
|
+
let scopeStart = start;
|
|
74
|
+
let scopeEnd = text.length;
|
|
75
|
+
for (let i = start; i < text.length; i++) {
|
|
76
|
+
const ch = text[i];
|
|
77
|
+
if (ch === "{") {
|
|
78
|
+
if (!inScope) {
|
|
79
|
+
inScope = true;
|
|
80
|
+
scopeStart = i;
|
|
81
|
+
depth = 1;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
depth++;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else if (ch === "}" && inScope) {
|
|
88
|
+
depth--;
|
|
89
|
+
if (depth === 0) {
|
|
90
|
+
scopeEnd = i + 1;
|
|
91
|
+
break;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
if (!inScope)
|
|
96
|
+
return null;
|
|
97
|
+
// Return range from the function keyword (not just the body `{`) so that
|
|
98
|
+
// parameter names in the signature are also included in the replacement.
|
|
99
|
+
return [start, scopeEnd];
|
|
100
|
+
}
|
|
101
|
+
// ─── Inversion d'un refactoring ───────────────────────────────────────────────
|
|
102
|
+
/**
|
|
103
|
+
* Inverse un seul refactoring dans le texte complet du fichier.
|
|
104
|
+
*
|
|
105
|
+
* @param text - Contenu courant du fichier (branche à inverser)
|
|
106
|
+
* @param refactoring - Refactoring à inverser
|
|
107
|
+
* @returns Texte avec le refactoring inversé
|
|
108
|
+
*/
|
|
109
|
+
function invertOne(text, refactoring) {
|
|
110
|
+
const { kind, oldName, newName, scope } = refactoring;
|
|
111
|
+
switch (kind) {
|
|
112
|
+
case "rename-top-level": {
|
|
113
|
+
// Substitution globale : newName → oldName dans tout le fichier
|
|
114
|
+
if (!newName)
|
|
115
|
+
return text;
|
|
116
|
+
return replaceIdentifier(text, newName, oldName);
|
|
117
|
+
}
|
|
118
|
+
case "rename-local": {
|
|
119
|
+
// Substitution limitée à la portée `scope` si disponible
|
|
120
|
+
if (!newName)
|
|
121
|
+
return text;
|
|
122
|
+
if (!scope) {
|
|
123
|
+
// Pas de portée connue → substitution globale (plus conservative)
|
|
124
|
+
return replaceIdentifier(text, newName, oldName);
|
|
125
|
+
}
|
|
126
|
+
// Localiser la portée dans le texte
|
|
127
|
+
const range = findScopeRange(text, scope);
|
|
128
|
+
if (!range) {
|
|
129
|
+
// Portée introuvable → substitution globale (dégradation sûre)
|
|
130
|
+
return replaceIdentifier(text, newName, oldName);
|
|
131
|
+
}
|
|
132
|
+
const [scopeStart, scopeEnd] = range;
|
|
133
|
+
const before = text.slice(0, scopeStart);
|
|
134
|
+
const inside = text.slice(scopeStart, scopeEnd);
|
|
135
|
+
const after = text.slice(scopeEnd);
|
|
136
|
+
return before + replaceIdentifier(inside, newName, oldName) + after;
|
|
137
|
+
}
|
|
138
|
+
case "move-method": {
|
|
139
|
+
// Pas d'inversion textuelle : la méthode est déjà dans la nouvelle classe.
|
|
140
|
+
// L'orchestrateur gère ce cas différemment (merge structurel de la méthode).
|
|
141
|
+
return text;
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
// ─── API publique ─────────────────────────────────────────────────────────────
|
|
146
|
+
/**
|
|
147
|
+
* Inverse une liste de refactorings dans les lignes d'une branche.
|
|
148
|
+
*
|
|
149
|
+
* Applique les inversions dans l'ordre inverse de la liste (le dernier
|
|
150
|
+
* refactoring détecté est inversé en premier) pour gérer correctement
|
|
151
|
+
* les chaînes de renommage.
|
|
152
|
+
*
|
|
153
|
+
* @param branchLines - Lignes de la branche (ours ou theirs) à inverser
|
|
154
|
+
* @param refactorings - Liste des refactorings détectés sur cette branche
|
|
155
|
+
* @returns Lignes avec les refactorings inversés, prêtes pour le merge textuel
|
|
156
|
+
*
|
|
157
|
+
* @example
|
|
158
|
+
* ```ts
|
|
159
|
+
* const refs = detectRefactorings(baseLines, oursLines);
|
|
160
|
+
* const oursInverted = invertRefactorings(oursLines, refs);
|
|
161
|
+
* // oursInverted utilise maintenant la nomenclature de base
|
|
162
|
+
* ```
|
|
163
|
+
*/
|
|
164
|
+
export function invertRefactorings(branchLines, refactorings) {
|
|
165
|
+
try {
|
|
166
|
+
if (refactorings.length === 0)
|
|
167
|
+
return branchLines;
|
|
168
|
+
let text = branchLines.join("\n");
|
|
169
|
+
// Appliquer les inversions en ordre inverse
|
|
170
|
+
for (let i = refactorings.length - 1; i >= 0; i--) {
|
|
171
|
+
text = invertOne(text, refactorings[i]);
|
|
172
|
+
}
|
|
173
|
+
return text.split("\n");
|
|
174
|
+
}
|
|
175
|
+
catch {
|
|
176
|
+
// Dégradation silencieuse — retourner les lignes inchangées
|
|
177
|
+
return branchLines;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
//# sourceMappingURL=invert.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"invert.js","sourceRoot":"","sources":["../../src/refactoring/invert.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Pipeline RefMerge (expérimental)
|
|
3
|
+
*
|
|
4
|
+
* Orchestre la détection, inversion, merge textuel et rejeu des refactorings
|
|
5
|
+
* pour résoudre des conflits causés par des renommages concurrents.
|
|
6
|
+
*
|
|
7
|
+
* ## Pipeline complet
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* input (base, ours, theirs)
|
|
11
|
+
* ↓
|
|
12
|
+
* detectRefactorings(base, ours) → oursRefs
|
|
13
|
+
* detectRefactorings(base, theirs) → theirsRefs
|
|
14
|
+
* ↓
|
|
15
|
+
* si quota dépassé → abort (renvoyer null — trop risqué)
|
|
16
|
+
* ↓
|
|
17
|
+
* ours' = invertRefactorings(ours, oursRefs)
|
|
18
|
+
* theirs' = invertRefactorings(theirs, theirsRefs)
|
|
19
|
+
* ↓
|
|
20
|
+
* merge textuel sur (base, ours', theirs') → merged'
|
|
21
|
+
* ↓
|
|
22
|
+
* si merge textuel échoue → abort (renvoyer null)
|
|
23
|
+
* ↓
|
|
24
|
+
* merged = replayRefactorings(merged', mergeRefactorings(oursRefs, theirsRefs))
|
|
25
|
+
* ↓
|
|
26
|
+
* return { lines: merged, oursRefs, theirsRefs }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## Garanties
|
|
30
|
+
* - Retourne `null` si aucun refactoring détecté ou si le pipeline échoue.
|
|
31
|
+
* - Retourne `null` en cas d'erreur (never throws — safe by default).
|
|
32
|
+
* - Zéro import Node.js — compatible browser, Node.js, Tauri WebView.
|
|
33
|
+
*/
|
|
34
|
+
import type { ClassifyInput, Refactoring } from "../types.js";
|
|
35
|
+
/** Résultat du pipeline RefMerge pour un hunk. */
|
|
36
|
+
export interface RefMergeResult {
|
|
37
|
+
/** Lignes résolues après inversion + merge + rejeu. `null` si le pipeline a échoué. */
|
|
38
|
+
lines: string[] | null;
|
|
39
|
+
/** Raison de la résolution ou de l'échec. */
|
|
40
|
+
reason: string;
|
|
41
|
+
/** Refactorings détectés sur la branche ours (peut être vide). */
|
|
42
|
+
oursRefs: Refactoring[];
|
|
43
|
+
/** Refactorings détectés sur la branche theirs (peut être vide). */
|
|
44
|
+
theirsRefs: Refactoring[];
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Tente de résoudre un hunk via le pipeline RefMerge.
|
|
48
|
+
*
|
|
49
|
+
* @param input - Hunk d'entrée (oursLines, baseLines, theirsLines)
|
|
50
|
+
* @param maxRefactorings - Nombre maximum de refactorings autorisés par branche
|
|
51
|
+
* @returns Résultat du pipeline, ou `{ lines: null, ... }` si le pipeline échoue
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```ts
|
|
55
|
+
* const result = tryRefMerge(
|
|
56
|
+
* { oursLines: [...], baseLines: [...], theirsLines: [...], startLine: 1, endLine: 10 },
|
|
57
|
+
* 10,
|
|
58
|
+
* );
|
|
59
|
+
* if (result.lines !== null) {
|
|
60
|
+
* // La résolution RefMerge a réussi
|
|
61
|
+
* }
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export declare function tryRefMerge(input: ClassifyInput, maxRefactorings?: number): RefMergeResult;
|
|
65
|
+
//# sourceMappingURL=orchestration.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestration.d.ts","sourceRoot":"","sources":["../../src/refactoring/orchestration.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAQ9D,kDAAkD;AAClD,MAAM,WAAW,cAAc;IAC7B,uFAAuF;IACvF,KAAK,EAAE,MAAM,EAAE,GAAG,IAAI,CAAC;IACvB,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,QAAQ,EAAE,WAAW,EAAE,CAAC;IACxB,oEAAoE;IACpE,UAAU,EAAE,WAAW,EAAE,CAAC;CAC3B;AA6CD;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,WAAW,CACzB,KAAK,EAAE,aAAa,EACpB,eAAe,SAAK,GACnB,cAAc,CA0EhB"}
|
|
@@ -0,0 +1,174 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Pipeline RefMerge (expérimental)
|
|
3
|
+
*
|
|
4
|
+
* Orchestre la détection, inversion, merge textuel et rejeu des refactorings
|
|
5
|
+
* pour résoudre des conflits causés par des renommages concurrents.
|
|
6
|
+
*
|
|
7
|
+
* ## Pipeline complet
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* input (base, ours, theirs)
|
|
11
|
+
* ↓
|
|
12
|
+
* detectRefactorings(base, ours) → oursRefs
|
|
13
|
+
* detectRefactorings(base, theirs) → theirsRefs
|
|
14
|
+
* ↓
|
|
15
|
+
* si quota dépassé → abort (renvoyer null — trop risqué)
|
|
16
|
+
* ↓
|
|
17
|
+
* ours' = invertRefactorings(ours, oursRefs)
|
|
18
|
+
* theirs' = invertRefactorings(theirs, theirsRefs)
|
|
19
|
+
* ↓
|
|
20
|
+
* merge textuel sur (base, ours', theirs') → merged'
|
|
21
|
+
* ↓
|
|
22
|
+
* si merge textuel échoue → abort (renvoyer null)
|
|
23
|
+
* ↓
|
|
24
|
+
* merged = replayRefactorings(merged', mergeRefactorings(oursRefs, theirsRefs))
|
|
25
|
+
* ↓
|
|
26
|
+
* return { lines: merged, oursRefs, theirsRefs }
|
|
27
|
+
* ```
|
|
28
|
+
*
|
|
29
|
+
* ## Garanties
|
|
30
|
+
* - Retourne `null` si aucun refactoring détecté ou si le pipeline échoue.
|
|
31
|
+
* - Retourne `null` en cas d'erreur (never throws — safe by default).
|
|
32
|
+
* - Zéro import Node.js — compatible browser, Node.js, Tauri WebView.
|
|
33
|
+
*/
|
|
34
|
+
import { mergeNonOverlapping } from "../diff.js";
|
|
35
|
+
import { detectRefactorings } from "./detect.js";
|
|
36
|
+
import { invertRefactorings } from "./invert.js";
|
|
37
|
+
import { replayRefactorings, mergeRefactorings } from "./replay.js";
|
|
38
|
+
// ─── Merge textuel sur les versions inversées ─────────────────────────────────
|
|
39
|
+
/**
|
|
40
|
+
* Tente un merge textuel simple entre base, ours' et theirs'.
|
|
41
|
+
*
|
|
42
|
+
* Essaie dans l'ordre :
|
|
43
|
+
* 1. same_change : ours' === theirs' → prendre ours'
|
|
44
|
+
* 2. one_side_ours : theirs' === base → prendre ours'
|
|
45
|
+
* 3. one_side_they : ours' === base → prendre theirs'
|
|
46
|
+
* 4. non_overlapping : essayer `mergeNonOverlapping(base, ours', theirs')`
|
|
47
|
+
*
|
|
48
|
+
* @returns Les lignes fusionnées, ou `null` si chevauchement résiduel.
|
|
49
|
+
*/
|
|
50
|
+
function mergeInverted(base, oursInverted, theirsInverted) {
|
|
51
|
+
const oursText = oursInverted.join("\n");
|
|
52
|
+
const theirsText = theirsInverted.join("\n");
|
|
53
|
+
const baseText = base.join("\n");
|
|
54
|
+
// 1. same_change : les deux versions inversées sont identiques
|
|
55
|
+
if (oursText === theirsText) {
|
|
56
|
+
return [...oursInverted];
|
|
57
|
+
}
|
|
58
|
+
// 2. one_side_change : theirs' == base → prendre ours'
|
|
59
|
+
if (theirsText === baseText) {
|
|
60
|
+
return [...oursInverted];
|
|
61
|
+
}
|
|
62
|
+
// 3. one_side_change : ours' == base → prendre theirs'
|
|
63
|
+
if (oursText === baseText) {
|
|
64
|
+
return [...theirsInverted];
|
|
65
|
+
}
|
|
66
|
+
// 4. Tentative de merge non-overlapping (les changements résiduels ne se chevauchent pas)
|
|
67
|
+
return mergeNonOverlapping(base, oursInverted, theirsInverted);
|
|
68
|
+
}
|
|
69
|
+
// ─── Pipeline principal ───────────────────────────────────────────────────────
|
|
70
|
+
/**
|
|
71
|
+
* Tente de résoudre un hunk via le pipeline RefMerge.
|
|
72
|
+
*
|
|
73
|
+
* @param input - Hunk d'entrée (oursLines, baseLines, theirsLines)
|
|
74
|
+
* @param maxRefactorings - Nombre maximum de refactorings autorisés par branche
|
|
75
|
+
* @returns Résultat du pipeline, ou `{ lines: null, ... }` si le pipeline échoue
|
|
76
|
+
*
|
|
77
|
+
* @example
|
|
78
|
+
* ```ts
|
|
79
|
+
* const result = tryRefMerge(
|
|
80
|
+
* { oursLines: [...], baseLines: [...], theirsLines: [...], startLine: 1, endLine: 10 },
|
|
81
|
+
* 10,
|
|
82
|
+
* );
|
|
83
|
+
* if (result.lines !== null) {
|
|
84
|
+
* // La résolution RefMerge a réussi
|
|
85
|
+
* }
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function tryRefMerge(input, maxRefactorings = 10) {
|
|
89
|
+
try {
|
|
90
|
+
const { oursLines, baseLines, theirsLines } = input;
|
|
91
|
+
// Cas trivial : pas de base → le pipeline ne peut pas fonctionner
|
|
92
|
+
if (baseLines.length === 0) {
|
|
93
|
+
return {
|
|
94
|
+
lines: null,
|
|
95
|
+
reason: "RefMerge : base vide (diff2 uniquement) — pipeline inapplicable.",
|
|
96
|
+
oursRefs: [],
|
|
97
|
+
theirsRefs: [],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
// ── Phase 1 : Détection ─────────────────────────────────────────────────
|
|
101
|
+
const oursRefs = detectRefactorings(baseLines, oursLines, maxRefactorings);
|
|
102
|
+
const theirsRefs = detectRefactorings(baseLines, theirsLines, maxRefactorings);
|
|
103
|
+
// Si aucun refactoring détecté → laisser le pipeline standard gérer
|
|
104
|
+
if (oursRefs.length === 0 && theirsRefs.length === 0) {
|
|
105
|
+
return {
|
|
106
|
+
lines: null,
|
|
107
|
+
reason: "RefMerge : aucun refactoring détecté — fallback au pipeline standard.",
|
|
108
|
+
oursRefs: [],
|
|
109
|
+
theirsRefs: [],
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
// Si quota dépassé de chaque côté → trop risqué, abandonner
|
|
113
|
+
if (oursRefs.length >= maxRefactorings || theirsRefs.length >= maxRefactorings) {
|
|
114
|
+
return {
|
|
115
|
+
lines: null,
|
|
116
|
+
reason: `RefMerge : quota atteint (ours: ${oursRefs.length}, theirs: ${theirsRefs.length}) — fallback au pipeline standard.`,
|
|
117
|
+
oursRefs,
|
|
118
|
+
theirsRefs,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
// ── Phase 2 : Inversion ─────────────────────────────────────────────────
|
|
122
|
+
const oursInverted = invertRefactorings(oursLines, oursRefs);
|
|
123
|
+
const theirsInverted = invertRefactorings(theirsLines, theirsRefs);
|
|
124
|
+
// ── Phase 3 : Merge textuel sur les versions inversées ──────────────────
|
|
125
|
+
const mergedInverted = mergeInverted(baseLines, oursInverted, theirsInverted);
|
|
126
|
+
if (mergedInverted === null) {
|
|
127
|
+
return {
|
|
128
|
+
lines: null,
|
|
129
|
+
reason: "RefMerge : chevauchement résiduel après inversion — fallback au pipeline standard.",
|
|
130
|
+
oursRefs,
|
|
131
|
+
theirsRefs,
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
// ── Phase 4 : Rejeu ─────────────────────────────────────────────────────
|
|
135
|
+
const allRefs = mergeRefactorings(oursRefs, theirsRefs);
|
|
136
|
+
const finalLines = replayRefactorings(mergedInverted, allRefs);
|
|
137
|
+
const summary = summarizeRefs(oursRefs, theirsRefs);
|
|
138
|
+
return {
|
|
139
|
+
lines: finalLines,
|
|
140
|
+
reason: `RefMerge : ${summary} — résolution par inversion+merge+rejeu.`,
|
|
141
|
+
oursRefs,
|
|
142
|
+
theirsRefs,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
catch {
|
|
146
|
+
// Dégradation silencieuse — jamais crasher le pipeline principal
|
|
147
|
+
return {
|
|
148
|
+
lines: null,
|
|
149
|
+
reason: "RefMerge : erreur interne — fallback au pipeline standard.",
|
|
150
|
+
oursRefs: [],
|
|
151
|
+
theirsRefs: [],
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
// ─── Utilitaires ──────────────────────────────────────────────────────────────
|
|
156
|
+
/** Produit un résumé compact des refactorings pour le trace. */
|
|
157
|
+
function summarizeRefs(oursRefs, theirsRefs) {
|
|
158
|
+
const parts = [];
|
|
159
|
+
const allRefs = [...oursRefs, ...theirsRefs];
|
|
160
|
+
const renames = allRefs.filter((r) => r.kind !== "move-method");
|
|
161
|
+
const moves = allRefs.filter((r) => r.kind === "move-method");
|
|
162
|
+
if (renames.length > 0) {
|
|
163
|
+
const sample = renames
|
|
164
|
+
.slice(0, 2)
|
|
165
|
+
.map((r) => `${r.oldName}→${r.newName ?? "?"}`)
|
|
166
|
+
.join(", ");
|
|
167
|
+
parts.push(`${renames.length} rename(s) [${sample}${renames.length > 2 ? "…" : ""}]`);
|
|
168
|
+
}
|
|
169
|
+
if (moves.length > 0) {
|
|
170
|
+
parts.push(`${moves.length} move-method(s)`);
|
|
171
|
+
}
|
|
172
|
+
return parts.join(", ");
|
|
173
|
+
}
|
|
174
|
+
//# sourceMappingURL=orchestration.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestration.js","sourceRoot":"","sources":["../../src/refactoring/orchestration.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* GitWand v2.6 — Rejeu de refactorings (expérimental)
|
|
3
|
+
*
|
|
4
|
+
* Rejoue les refactorings sur le résultat du merge textuel pour produire
|
|
5
|
+
* la sortie finale RefMerge.
|
|
6
|
+
*
|
|
7
|
+
* ## Rôle dans le pipeline RefMerge
|
|
8
|
+
*
|
|
9
|
+
* ```
|
|
10
|
+
* merged' (résultat du merge textuel sur les branches inversées)
|
|
11
|
+
* │
|
|
12
|
+
* ↓ replayRefactorings(merged', refs_ours ∪ refs_theirs)
|
|
13
|
+
* │
|
|
14
|
+
* merged (sortie finale — nomenclature de la branche qui a renommé)
|
|
15
|
+
* ```
|
|
16
|
+
*
|
|
17
|
+
* ## Stratégie de rejeu
|
|
18
|
+
*
|
|
19
|
+
* Quand ours et theirs ont tous deux renommé le même symbole (ex: `x` → `y`
|
|
20
|
+
* des deux côtés), le rejeu est simple : appliquer une fois.
|
|
21
|
+
*
|
|
22
|
+
* Quand ours et theirs ont renommé différemment (ex: ours `x` → `y`,
|
|
23
|
+
* theirs `x` → `z`), c'est un conflit de renommage réel. Le pipeline
|
|
24
|
+
* RefMerge préfère le renommage de **ours** dans ce cas (comportement
|
|
25
|
+
* analogue à `prefer-ours` pour les renommages). Le conflit résiduel est
|
|
26
|
+
* tracé dans le `DecisionTrace` par l'orchestrateur.
|
|
27
|
+
*
|
|
28
|
+
* ## Algorithme
|
|
29
|
+
*
|
|
30
|
+
* Pour chaque `Refactoring` dans la liste (dédupliquée) :
|
|
31
|
+
* - `rename-local` : remplacer `oldName` → `newName` dans la portée
|
|
32
|
+
* - `rename-top-level` : remplacer `oldName` → `newName` dans tout le texte
|
|
33
|
+
* - `move-method` : no-op (déjà géré par le merge structurel)
|
|
34
|
+
*
|
|
35
|
+
* ## Garanties
|
|
36
|
+
* - Retourne les lignes inchangées si la liste est vide.
|
|
37
|
+
* - Retourne les lignes inchangées en cas d'erreur (safe by default).
|
|
38
|
+
* - Zéro import Node.js — compatible browser, Node.js, Tauri WebView.
|
|
39
|
+
*/
|
|
40
|
+
import type { Refactoring } from "../types.js";
|
|
41
|
+
/**
|
|
42
|
+
* Déduplique et fusionne deux listes de refactorings (ours + theirs).
|
|
43
|
+
*
|
|
44
|
+
* Règles :
|
|
45
|
+
* 1. Si ours et theirs ont le même `(kind, oldName, newName)` → garder une copie.
|
|
46
|
+
* 2. Si ours et theirs ont renommé le même `oldName` différemment →
|
|
47
|
+
* préférer ours (comportement `prefer-ours` pour les renommages).
|
|
48
|
+
* 3. Les refactorings sans conflit des deux côtés sont tous inclus.
|
|
49
|
+
* 4. Les `move-method` sont inclus sans déduplication (clé = `oldName + sourceClass`).
|
|
50
|
+
*
|
|
51
|
+
* @returns Liste déduplicée, avec les refactorings ours prioritaires en cas de conflit.
|
|
52
|
+
*/
|
|
53
|
+
export declare function mergeRefactorings(oursRefs: Refactoring[], theirsRefs: Refactoring[]): Refactoring[];
|
|
54
|
+
/**
|
|
55
|
+
* Rejoue une liste de refactorings sur les lignes du résultat de merge.
|
|
56
|
+
*
|
|
57
|
+
* Applique les refactorings dans leur ordre naturel (premier détecté =
|
|
58
|
+
* premier rejoué), ce qui est l'inverse de l'ordre d'inversion.
|
|
59
|
+
* Cette symétrie garantit que `replay(invert(branch, refs), refs) ≈ branch`
|
|
60
|
+
* à isomorphisme de merge près.
|
|
61
|
+
*
|
|
62
|
+
* @param mergedLines - Lignes du résultat du merge textuel (base inversée)
|
|
63
|
+
* @param refactorings - Liste des refactorings à rejouer (déjà déduplicée)
|
|
64
|
+
* @returns Lignes avec les refactorings réappliqués, prêtes comme sortie finale
|
|
65
|
+
*
|
|
66
|
+
* @example
|
|
67
|
+
* ```ts
|
|
68
|
+
* const refs = mergeRefactorings(oursRefs, theirsRefs);
|
|
69
|
+
* const finalLines = replayRefactorings(mergedLines, refs);
|
|
70
|
+
* // finalLines utilise la nomenclature finale (post-refactoring)
|
|
71
|
+
* ```
|
|
72
|
+
*/
|
|
73
|
+
export declare function replayRefactorings(mergedLines: string[], refactorings: Refactoring[]): string[];
|
|
74
|
+
//# sourceMappingURL=replay.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay.d.ts","sourceRoot":"","sources":["../../src/refactoring/replay.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsCG;AAEH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AA+D/C;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAC/B,QAAQ,EAAE,WAAW,EAAE,EACvB,UAAU,EAAE,WAAW,EAAE,GACxB,WAAW,EAAE,CAqBf;AAmDD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,kBAAkB,CAChC,WAAW,EAAE,MAAM,EAAE,EACrB,YAAY,EAAE,WAAW,EAAE,GAC1B,MAAM,EAAE,CAeV"}
|