@rsuci/shared-form-components 1.0.140 → 1.0.141
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/lib/__tests__/condition-engine-index.test.d.ts +6 -0
- package/dist/lib/__tests__/condition-engine-index.test.d.ts.map +1 -0
- package/dist/lib/__tests__/condition-engine-index.test.js +132 -0
- package/dist/lib/__tests__/groupeInstanceManager.test.js +1 -1
- package/dist/lib/condition-engine.d.ts.map +1 -1
- package/dist/lib/condition-engine.js +8 -2
- package/dist/lib/roster-condition-engine.js +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"condition-engine-index.test.d.ts","sourceRoot":"","sources":["../../../src/lib/__tests__/condition-engine-index.test.ts"],"names":[],"mappings":"AAAA;;;GAGG"}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests unitaires pour la pseudo-variable ${_INDEX_} dans le ConditionEngine
|
|
3
|
+
* Permet de référencer le numéro d'instance courant dans les groupes multiples
|
|
4
|
+
*/
|
|
5
|
+
import { ConditionEngine } from '../condition-engine';
|
|
6
|
+
function makeResponse(variableCode, valeur, numeroMembre) {
|
|
7
|
+
const key = numeroMembre ? `${variableCode}_${numeroMembre}` : variableCode;
|
|
8
|
+
return {
|
|
9
|
+
variableId: 1,
|
|
10
|
+
variableCode,
|
|
11
|
+
valeur,
|
|
12
|
+
numeroMembre,
|
|
13
|
+
dateModification: new Date(),
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
function buildResponses(entries) {
|
|
17
|
+
const responses = {};
|
|
18
|
+
for (const entry of entries) {
|
|
19
|
+
const key = entry.numeroMembre
|
|
20
|
+
? `${entry.variableCode}_${entry.numeroMembre}`
|
|
21
|
+
: entry.variableCode;
|
|
22
|
+
responses[key] = entry;
|
|
23
|
+
}
|
|
24
|
+
return responses;
|
|
25
|
+
}
|
|
26
|
+
describe('ConditionEngine - ${_INDEX_} pseudo-variable', () => {
|
|
27
|
+
describe('showMe avec _INDEX_', () => {
|
|
28
|
+
it('devrait retourner true quand _INDEX_ == instance courante', () => {
|
|
29
|
+
const engine = new ConditionEngine({});
|
|
30
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 1)', 1)).toBe(true);
|
|
31
|
+
});
|
|
32
|
+
it('devrait retourner false quand _INDEX_ != instance courante', () => {
|
|
33
|
+
const engine = new ConditionEngine({});
|
|
34
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 1)', 2)).toBe(false);
|
|
35
|
+
});
|
|
36
|
+
});
|
|
37
|
+
describe('hideMe avec _INDEX_', () => {
|
|
38
|
+
it('devrait retourner true (visible) quand la condition hideMe est fausse', () => {
|
|
39
|
+
const engine = new ConditionEngine({});
|
|
40
|
+
expect(engine.evaluate('hideMe(${_INDEX_} > 2)', 1)).toBe(true);
|
|
41
|
+
});
|
|
42
|
+
it('devrait retourner false (masqué) quand la condition hideMe est vraie', () => {
|
|
43
|
+
const engine = new ConditionEngine({});
|
|
44
|
+
expect(engine.evaluate('hideMe(${_INDEX_} > 2)', 3)).toBe(false);
|
|
45
|
+
});
|
|
46
|
+
});
|
|
47
|
+
describe('mix avec auto-suffixage', () => {
|
|
48
|
+
it('devrait combiner _INDEX_ et variables itératives', () => {
|
|
49
|
+
const responses = buildResponses([
|
|
50
|
+
makeResponse('AGE', 25, 1),
|
|
51
|
+
makeResponse('AGE', 15, 2),
|
|
52
|
+
]);
|
|
53
|
+
const engine = new ConditionEngine(responses);
|
|
54
|
+
engine.setMultipleGroupVariables(new Set(['AGE']));
|
|
55
|
+
// Instance 1 : _INDEX_ == 1 && AGE_1 (25) >= 18 → true
|
|
56
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 1 && ${AGE} >= 18)', 1)).toBe(true);
|
|
57
|
+
// Instance 2 : _INDEX_ == 1 → false (court-circuit)
|
|
58
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 1 && ${AGE} >= 18)', 2)).toBe(false);
|
|
59
|
+
});
|
|
60
|
+
});
|
|
61
|
+
describe('sans itération (currentIteration undefined)', () => {
|
|
62
|
+
it('devrait utiliser 1 par défaut', () => {
|
|
63
|
+
const engine = new ConditionEngine({});
|
|
64
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 1)')).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
it('devrait retourner false pour _INDEX_ != 1 sans itération', () => {
|
|
67
|
+
const engine = new ConditionEngine({});
|
|
68
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 2)')).toBe(false);
|
|
69
|
+
});
|
|
70
|
+
});
|
|
71
|
+
describe('opérateurs de comparaison', () => {
|
|
72
|
+
it('devrait supporter >=', () => {
|
|
73
|
+
const engine = new ConditionEngine({});
|
|
74
|
+
expect(engine.evaluate('${_INDEX_} >= 2', 2)).toBe(true);
|
|
75
|
+
expect(engine.evaluate('${_INDEX_} >= 2', 1)).toBe(false);
|
|
76
|
+
});
|
|
77
|
+
it('devrait supporter <', () => {
|
|
78
|
+
const engine = new ConditionEngine({});
|
|
79
|
+
expect(engine.evaluate('${_INDEX_} < 4', 3)).toBe(true);
|
|
80
|
+
expect(engine.evaluate('${_INDEX_} < 4', 4)).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
it('devrait supporter !=', () => {
|
|
83
|
+
const engine = new ConditionEngine({});
|
|
84
|
+
expect(engine.evaluate('${_INDEX_} != 1', 2)).toBe(true);
|
|
85
|
+
expect(engine.evaluate('${_INDEX_} != 1', 1)).toBe(false);
|
|
86
|
+
});
|
|
87
|
+
});
|
|
88
|
+
describe('isolation du cache', () => {
|
|
89
|
+
it('devrait retourner des résultats différents pour des instances différentes', () => {
|
|
90
|
+
const engine = new ConditionEngine({});
|
|
91
|
+
const condition = 'showMe(${_INDEX_} == 1)';
|
|
92
|
+
expect(engine.evaluate(condition, 1)).toBe(true);
|
|
93
|
+
expect(engine.evaluate(condition, 2)).toBe(false);
|
|
94
|
+
// Re-évaluer pour vérifier que le cache ne contamine pas
|
|
95
|
+
expect(engine.evaluate(condition, 1)).toBe(true);
|
|
96
|
+
});
|
|
97
|
+
});
|
|
98
|
+
describe('pas de suffixage de _INDEX_', () => {
|
|
99
|
+
it('ne devrait pas transformer _INDEX_ en _INDEX__2', () => {
|
|
100
|
+
const responses = buildResponses([
|
|
101
|
+
makeResponse('NOM', 'Jean', 1),
|
|
102
|
+
makeResponse('NOM', 'Marie', 2),
|
|
103
|
+
]);
|
|
104
|
+
const engine = new ConditionEngine(responses);
|
|
105
|
+
engine.setMultipleGroupVariables(new Set(['NOM']));
|
|
106
|
+
// Si _INDEX_ était suffixé, il deviendrait _INDEX__2 et l'évaluation échouerait
|
|
107
|
+
expect(engine.evaluate('showMe(${_INDEX_} == 2)', 2)).toBe(true);
|
|
108
|
+
});
|
|
109
|
+
});
|
|
110
|
+
describe('condition croisée avec index explicite', () => {
|
|
111
|
+
it('devrait évaluer la valeur du membre 1 depuis une autre instance', () => {
|
|
112
|
+
const responses = buildResponses([
|
|
113
|
+
makeResponse('C0_02', 'oui', 1),
|
|
114
|
+
makeResponse('C0_02', 'non', 2),
|
|
115
|
+
]);
|
|
116
|
+
const engine = new ConditionEngine(responses);
|
|
117
|
+
engine.setMultipleGroupVariables(new Set(['C0_02']));
|
|
118
|
+
// Depuis l'instance 2, référencer explicitement le membre 1
|
|
119
|
+
expect(engine.evaluate("showMe(${C0_02_1} == 'oui')", 2)).toBe(true);
|
|
120
|
+
// Depuis l'instance 1, la valeur du membre 2 est 'non'
|
|
121
|
+
expect(engine.evaluate("showMe(${C0_02_2} == 'oui')", 1)).toBe(false);
|
|
122
|
+
});
|
|
123
|
+
});
|
|
124
|
+
describe('_INDEX_ exclu de getReferencedVariables', () => {
|
|
125
|
+
it('ne devrait pas inclure _INDEX_ dans les variables référencées', () => {
|
|
126
|
+
const engine = new ConditionEngine({});
|
|
127
|
+
const refs = engine.getReferencedVariables('showMe(${_INDEX_} == 1 && ${AGE} >= 18)');
|
|
128
|
+
expect(refs).not.toContain('_INDEX_');
|
|
129
|
+
expect(refs).toContain('AGE');
|
|
130
|
+
});
|
|
131
|
+
});
|
|
132
|
+
});
|
|
@@ -154,7 +154,7 @@ describe('GroupeInstanceManager', () => {
|
|
|
154
154
|
it('devrait creer des instances basees sur les reponses existantes avec numeroMembre', () => {
|
|
155
155
|
const groupe = createMultipleGroupe();
|
|
156
156
|
const responses = {
|
|
157
|
-
...createControlResponse(
|
|
157
|
+
...createControlResponse(2),
|
|
158
158
|
'S1_01_1': createResponse('S1_01', 'Alice', 1),
|
|
159
159
|
'S1_02_1': createResponse('S1_02', '25', 1),
|
|
160
160
|
'S1_01_2': createResponse('S1_01', 'Bob', 2),
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/condition-engine.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAIvF,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,UAAU,CAAC;IACjB,cAAc,EAAE,MAAM,CAAC;IACvB,KAAK,EAAE,aAAa,CAAC;IACrB,SAAS,EAAE,MAAM,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;CACxB;AAGD,MAAM,WAAW,qBAAqB;IACpC,IAAI,EAAE,QAAQ,GAAG,QAAQ,GAAG,WAAW,CAAC;IACxC,MAAM,EAAE,OAAO,GAAG,UAAU,EAAE,CAAC;IAC/B,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED,qBAAa,eAAe;IAiBd,OAAO,CAAC,SAAS;IAhB7B,OAAO,CAAC,OAAO,CAAqC;IACpD,OAAO,CAAC,WAAW,CAAoB;IACvC,OAAO,CAAC,cAAc,CAAoE;IAC1F,OAAO,CAAC,YAAY,CAAO;IAC3B,OAAO,CAAC,sBAAsB,CAA0B;IAGxD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,8BAA8B,CAIpD;IAGF,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,wBAAwB,CAAuB;gBAEnD,SAAS,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC;IAI7D;;;;;;;;;;;;;;;;;OAiBG;IACH,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,gBAAgB,CAAC,EAAE,MAAM,GAAG,OAAO;IAuD/D;;;OAGG;IACH,OAAO,CAAC,WAAW;IAYnB;;OAEG;IACH,aAAa,CAAC,YAAY,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAAC,GAAG,IAAI;IAOjE;;;OAGG;IACH,yBAAyB,CAAC,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,GAAG,IAAI;IAIvD;;OAEG;IACH,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAKnD;;;;;OAKG;IACH,OAAO,CAAC,0BAA0B;IAgBlC;;OAEG;IACH,2BAA2B,CAAC,aAAa,EAAE,MAAM,EAAE,GAAG,IAAI;IAa1D;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAIzB;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAkB/B;;;OAGG;IACH,OAAO,CAAC,cAAc;IAwBtB;;;OAGG;IACH,OAAO,CAAC,cAAc;IAsBtB;;;;;OAKG;IACH,OAAO,CAAC,iBAAiB;IA8CzB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;IAwB5B;;OAEG;IACH,OAAO,CAAC,UAAU;IA0ClB;;;OAGG;IACH,OAAO,CAAC,UAAU;IA8FlB;;OAEG;IACH,cAAc,IAAI,UAAU,EAAE;IAI9B;;OAEG;IACH,gBAAgB,IAAI,IAAI;IAIxB;;;;;;;;OAQG;IACH,kBAAkB,CAChB,mBAAmB,EAAE,MAAM,EAC3B,YAAY,EAAE,MAAM,EACpB,gBAAgB,CAAC,EAAE,MAAM,GACxB,oBAAoB;IA4CvB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAwE7B;;OAEG;IACH,OAAO,CAAC,mCAAmC;IAS3C;;OAEG;IACH,OAAO,CAAC,gBAAgB;IASxB;;;;;;OAMG;IACH,OAAO,CAAC,YAAY;IA8BpB;;;OAGG;IACH,OAAO,CAAC,uCAAuC;
|
|
1
|
+
{"version":3,"file":"condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/condition-engine.ts"],"names":[],"mappings":"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"}
|
|
@@ -110,7 +110,7 @@ export class ConditionEngine {
|
|
|
110
110
|
*/
|
|
111
111
|
getReferencedVariables(condition) {
|
|
112
112
|
const matches = condition.match(/\$\{([A-Z_][A-Z0-9_]*(?:_\d+)?)\}/g);
|
|
113
|
-
return matches ? matches.map(match => match.slice(2, -1)) : [];
|
|
113
|
+
return matches ? matches.map(match => match.slice(2, -1)).filter(v => v !== '_INDEX_') : [];
|
|
114
114
|
}
|
|
115
115
|
/**
|
|
116
116
|
* Génère un hash du contexte pour les variables référencées dans une condition
|
|
@@ -588,7 +588,9 @@ export class ConditionEngine {
|
|
|
588
588
|
* ORDRE CORRIGÉ: suffixer d'abord, puis traiter les fonctions de date
|
|
589
589
|
*/
|
|
590
590
|
replaceVariableReferencesWithIterations(condition, currentIteration) {
|
|
591
|
-
// ÉTAPE
|
|
591
|
+
// ÉTAPE 0: Remplacer ${_INDEX_} par le numéro d'instance courant
|
|
592
|
+
condition = condition.replace(/\$\{_INDEX_\}/g, String(currentIteration ?? 1));
|
|
593
|
+
// ÉTAPE 1: Suffixer les références ${VAR} → ${VAR_index} AVANT les fonctions de date
|
|
592
594
|
if (currentIteration !== undefined) {
|
|
593
595
|
condition = this.suffixVariableReferences(condition, currentIteration);
|
|
594
596
|
}
|
|
@@ -632,6 +634,8 @@ export class ConditionEngine {
|
|
|
632
634
|
suffixVariableReferences(condition, iteration) {
|
|
633
635
|
// Regex pour capturer ${VAR} mais pas ${VAR_N} (déjà suffixé)
|
|
634
636
|
return condition.replace(/\$\{([A-Z_][A-Z0-9_]*)(?!_\d)\}/g, (match, varCode) => {
|
|
637
|
+
if (varCode === '_INDEX_')
|
|
638
|
+
return match;
|
|
635
639
|
// Si au moins une version itérative existe (ex: VAR_1), TOUJOURS suffixer
|
|
636
640
|
if (this.isIterativeVariable(varCode)) {
|
|
637
641
|
return `\${${varCode}_${iteration}}`;
|
|
@@ -644,6 +648,8 @@ export class ConditionEngine {
|
|
|
644
648
|
* Vérifie si une variable est de type itératif (groupe multiple)
|
|
645
649
|
*/
|
|
646
650
|
isIterativeVariable(varCode) {
|
|
651
|
+
if (varCode === '_INDEX_')
|
|
652
|
+
return false;
|
|
647
653
|
// Utiliser la connaissance structurelle des groupes multiples
|
|
648
654
|
// plutôt que de deviner depuis le contexte (fragile si _1 n'existe pas)
|
|
649
655
|
if (this.multipleGroupVariables.size > 0) {
|
|
@@ -154,7 +154,7 @@ export class RosterConditionEngine {
|
|
|
154
154
|
if (!condition)
|
|
155
155
|
return [];
|
|
156
156
|
const matches = condition.match(/\$\{([A-Z_][A-Z0-9_]*)\}/g) || [];
|
|
157
|
-
return matches.map(m => m.slice(2, -1));
|
|
157
|
+
return matches.map(m => m.slice(2, -1)).filter(v => v !== '_INDEX_');
|
|
158
158
|
}
|
|
159
159
|
/**
|
|
160
160
|
* Extrait la cible d'un jump s'il existe dans la condition (premier match uniquement)
|
package/package.json
CHANGED