@rsuci/shared-form-components 1.0.16 → 1.0.18

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.
@@ -19,6 +19,7 @@ export interface RosterVariable {
19
19
  valeurDefaut?: string;
20
20
  ordre: number;
21
21
  estObligatoire?: boolean;
22
+ conditionsAffichage?: string;
22
23
  }
23
24
  export interface RosterPanelProps {
24
25
  option: RosterOption;
@@ -1 +1 @@
1
- {"version":3,"file":"RosterPanel.d.ts","sourceRoot":"","sources":["../../../src/components/roster/RosterPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAK,MAAM,OAAO,CAAC;AAM1B,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CAuI3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
1
+ {"version":3,"file":"RosterPanel.d.ts","sourceRoot":"","sources":["../../../src/components/roster/RosterPanel.tsx"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAIH,OAAO,KAAkB,MAAM,OAAO,CAAC;AAOvC,UAAU,YAAY;IACpB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;CACrB;AAGD,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,KAAK,EAAE,MAAM,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mBAAmB,CAAC,EAAE,MAAM,CAAC;CAC9B;AAGD,MAAM,WAAW,gBAAgB;IAC/B,MAAM,EAAE,YAAY,CAAC;IACrB,eAAe,EAAE,cAAc,EAAE,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;IAC3B,QAAQ,EAAE,CAAC,YAAY,EAAE,MAAM,EAAE,KAAK,EAAE,GAAG,KAAK,IAAI,CAAC;IACrD,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;IACpB,aAAa,CAAC,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,IAAI,CAAC;CAC5C;AAED,QAAA,MAAM,WAAW,EAAE,KAAK,CAAC,EAAE,CAAC,gBAAgB,CA+J3C,CAAC;AAEF,eAAe,WAAW,CAAC"}
@@ -7,12 +7,33 @@
7
7
  */
8
8
  'use client';
9
9
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
10
+ import { useMemo } from 'react';
10
11
  import VariableRenderer from '../VariableRenderer';
11
12
  import { cn } from '../../lib/utils/cn';
13
+ import { RosterConditionEngine } from '../../lib/roster-condition-engine';
12
14
  const RosterPanel = ({ option, rosterVariables, value, onChange, disabled, showCheckbox = false, isChecked = true, onCheckChange }) => {
13
15
  // Trier les variables par ordre
14
16
  const sortedVariables = [...rosterVariables].sort((a, b) => a.ordre - b.ordre);
15
- return (_jsxs("div", { className: cn('border border-gray-200 rounded-lg p-4 bg-white', 'shadow-sm hover:shadow-md transition-shadow', disabled && 'opacity-60'), children: [_jsx("div", { className: "border-b border-gray-100 pb-3 mb-4", children: _jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "flex items-center flex-1", children: [showCheckbox && (_jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onCheckChange?.(e.target.checked), disabled: disabled, className: cn('w-5 h-5 mr-3 text-green-600 border-gray-300 rounded focus:ring-green-500', disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer') })), _jsxs("div", { children: [_jsxs("h3", { className: "font-semibold text-lg text-gray-800 flex items-center", children: [_jsx("span", { className: "mr-2", children: "\uD83D\uDCCC" }), option.designation] }), _jsxs("p", { className: "text-xs text-blue-600 font-mono mt-1", children: ["(", option.code, ")"] })] })] }) }) }), !showCheckbox || isChecked ? (_jsx("div", { className: "space-y-4", children: sortedVariables.map(rosterVar => {
17
+ // Calculer les variables masquées par les jumps
18
+ const jumpedVariables = useMemo(() => {
19
+ return RosterConditionEngine.computeJumpedVariables(sortedVariables.map(v => ({ code: v.code, ordre: v.ordre, conditionsAffichage: v.conditionsAffichage })), value);
20
+ }, [sortedVariables, value]);
21
+ // Filtrer les variables visibles (conditions + jumps)
22
+ const visibleVariables = useMemo(() => {
23
+ return sortedVariables.filter(rosterVar => {
24
+ // Variable masquée par un jump actif
25
+ if (jumpedVariables.has(rosterVar.code)) {
26
+ return false;
27
+ }
28
+ // Pas de condition = visible
29
+ if (!rosterVar.conditionsAffichage) {
30
+ return true;
31
+ }
32
+ // Évaluer la condition avec les valeurs de cette ligne
33
+ return RosterConditionEngine.evaluate(rosterVar.conditionsAffichage, value);
34
+ });
35
+ }, [sortedVariables, jumpedVariables, value]);
36
+ return (_jsxs("div", { className: cn('border border-gray-200 rounded-lg p-4 bg-white', 'shadow-sm hover:shadow-md transition-shadow', disabled && 'opacity-60'), children: [_jsx("div", { className: "border-b border-gray-100 pb-3 mb-4", children: _jsx("div", { className: "flex items-center justify-between", children: _jsxs("div", { className: "flex items-center flex-1", children: [showCheckbox && (_jsx("input", { type: "checkbox", checked: isChecked, onChange: (e) => onCheckChange?.(e.target.checked), disabled: disabled, className: cn('w-5 h-5 mr-3 text-green-600 border-gray-300 rounded focus:ring-green-500', disabled ? 'cursor-not-allowed opacity-50' : 'cursor-pointer') })), _jsxs("div", { children: [_jsxs("h3", { className: "font-semibold text-lg text-gray-800 flex items-center", children: [_jsx("span", { className: "mr-2", children: "\uD83D\uDCCC" }), option.designation] }), _jsxs("p", { className: "text-xs text-blue-600 font-mono mt-1", children: ["(", option.code, ")"] })] })] }) }) }), !showCheckbox || isChecked ? (_jsx("div", { className: "space-y-4", children: visibleVariables.map(rosterVar => {
16
37
  // Créer un objet VariableFormulaire compatible avec VariableRenderer
17
38
  // Rendre le code unique par panel pour éviter les conflits de radios/checkboxes
18
39
  const uniqueCode = `${option.code}_${rosterVar.code}`;
package/dist/index.d.ts CHANGED
@@ -38,6 +38,7 @@ export type { VariableNodeState, GroupNodeState, JumpRange, JumpError, IFormTree
38
38
  export { VariableValueConverter } from './lib/utils/variableValueConverter';
39
39
  export { interpolateVariableLabel } from './lib/utils/interpolateVariableLabel';
40
40
  export { ConditionEngine } from './lib/condition-engine';
41
+ export { RosterConditionEngine, type RosterConditionError, type RosterConditionErrorType, type RosterConditionValidationResult, type RosterVariableRef } from './lib/roster-condition-engine';
41
42
  export { FormTree } from './lib/form-tree';
42
43
  export { useFormTree, type UseFormTreeOptions, type UseFormTreeReturn } from './hooks/useFormTree';
43
44
  export { cn } from './lib/utils/cn';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,4BAA4B,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,+BAA+B,CAAC;AAG5E,OAAO,EACL,OAAO,IAAI,gBAAgB,EAC3B,KAAK,qBAAqB,EAC3B,MAAM,sCAAsC,CAAC;AAE9C,OAAO,EACL,OAAO,IAAI,eAAe,EAC1B,KAAK,oBAAoB,EAC1B,MAAM,qCAAqC,CAAC;AAE7C,OAAO,EACL,OAAO,IAAI,WAAW,EACtB,KAAK,gBAAgB,EACrB,KAAK,cAAc,EACpB,MAAM,iCAAiC,CAAC;AAOzC,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAGhE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACzE,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,8BAA8B,CAAC;AACnE,OAAO,EAAE,OAAO,IAAI,UAAU,EAAE,MAAM,gCAAgC,CAAC;AACvE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,+BAA+B,CAAC;AAGrE,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,oCAAoC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAG3E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAM5E,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,qCAAqC,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,0CAA0C,CAAC;AACvF,OAAO,EAAE,OAAO,IAAI,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAC7F,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,MAAM,uCAAuC,CAAC;AACjF,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAM/E,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,oCAAoC,CAAC;AAC5E,OAAO,EAAE,OAAO,IAAI,YAAY,EAAE,MAAM,qCAAqC,CAAC;AAO9E,YAAY,EACV,cAAc,EACd,kBAAkB,EAClB,gBAAgB,EAChB,iBAAiB,EACjB,eAAe,EACf,cAAc,EACd,aAAa,EACb,YAAY,EACZ,eAAe,EACf,UAAU,EACV,eAAe,EAChB,MAAM,iBAAiB,CAAC;AAGzB,YAAY,EACV,oBAAoB,EACpB,oBAAoB,EACpB,qBAAqB,EACrB,mBAAmB,EACnB,wBAAwB,EACxB,2BAA2B,EAC3B,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,kBAAkB,CAAC;AAG1B,YAAY,EACV,iBAAiB,EACjB,kBAAkB,EAClB,qBAAqB,EACtB,MAAM,uBAAuB,CAAC;AAG/B,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,SAAS,EACT,SAAS,EACT,SAAS,EACT,eAAe,EACf,oBAAoB,EACrB,MAAM,mBAAmB,CAAC;AAO3B,OAAO,EAAE,sBAAsB,EAAE,MAAM,oCAAoC,CAAC;AAG5E,OAAO,EAAE,wBAAwB,EAAE,MAAM,sCAAsC,CAAC;AAGhF,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAGzD,OAAO,EACL,qBAAqB,EACrB,KAAK,oBAAoB,EACzB,KAAK,wBAAwB,EAC7B,KAAK,+BAA+B,EACpC,KAAK,iBAAiB,EACvB,MAAM,+BAA+B,CAAC;AAGvC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAO3C,OAAO,EAAE,WAAW,EAAE,KAAK,kBAAkB,EAAE,KAAK,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAGnG,OAAO,EAAE,EAAE,EAAE,MAAM,gBAAgB,CAAC"}
package/dist/index.js CHANGED
@@ -58,6 +58,8 @@ export { VariableValueConverter } from './lib/utils/variableValueConverter';
58
58
  export { interpolateVariableLabel } from './lib/utils/interpolateVariableLabel';
59
59
  // Moteur de conditions
60
60
  export { ConditionEngine } from './lib/condition-engine';
61
+ // Moteur de conditions scopées pour les ROSTER
62
+ export { RosterConditionEngine } from './lib/roster-condition-engine';
61
63
  // FormTree (arbre virtuel du formulaire)
62
64
  export { FormTree } from './lib/form-tree';
63
65
  // ========================================
@@ -0,0 +1,75 @@
1
+ /**
2
+ * Moteur d'évaluation des conditions scopées pour les variables ROSTER
3
+ * RSU v2 - Moteur de Rendu des Formulaires d'Enquête
4
+ *
5
+ * Ce moteur est ISOLÉ du ConditionEngine principal.
6
+ * Les conditions sont évaluées PAR LIGNE (par option de roster) indépendamment.
7
+ * Le scope est limité aux variables du même ROSTER uniquement.
8
+ */
9
+ export type RosterConditionErrorType = 'variable_not_in_scope' | 'jump_out_of_scope' | 'backward_jump' | 'self_reference' | 'syntax_error';
10
+ export interface RosterConditionError {
11
+ type: RosterConditionErrorType;
12
+ variableCode: string;
13
+ message: string;
14
+ }
15
+ export interface RosterConditionValidationResult {
16
+ isValid: boolean;
17
+ errors: RosterConditionError[];
18
+ }
19
+ export interface RosterVariableRef {
20
+ code: string;
21
+ ordre: number;
22
+ }
23
+ /**
24
+ * Moteur de conditions scopées pour les ROSTER
25
+ * Toutes les méthodes sont statiques pour une utilisation sans état
26
+ */
27
+ export declare class RosterConditionEngine {
28
+ /**
29
+ * Valide une condition au moment du design (admin)
30
+ * Vérifie que les références sont dans le scope et que les jumps sont valides
31
+ */
32
+ static validateCondition(condition: string, availableVariables: RosterVariableRef[], currentVariableCode: string, currentVariableOrdre: number): RosterConditionValidationResult;
33
+ /**
34
+ * Évalue une condition au runtime (rendu)
35
+ * Utilise les valeurs de la ligne courante du roster
36
+ */
37
+ static evaluate(condition: string, lineValues: Record<string, any>): boolean;
38
+ /**
39
+ * Extrait toutes les références de variables d'une condition
40
+ * Format: ${VAR_CODE}
41
+ */
42
+ static extractVariableReferences(condition: string): string[];
43
+ /**
44
+ * Extrait la cible d'un jump s'il existe dans la condition (premier match uniquement)
45
+ * Format: jump(condition, ${TARGET})
46
+ * @deprecated Utiliser extractAllJumps pour supporter les jumps multiples
47
+ */
48
+ static extractJumpTarget(condition: string): string | null;
49
+ /**
50
+ * Extrait TOUS les jumps d'une condition
51
+ * Supporte: jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
52
+ * Retourne un tableau de { fullExpression, innerCondition, target }
53
+ */
54
+ static extractAllJumps(condition: string): Array<{
55
+ fullExpression: string;
56
+ innerCondition: string;
57
+ target: string;
58
+ }>;
59
+ /**
60
+ * Calcule les variables qui doivent être masquées à cause des jumps actifs
61
+ * Supporte les jumps multiples avec court-circuit:
62
+ * - jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
63
+ * - Si cond1 est vraie, on saute à VAR1 et cond2 n'est pas évaluée
64
+ */
65
+ static computeJumpedVariables(sortedVariables: RosterVariableRef[], lineValues: Record<string, any>): Set<string>;
66
+ /**
67
+ * Évalue une condition interne (sans le wrapper jump())
68
+ */
69
+ private static evaluateInnerCondition;
70
+ /**
71
+ * Valide la syntaxe de base d'une condition
72
+ */
73
+ private static validateSyntax;
74
+ }
75
+ //# sourceMappingURL=roster-condition-engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"roster-condition-engine.d.ts","sourceRoot":"","sources":["../../src/lib/roster-condition-engine.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,MAAM,wBAAwB,GAChC,uBAAuB,GACvB,mBAAmB,GACnB,eAAe,GACf,gBAAgB,GAChB,cAAc,CAAC;AAEnB,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,wBAAwB,CAAC;IAC/B,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,oBAAoB,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,iBAAiB;IAChC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,qBAAa,qBAAqB;IAEhC;;;OAGG;IACH,MAAM,CAAC,iBAAiB,CACtB,SAAS,EAAE,MAAM,EACjB,kBAAkB,EAAE,iBAAiB,EAAE,EACvC,mBAAmB,EAAE,MAAM,EAC3B,oBAAoB,EAAE,MAAM,GAC3B,+BAA+B;IAgElC;;;OAGG;IACH,MAAM,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,OAAO;IAyB5E;;;OAGG;IACH,MAAM,CAAC,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,EAAE;IAO7D;;;;OAIG;IACH,MAAM,CAAC,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI;IAO1D;;;;OAIG;IACH,MAAM,CAAC,eAAe,CAAC,SAAS,EAAE,MAAM,GAAG,KAAK,CAAC;QAC/C,cAAc,EAAE,MAAM,CAAC;QACvB,cAAc,EAAE,MAAM,CAAC;QACvB,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC;IAoBF;;;;;OAKG;IACH,MAAM,CAAC,sBAAsB,CAC3B,eAAe,EAAE,iBAAiB,EAAE,EACpC,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAC9B,GAAG,CAAC,MAAM,CAAC;IAmCd;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,sBAAsB;IA6BrC;;OAEG;IACH,OAAO,CAAC,MAAM,CAAC,cAAc;CA0B9B"}
@@ -0,0 +1,243 @@
1
+ /**
2
+ * Moteur d'évaluation des conditions scopées pour les variables ROSTER
3
+ * RSU v2 - Moteur de Rendu des Formulaires d'Enquête
4
+ *
5
+ * Ce moteur est ISOLÉ du ConditionEngine principal.
6
+ * Les conditions sont évaluées PAR LIGNE (par option de roster) indépendamment.
7
+ * Le scope est limité aux variables du même ROSTER uniquement.
8
+ */
9
+ import { ConditionEngine } from './condition-engine';
10
+ /**
11
+ * Moteur de conditions scopées pour les ROSTER
12
+ * Toutes les méthodes sont statiques pour une utilisation sans état
13
+ */
14
+ export class RosterConditionEngine {
15
+ /**
16
+ * Valide une condition au moment du design (admin)
17
+ * Vérifie que les références sont dans le scope et que les jumps sont valides
18
+ */
19
+ static validateCondition(condition, availableVariables, currentVariableCode, currentVariableOrdre) {
20
+ const errors = [];
21
+ if (!condition?.trim()) {
22
+ return { isValid: true, errors: [] };
23
+ }
24
+ const availableCodes = new Set(availableVariables.map(v => v.code));
25
+ // 1. Vérifier les références de variables
26
+ const refs = this.extractVariableReferences(condition);
27
+ for (const ref of refs) {
28
+ if (ref === currentVariableCode) {
29
+ errors.push({
30
+ type: 'self_reference',
31
+ variableCode: ref,
32
+ message: 'Une variable ne peut pas se référencer elle-même'
33
+ });
34
+ }
35
+ else if (!availableCodes.has(ref)) {
36
+ errors.push({
37
+ type: 'variable_not_in_scope',
38
+ variableCode: ref,
39
+ message: `La variable \${${ref}} n'existe pas dans ce Roster`
40
+ });
41
+ }
42
+ }
43
+ // 2. Vérifier TOUS les jumps (supporte jump() || jump() || ...)
44
+ const allJumps = this.extractAllJumps(condition);
45
+ for (const jump of allJumps) {
46
+ if (!availableCodes.has(jump.target)) {
47
+ errors.push({
48
+ type: 'jump_out_of_scope',
49
+ variableCode: jump.target,
50
+ message: `La variable cible \${${jump.target}} n'existe pas dans ce Roster`
51
+ });
52
+ }
53
+ else {
54
+ const targetVar = availableVariables.find(v => v.code === jump.target);
55
+ if (targetVar && targetVar.ordre <= currentVariableOrdre) {
56
+ errors.push({
57
+ type: 'backward_jump',
58
+ variableCode: jump.target,
59
+ message: `Le jump vers \${${jump.target}} ne peut pas cibler une variable précédente`
60
+ });
61
+ }
62
+ }
63
+ }
64
+ // 3. Valider la syntaxe générale
65
+ const syntaxError = this.validateSyntax(condition);
66
+ if (syntaxError) {
67
+ errors.push({
68
+ type: 'syntax_error',
69
+ variableCode: '',
70
+ message: syntaxError
71
+ });
72
+ }
73
+ return {
74
+ isValid: errors.length === 0,
75
+ errors
76
+ };
77
+ }
78
+ /**
79
+ * Évalue une condition au runtime (rendu)
80
+ * Utilise les valeurs de la ligne courante du roster
81
+ */
82
+ static evaluate(condition, lineValues) {
83
+ if (!condition?.trim()) {
84
+ return true;
85
+ }
86
+ try {
87
+ // Construire un contexte isolé pour cette ligne du roster
88
+ const responses = {};
89
+ for (const [code, value] of Object.entries(lineValues)) {
90
+ responses[code] = {
91
+ variableCode: code,
92
+ valeur: value,
93
+ dateModification: new Date()
94
+ };
95
+ }
96
+ // Utiliser le ConditionEngine en composition (pas héritage)
97
+ const engine = new ConditionEngine(responses);
98
+ return engine.evaluate(condition);
99
+ }
100
+ catch (error) {
101
+ console.warn('[RosterConditionEngine] Erreur évaluation:', condition, error);
102
+ return true; // En cas d'erreur, afficher par défaut
103
+ }
104
+ }
105
+ /**
106
+ * Extrait toutes les références de variables d'une condition
107
+ * Format: ${VAR_CODE}
108
+ */
109
+ static extractVariableReferences(condition) {
110
+ if (!condition)
111
+ return [];
112
+ const matches = condition.match(/\$\{([A-Z_][A-Z0-9_]*)\}/g) || [];
113
+ return matches.map(m => m.slice(2, -1));
114
+ }
115
+ /**
116
+ * Extrait la cible d'un jump s'il existe dans la condition (premier match uniquement)
117
+ * Format: jump(condition, ${TARGET})
118
+ * @deprecated Utiliser extractAllJumps pour supporter les jumps multiples
119
+ */
120
+ static extractJumpTarget(condition) {
121
+ if (!condition)
122
+ return null;
123
+ const match = condition.match(/jump\s*\([^,]+,\s*\$\{([A-Z_][A-Z0-9_]*)\}\s*\)/);
124
+ return match ? match[1] : null;
125
+ }
126
+ /**
127
+ * Extrait TOUS les jumps d'une condition
128
+ * Supporte: jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
129
+ * Retourne un tableau de { fullExpression, innerCondition, target }
130
+ */
131
+ static extractAllJumps(condition) {
132
+ if (!condition)
133
+ return [];
134
+ const jumps = [];
135
+ // Regex pour capturer chaque jump avec sa condition interne et sa cible
136
+ const jumpRegex = /jump\s*\(\s*([^,]+?)\s*,\s*\$\{([A-Z_][A-Z0-9_]*)\}\s*\)/g;
137
+ let match;
138
+ while ((match = jumpRegex.exec(condition)) !== null) {
139
+ jumps.push({
140
+ fullExpression: match[0],
141
+ innerCondition: match[1].trim(),
142
+ target: match[2]
143
+ });
144
+ }
145
+ return jumps;
146
+ }
147
+ /**
148
+ * Calcule les variables qui doivent être masquées à cause des jumps actifs
149
+ * Supporte les jumps multiples avec court-circuit:
150
+ * - jump(cond1, ${VAR1}) || jump(cond2, ${VAR2})
151
+ * - Si cond1 est vraie, on saute à VAR1 et cond2 n'est pas évaluée
152
+ */
153
+ static computeJumpedVariables(sortedVariables, lineValues) {
154
+ const jumped = new Set();
155
+ for (const rosterVar of sortedVariables) {
156
+ const condition = rosterVar.conditionsAffichage;
157
+ if (!condition)
158
+ continue;
159
+ // Extraire tous les jumps de cette condition
160
+ const allJumps = this.extractAllJumps(condition);
161
+ if (allJumps.length === 0)
162
+ continue;
163
+ // Évaluer les jumps dans l'ordre avec court-circuit
164
+ for (const jump of allJumps) {
165
+ // Évaluer la condition interne du jump
166
+ const innerConditionResult = this.evaluateInnerCondition(jump.innerCondition, lineValues);
167
+ if (innerConditionResult) {
168
+ // Ce jump s'active - masquer les variables entre source et cible
169
+ const targetVar = sortedVariables.find(v => v.code === jump.target);
170
+ if (targetVar) {
171
+ for (const v of sortedVariables) {
172
+ if (v.ordre > rosterVar.ordre && v.ordre < targetVar.ordre) {
173
+ jumped.add(v.code);
174
+ }
175
+ }
176
+ }
177
+ // Court-circuit: on ne vérifie pas les jumps suivants
178
+ break;
179
+ }
180
+ }
181
+ }
182
+ return jumped;
183
+ }
184
+ /**
185
+ * Évalue une condition interne (sans le wrapper jump())
186
+ */
187
+ static evaluateInnerCondition(innerCondition, lineValues) {
188
+ if (!innerCondition?.trim())
189
+ return false;
190
+ try {
191
+ // Construire un contexte isolé pour cette ligne du roster
192
+ const responses = {};
193
+ for (const [code, value] of Object.entries(lineValues)) {
194
+ responses[code] = {
195
+ variableCode: code,
196
+ valeur: value,
197
+ dateModification: new Date()
198
+ };
199
+ }
200
+ const engine = new ConditionEngine(responses);
201
+ // Si c'est déjà un showMe(), l'évaluer directement
202
+ if (innerCondition.trim().startsWith('showMe(')) {
203
+ return engine.evaluate(innerCondition);
204
+ }
205
+ // Sinon, wrapper dans showMe pour évaluation
206
+ return engine.evaluate(`showMe(${innerCondition})`);
207
+ }
208
+ catch (error) {
209
+ console.warn('[RosterConditionEngine] Erreur évaluation condition interne:', innerCondition, error);
210
+ return false;
211
+ }
212
+ }
213
+ /**
214
+ * Valide la syntaxe de base d'une condition
215
+ */
216
+ static validateSyntax(condition) {
217
+ try {
218
+ // Vérifier les parenthèses équilibrées
219
+ let depth = 0;
220
+ for (const char of condition) {
221
+ if (char === '(')
222
+ depth++;
223
+ if (char === ')')
224
+ depth--;
225
+ if (depth < 0) {
226
+ return 'Parenthèses non équilibrées';
227
+ }
228
+ }
229
+ if (depth !== 0) {
230
+ return 'Parenthèses non équilibrées';
231
+ }
232
+ // Vérifier les fonctions reconnues
233
+ const functionMatch = condition.match(/^(showMe|hideMe|jump)\s*\(/);
234
+ if (!functionMatch && !condition.includes('${')) {
235
+ return 'Condition invalide: utilisez showMe(), hideMe() ou jump()';
236
+ }
237
+ return null;
238
+ }
239
+ catch (error) {
240
+ return `Erreur de syntaxe: ${error instanceof Error ? error.message : 'Erreur inconnue'}`;
241
+ }
242
+ }
243
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rsuci/shared-form-components",
3
- "version": "1.0.16",
3
+ "version": "1.0.18",
4
4
  "description": "Composants partagés de rendu de formulaires RSU v2 - Package local pour frontend Admin et Public",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",