@inseefr/lunatic 3.7.7-rc.0 → 3.8.0-rc.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/components/Suggester/Suggester.spec.d.ts +1 -0
- package/components/Suggester/Suggester.spec.js +58 -0
- package/components/Suggester/Suggester.spec.js.map +1 -0
- package/esm/components/Suggester/Suggester.spec.d.ts +1 -0
- package/esm/components/Suggester/Suggester.spec.js +56 -0
- package/esm/components/Suggester/Suggester.spec.js.map +1 -0
- package/esm/type.source.d.ts +9 -0
- package/esm/use-lunatic/commons/compile-controls.js +2 -16
- package/esm/use-lunatic/commons/compile-controls.js.map +1 -1
- package/esm/use-lunatic/commons/component.d.ts +33 -0
- package/esm/use-lunatic/commons/component.js +37 -0
- package/esm/use-lunatic/commons/component.js.map +1 -1
- package/esm/use-lunatic/commons/variables/behaviours/cleaning-behaviour.js.map +1 -1
- package/esm/use-lunatic/commons/variables/global-variables.d.ts +5 -0
- package/esm/use-lunatic/commons/variables/global-variables.js +7 -0
- package/esm/use-lunatic/commons/variables/global-variables.js.map +1 -0
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.d.ts +21 -9
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.js +67 -49
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js +137 -6
- package/esm/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
- package/esm/use-lunatic/commons/variables/models.d.ts +1 -0
- package/esm/use-lunatic/commons/variables/models.js +2 -0
- package/esm/use-lunatic/commons/variables/models.js.map +1 -0
- package/esm/use-lunatic/commons/variables/pairwise-variables.d.ts +29 -0
- package/esm/use-lunatic/commons/variables/pairwise-variables.js +196 -0
- package/esm/use-lunatic/commons/variables/pairwise-variables.js.map +1 -0
- package/esm/use-lunatic/props/getComponentTypeProps.d.ts +1 -1
- package/esm/use-lunatic/reducer/reducerInitializer.js +5 -1
- package/esm/use-lunatic/reducer/reducerInitializer.js.map +1 -1
- package/package.json +30 -1
- package/src/components/Suggester/Suggester.spec.tsx +62 -0
- package/src/stories/pairwise/pairwise.stories.tsx +7 -0
- package/src/stories/pairwise/sourceGlobalVariables.json +337 -0
- package/src/type.source.ts +9 -0
- package/src/use-lunatic/commons/compile-controls.ts +10 -42
- package/src/use-lunatic/commons/component.ts +79 -0
- package/src/use-lunatic/commons/variables/behaviours/cleaning-behaviour.ts +2 -4
- package/src/use-lunatic/commons/variables/global-variables.ts +9 -0
- package/src/use-lunatic/commons/variables/lunatic-variables-store.spec.ts +149 -6
- package/src/use-lunatic/commons/variables/lunatic-variables-store.ts +113 -50
- package/src/use-lunatic/commons/variables/models.ts +1 -0
- package/src/use-lunatic/commons/variables/pairwise-variables.ts +251 -0
- package/src/use-lunatic/reducer/reducerInitializer.tsx +5 -7
- package/tsconfig.build.tsbuildinfo +1 -1
- package/type.source.d.ts +9 -0
- package/use-lunatic/commons/compile-controls.js +4 -18
- package/use-lunatic/commons/compile-controls.js.map +1 -1
- package/use-lunatic/commons/component.d.ts +33 -0
- package/use-lunatic/commons/component.js +42 -0
- package/use-lunatic/commons/component.js.map +1 -1
- package/use-lunatic/commons/variables/behaviours/cleaning-behaviour.js.map +1 -1
- package/use-lunatic/commons/variables/global-variables.d.ts +5 -0
- package/use-lunatic/commons/variables/global-variables.js +11 -0
- package/use-lunatic/commons/variables/global-variables.js.map +1 -0
- package/use-lunatic/commons/variables/lunatic-variables-store.d.ts +21 -9
- package/use-lunatic/commons/variables/lunatic-variables-store.js +72 -50
- package/use-lunatic/commons/variables/lunatic-variables-store.js.map +1 -1
- package/use-lunatic/commons/variables/lunatic-variables-store.spec.js +137 -6
- package/use-lunatic/commons/variables/lunatic-variables-store.spec.js.map +1 -1
- package/use-lunatic/commons/variables/models.d.ts +1 -0
- package/use-lunatic/commons/variables/models.js +3 -0
- package/use-lunatic/commons/variables/models.js.map +1 -0
- package/use-lunatic/commons/variables/pairwise-variables.d.ts +29 -0
- package/use-lunatic/commons/variables/pairwise-variables.js +199 -0
- package/use-lunatic/commons/variables/pairwise-variables.js.map +1 -0
- package/use-lunatic/props/getComponentTypeProps.d.ts +1 -1
- package/use-lunatic/reducer/reducerInitializer.js +5 -1
- package/use-lunatic/reducer/reducerInitializer.js.map +1 -1
|
@@ -4,6 +4,7 @@ import * as cleaningModule from './behaviours/cleaning-behaviour';
|
|
|
4
4
|
import { missingBehaviour } from './behaviours/missing-behaviour';
|
|
5
5
|
import { resizingBehaviour } from './behaviours/resizing-behaviour';
|
|
6
6
|
import { LunaticVariablesStore } from './lunatic-variables-store';
|
|
7
|
+
import { ComponentDefinitionWithPage } from '../../../type.source';
|
|
7
8
|
|
|
8
9
|
describe('lunatic-variables-store', () => {
|
|
9
10
|
let variables: LunaticVariablesStore;
|
|
@@ -710,7 +711,9 @@ describe('lunatic-variables-store', () => {
|
|
|
710
711
|
},
|
|
711
712
|
},
|
|
712
713
|
},
|
|
713
|
-
{
|
|
714
|
+
{
|
|
715
|
+
changeHandler: { current: () => {} },
|
|
716
|
+
}
|
|
714
717
|
);
|
|
715
718
|
expect(store.get('PRENOM')).toEqual('Jane');
|
|
716
719
|
store.set('NOM', 'Doe');
|
|
@@ -755,7 +758,9 @@ describe('lunatic-variables-store', () => {
|
|
|
755
758
|
],
|
|
756
759
|
},
|
|
757
760
|
{},
|
|
758
|
-
{
|
|
761
|
+
{
|
|
762
|
+
changeHandler: { current: () => {} },
|
|
763
|
+
}
|
|
759
764
|
);
|
|
760
765
|
|
|
761
766
|
expect(store.get('calc1')).toBeNull();
|
|
@@ -797,8 +802,10 @@ describe('lunatic-variables-store', () => {
|
|
|
797
802
|
},
|
|
798
803
|
},
|
|
799
804
|
},
|
|
800
|
-
{
|
|
801
|
-
|
|
805
|
+
{
|
|
806
|
+
changeHandler: { current: () => {} },
|
|
807
|
+
disableCleaning: false, // enable cleaning
|
|
808
|
+
}
|
|
802
809
|
);
|
|
803
810
|
expect(cleaningSpy).toHaveBeenCalled();
|
|
804
811
|
});
|
|
@@ -836,10 +843,146 @@ describe('lunatic-variables-store', () => {
|
|
|
836
843
|
},
|
|
837
844
|
},
|
|
838
845
|
},
|
|
839
|
-
{
|
|
840
|
-
|
|
846
|
+
{
|
|
847
|
+
changeHandler: { current: () => {} },
|
|
848
|
+
disableCleaning: true, // disable cleaning
|
|
849
|
+
}
|
|
841
850
|
);
|
|
842
851
|
expect(cleaningSpy).not.toHaveBeenCalled();
|
|
843
852
|
});
|
|
853
|
+
|
|
854
|
+
it('should create global pairwise variables', () => {
|
|
855
|
+
// Given a source with a pairwise component
|
|
856
|
+
const pairwiseComponent = {
|
|
857
|
+
id: 'm8ob5u9l',
|
|
858
|
+
page: '3',
|
|
859
|
+
symLinks: {
|
|
860
|
+
LINKS: {
|
|
861
|
+
'1': '1',
|
|
862
|
+
'2': '3',
|
|
863
|
+
'3': '2',
|
|
864
|
+
},
|
|
865
|
+
},
|
|
866
|
+
components: [
|
|
867
|
+
{
|
|
868
|
+
id: 'm8ob5u9l-pairwise-dropdown',
|
|
869
|
+
label: {
|
|
870
|
+
type: 'VTL|MD',
|
|
871
|
+
value: '"Qui est " || yAxis || " pour " || xAxis || " ?"',
|
|
872
|
+
},
|
|
873
|
+
options: [
|
|
874
|
+
{
|
|
875
|
+
label: {
|
|
876
|
+
type: 'VTL',
|
|
877
|
+
value: '"Son conjoint, sa conjointe"',
|
|
878
|
+
},
|
|
879
|
+
value: '1',
|
|
880
|
+
},
|
|
881
|
+
{
|
|
882
|
+
label: { type: 'VTL', value: '"Sa mère, son père"' },
|
|
883
|
+
value: '2',
|
|
884
|
+
},
|
|
885
|
+
{
|
|
886
|
+
label: { type: 'VTL', value: '"Sa fille, son fils"' },
|
|
887
|
+
value: '3',
|
|
888
|
+
},
|
|
889
|
+
],
|
|
890
|
+
response: { name: 'LINKS' },
|
|
891
|
+
isMandatory: false,
|
|
892
|
+
componentType: 'Dropdown',
|
|
893
|
+
conditionFilter: {
|
|
894
|
+
type: 'VTL',
|
|
895
|
+
value: '(nvl(xAxis, "") <> "") and (nvl(yAxis, "") <> "")',
|
|
896
|
+
},
|
|
897
|
+
},
|
|
898
|
+
],
|
|
899
|
+
sourceVariables: {
|
|
900
|
+
name: 'PRENOM',
|
|
901
|
+
gender: 'SEXE',
|
|
902
|
+
},
|
|
903
|
+
componentType: 'PairwiseLinks',
|
|
904
|
+
xAxisIterations: { type: 'VTL', value: 'count(PRENOM)' },
|
|
905
|
+
yAxisIterations: { type: 'VTL', value: 'count(PRENOM)' },
|
|
906
|
+
} as ComponentDefinitionWithPage;
|
|
907
|
+
|
|
908
|
+
// When we create the store
|
|
909
|
+
const store = LunaticVariablesStore.makeFromSource(
|
|
910
|
+
{
|
|
911
|
+
components: [pairwiseComponent],
|
|
912
|
+
variables: [
|
|
913
|
+
{
|
|
914
|
+
name: 'PRENOM',
|
|
915
|
+
values: { COLLECTED: [] },
|
|
916
|
+
dimension: 1,
|
|
917
|
+
variableType: 'COLLECTED',
|
|
918
|
+
iterationReference: 'm8ob7c76',
|
|
919
|
+
},
|
|
920
|
+
{
|
|
921
|
+
name: 'SEXE',
|
|
922
|
+
values: { COLLECTED: [] },
|
|
923
|
+
dimension: 1,
|
|
924
|
+
variableType: 'COLLECTED',
|
|
925
|
+
iterationReference: 'm8ob7c76',
|
|
926
|
+
},
|
|
927
|
+
{
|
|
928
|
+
name: 'LINKS',
|
|
929
|
+
values: { COLLECTED: [[]] },
|
|
930
|
+
dimension: 2,
|
|
931
|
+
variableType: 'COLLECTED',
|
|
932
|
+
iterationReference: 'm8ob7c76',
|
|
933
|
+
},
|
|
934
|
+
],
|
|
935
|
+
},
|
|
936
|
+
{},
|
|
937
|
+
{ changeHandler: { current: () => {} } }
|
|
938
|
+
);
|
|
939
|
+
|
|
940
|
+
// Then pairwise global variables are initialized
|
|
941
|
+
expect(store.get('GLOBAL_PARENT1_PRENOM', [0])).toBeUndefined();
|
|
942
|
+
expect(store.get('GLOBAL_PARENT2_PRENOM', [0])).toBeUndefined();
|
|
943
|
+
expect(store.get('GLOBAL_PARENT1_SEXE', [0])).toBeUndefined();
|
|
944
|
+
expect(store.get('GLOBAL_PARENT2_SEXE', [0])).toBeUndefined();
|
|
945
|
+
expect(store.get('GLOBAL_CONJOINT_PRENOM', [0])).toBeUndefined();
|
|
946
|
+
expect(store.get('GLOBAL_ENFANTS_PRENOMS', [0])).toBeUndefined();
|
|
947
|
+
|
|
948
|
+
// When pairwise link is updated
|
|
949
|
+
store.set('PRENOM', [
|
|
950
|
+
'Verso',
|
|
951
|
+
'Renoir',
|
|
952
|
+
'Aline',
|
|
953
|
+
'Monoco',
|
|
954
|
+
'Noco',
|
|
955
|
+
'Alicia',
|
|
956
|
+
'Sciel',
|
|
957
|
+
]);
|
|
958
|
+
store.set('SEXE', ['1', '1', '2', '1', '1', '2', '2']);
|
|
959
|
+
store.set('LINKS', [
|
|
960
|
+
[null, '2', '2', '3', '3', null, '1'],
|
|
961
|
+
['3', null, '1', null, null, '3', null],
|
|
962
|
+
['3', '1', null, null, null, '3', null],
|
|
963
|
+
['2', null, null, null, null, null, null],
|
|
964
|
+
['2', null, null, null, null, null, null],
|
|
965
|
+
[null, '2', '2', null, null, null, null],
|
|
966
|
+
['1', null, null, null, null, null, null],
|
|
967
|
+
]);
|
|
968
|
+
store.commit();
|
|
969
|
+
|
|
970
|
+
// Then the variables are set at the proper value
|
|
971
|
+
expect(store.get('GLOBAL_PARENT1_PRENOM', [0])).toBe('Renoir');
|
|
972
|
+
expect(store.get('GLOBAL_PARENT2_PRENOM', [0])).toBe('Aline');
|
|
973
|
+
expect(store.get('GLOBAL_PARENT1_SEXE', [0])).toBe('1');
|
|
974
|
+
expect(store.get('GLOBAL_PARENT2_SEXE', [0])).toBe('2');
|
|
975
|
+
expect(store.get('GLOBAL_CONJOINT_PRENOM', [0])).toBe('Sciel');
|
|
976
|
+
expect(store.get('GLOBAL_ENFANTS_PRENOMS', [0])).toBe('Monoco;Noco');
|
|
977
|
+
|
|
978
|
+
expect(store.get('GLOBAL_PARENT1_PRENOM', [1])).toBeUndefined();
|
|
979
|
+
expect(store.get('GLOBAL_PARENT2_PRENOM', [1])).toBeUndefined();
|
|
980
|
+
expect(store.get('GLOBAL_PARENT1_SEXE', [1])).toBeUndefined();
|
|
981
|
+
expect(store.get('GLOBAL_PARENT2_SEXE', [1])).toBeUndefined();
|
|
982
|
+
expect(store.get('GLOBAL_CONJOINT_PRENOM', [1])).toBe('Aline');
|
|
983
|
+
expect(store.get('GLOBAL_ENFANTS_PRENOMS', [1])).toBe('Verso;Alicia');
|
|
984
|
+
|
|
985
|
+
expect(store.get('GLOBAL_ENFANTS_PRENOMS', [4])).toBe(undefined);
|
|
986
|
+
});
|
|
844
987
|
});
|
|
845
988
|
});
|
|
@@ -18,13 +18,20 @@ import {
|
|
|
18
18
|
VTLMissingDependencies,
|
|
19
19
|
VTLMissingDependency,
|
|
20
20
|
} from './errors';
|
|
21
|
+
import {
|
|
22
|
+
computePairwiseGlobalVariables,
|
|
23
|
+
computePairwiseGlobalVariableValue,
|
|
24
|
+
PairwiseGlobalDependency,
|
|
25
|
+
} from './pairwise-variables';
|
|
26
|
+
import {
|
|
27
|
+
computeGlobalIterationIndexValue,
|
|
28
|
+
GLOBAL_ITERATION_INDEX,
|
|
29
|
+
} from './global-variables';
|
|
30
|
+
import { IterationLevel } from './models';
|
|
21
31
|
|
|
22
32
|
/** Interpret counter. Used for testing purpose. */
|
|
23
33
|
let interpretCount = 0;
|
|
24
|
-
/** Special variable that will take the current iteration value. */
|
|
25
|
-
const iterationVariableName = 'GLOBAL_ITERATION_INDEX';
|
|
26
34
|
|
|
27
|
-
export type IterationLevel = number[];
|
|
28
35
|
export type EventArgs = {
|
|
29
36
|
change: {
|
|
30
37
|
/** Name of the changed variable. */
|
|
@@ -73,12 +80,16 @@ export class LunaticVariablesStore {
|
|
|
73
80
|
public static makeFromSource(
|
|
74
81
|
source: LunaticSource,
|
|
75
82
|
data: LunaticData,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
83
|
+
options: {
|
|
84
|
+
changeHandler?: RefObject<LunaticOptions['onVariableChange']>;
|
|
85
|
+
// Disable cleaning
|
|
86
|
+
disableCleaning?: boolean;
|
|
87
|
+
// Do not delay resizing / cleaning
|
|
88
|
+
autoCommit?: boolean;
|
|
89
|
+
} = {}
|
|
81
90
|
) {
|
|
91
|
+
const { changeHandler, disableCleaning, autoCommit } = options;
|
|
92
|
+
|
|
82
93
|
const store = new LunaticVariablesStore();
|
|
83
94
|
if (typeof window !== 'undefined') {
|
|
84
95
|
(window as any).lunaticStore = store; // Allow access to the store from the console
|
|
@@ -89,6 +100,15 @@ export class LunaticVariablesStore {
|
|
|
89
100
|
if (autoCommit) {
|
|
90
101
|
store.autoCommit = autoCommit;
|
|
91
102
|
}
|
|
103
|
+
|
|
104
|
+
// Setup pairwise global variables if there is a pairwise component
|
|
105
|
+
const pairwiseVariables = computePairwiseGlobalVariables(source);
|
|
106
|
+
for (const pairwiseVariable of pairwiseVariables) {
|
|
107
|
+
const { name, dependencies, globalDependencies, shapeFrom } =
|
|
108
|
+
pairwiseVariable;
|
|
109
|
+
store.setGlobal(name, { dependencies, globalDependencies, shapeFrom });
|
|
110
|
+
}
|
|
111
|
+
|
|
92
112
|
// Source data (picked from "variables" in the source.json)s
|
|
93
113
|
const sourceValues: Record<string, unknown> = {};
|
|
94
114
|
// Starting data for the form (merged with data.json or injected data)
|
|
@@ -106,6 +126,9 @@ export class LunaticVariablesStore {
|
|
|
106
126
|
for (const variable of source.variables) {
|
|
107
127
|
switch (variable.variableType) {
|
|
108
128
|
case 'CALCULATED':
|
|
129
|
+
// In some cases, we have calculated variables in the source that are
|
|
130
|
+
// not used in the questionnaire (those variables are executed out of
|
|
131
|
+
// Lunatic.), so there is no need to add them to the dictionary.
|
|
109
132
|
if (variable.isIgnoredByLunatic) break;
|
|
110
133
|
store.setCalculated(variable.name, variable.expression.value, {
|
|
111
134
|
dependencies: variable.bindingDependencies,
|
|
@@ -257,6 +280,38 @@ export class LunaticVariablesStore {
|
|
|
257
280
|
return variable;
|
|
258
281
|
}
|
|
259
282
|
|
|
283
|
+
/**
|
|
284
|
+
* Register global variable
|
|
285
|
+
*/
|
|
286
|
+
public setGlobal(
|
|
287
|
+
name: string,
|
|
288
|
+
{
|
|
289
|
+
dependencies,
|
|
290
|
+
globalDependencies,
|
|
291
|
+
shapeFrom,
|
|
292
|
+
}: {
|
|
293
|
+
dependencies?: string[];
|
|
294
|
+
globalDependencies?: Map<unknown, string>;
|
|
295
|
+
shapeFrom?: string | string[];
|
|
296
|
+
}
|
|
297
|
+
): LunaticVariable {
|
|
298
|
+
if (this.dictionary.has(name)) {
|
|
299
|
+
return this.dictionary.get(name)!;
|
|
300
|
+
}
|
|
301
|
+
const variable = new LunaticVariable({
|
|
302
|
+
dictionary: this.dictionary,
|
|
303
|
+
shapeFrom,
|
|
304
|
+
dependencies,
|
|
305
|
+
name,
|
|
306
|
+
storeUpdatedAt: this.updatedAt,
|
|
307
|
+
isGlobal: true,
|
|
308
|
+
globalDependencies,
|
|
309
|
+
});
|
|
310
|
+
this.dictionary.set(name, variable);
|
|
311
|
+
this.updatedAt.touch();
|
|
312
|
+
return variable;
|
|
313
|
+
}
|
|
314
|
+
|
|
260
315
|
/**
|
|
261
316
|
* Run a VTL expression
|
|
262
317
|
*/
|
|
@@ -317,7 +372,7 @@ export class LunaticVariablesStore {
|
|
|
317
372
|
}
|
|
318
373
|
}
|
|
319
374
|
|
|
320
|
-
class LunaticVariable {
|
|
375
|
+
export class LunaticVariable {
|
|
321
376
|
/** Last time the value was updated (changed). */
|
|
322
377
|
public updatedAt = new Map<undefined | string, number>();
|
|
323
378
|
/** Last time the store was updated (changed). */
|
|
@@ -328,8 +383,6 @@ class LunaticVariable {
|
|
|
328
383
|
private value: unknown;
|
|
329
384
|
/** List of direct dependencies, ex: ['FULLNAME', 'FIRSTNAME', 'LASTNAME']. */
|
|
330
385
|
private dependencies?: string[];
|
|
331
|
-
/** List of deep dependencies, exploring the variables used in calculated variables, ex: ['FIRSTNAME', 'LASTNAME']. */
|
|
332
|
-
private baseDependencies?: string[];
|
|
333
386
|
/** Expression for calculated variable. */
|
|
334
387
|
public readonly expression?: string;
|
|
335
388
|
/** Dictionary holding all the available variables. */
|
|
@@ -338,6 +391,10 @@ class LunaticVariable {
|
|
|
338
391
|
private readonly iterationDepth?: number;
|
|
339
392
|
/** For calculated variable, shape is copied from another variable. */
|
|
340
393
|
private readonly shapeFrom?: string[];
|
|
394
|
+
/** Whether this is a global variable with custom computation rules. */
|
|
395
|
+
private readonly isGlobal?: boolean;
|
|
396
|
+
/** Name of variables needed for global variables computation rules. */
|
|
397
|
+
private readonly globalDependencies?: Map<unknown, string>;
|
|
341
398
|
/** Keep a record of variable name (optional, used for debug). */
|
|
342
399
|
public readonly name?: string;
|
|
343
400
|
/** Count the number of calculation. */
|
|
@@ -354,12 +411,22 @@ class LunaticVariable {
|
|
|
354
411
|
name?: string;
|
|
355
412
|
dimension?: number;
|
|
356
413
|
storeUpdatedAt: Timekey;
|
|
414
|
+
isGlobal?: boolean;
|
|
415
|
+
globalDependencies?: Map<unknown, string>;
|
|
357
416
|
}) {
|
|
358
417
|
if (args.expression && !args.dictionary) {
|
|
359
418
|
throw new Error(
|
|
360
|
-
|
|
419
|
+
'A calculated variable needs a dictionary to retrieve his deps'
|
|
361
420
|
);
|
|
362
421
|
}
|
|
422
|
+
if (args.isGlobal && args.dependencies && !args.dictionary) {
|
|
423
|
+
throw new Error(
|
|
424
|
+
'A global variable with dependencies needs a dictionary to retrieve its deps'
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
if (args.isGlobal && !args.name) {
|
|
428
|
+
throw new Error('A global variable needs a name to fetch its logic');
|
|
429
|
+
}
|
|
363
430
|
this.expression = args.expression;
|
|
364
431
|
this.dictionary = args.dictionary;
|
|
365
432
|
this.dependencies = args.dependencies;
|
|
@@ -369,11 +436,13 @@ class LunaticVariable {
|
|
|
369
436
|
this.name = args.name ?? args.expression;
|
|
370
437
|
this.dimension = args.dimension;
|
|
371
438
|
this.storeUpdatedAt = args.storeUpdatedAt;
|
|
439
|
+
this.isGlobal = args.isGlobal || false;
|
|
440
|
+
this.globalDependencies = args.globalDependencies || undefined;
|
|
372
441
|
}
|
|
373
442
|
|
|
374
443
|
getValue(iteration?: IterationLevel): unknown {
|
|
375
|
-
// The variable is not calculated
|
|
376
|
-
if (!this.expression) {
|
|
444
|
+
// The variable is not calculated or a global variable
|
|
445
|
+
if (!this.expression && !this.isGlobal) {
|
|
377
446
|
return this.getSavedValue(iteration);
|
|
378
447
|
}
|
|
379
448
|
|
|
@@ -424,6 +493,7 @@ class LunaticVariable {
|
|
|
424
493
|
if (isTestEnv()) {
|
|
425
494
|
interpretCount++;
|
|
426
495
|
}
|
|
496
|
+
|
|
427
497
|
// Scale down iteration if its dimension > shapeFrom dimension
|
|
428
498
|
const shapeDimension = arrayDimension(shapeFromValue);
|
|
429
499
|
if (
|
|
@@ -433,15 +503,30 @@ class LunaticVariable {
|
|
|
433
503
|
) {
|
|
434
504
|
iteration = iteration.slice(0, shapeDimension);
|
|
435
505
|
}
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
iteration
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
506
|
+
|
|
507
|
+
if (this.isGlobal) {
|
|
508
|
+
// compute global variable thanks to specific rule
|
|
509
|
+
const value = computePairwiseGlobalVariableValue(
|
|
510
|
+
this.name!,
|
|
511
|
+
iteration!,
|
|
512
|
+
this.globalDependencies! as Map<PairwiseGlobalDependency, string>,
|
|
513
|
+
this.dictionary!
|
|
514
|
+
);
|
|
515
|
+
this.setValue(value, { iteration });
|
|
516
|
+
} else {
|
|
517
|
+
// compute thanks to VTL expression
|
|
518
|
+
|
|
519
|
+
// Uncomment this if you want to track the number of calculation
|
|
520
|
+
// this.calculatedCount++;
|
|
521
|
+
|
|
522
|
+
// Remember the value
|
|
523
|
+
try {
|
|
524
|
+
this.setValue(interpretVTL(this.expression!, bindings), {
|
|
525
|
+
iteration: iteration,
|
|
526
|
+
});
|
|
527
|
+
} catch {
|
|
528
|
+
throw new VTLInterpretationError(this.expression!, bindings);
|
|
529
|
+
}
|
|
445
530
|
}
|
|
446
531
|
this.updateTimestamps(iteration, 'calculatedAt');
|
|
447
532
|
return this.getSavedValue(iteration);
|
|
@@ -525,31 +610,6 @@ class LunaticVariable {
|
|
|
525
610
|
return current;
|
|
526
611
|
}
|
|
527
612
|
|
|
528
|
-
/**
|
|
529
|
-
* Get a list of transitive dependencies (leaf of the dependency tree)
|
|
530
|
-
*/
|
|
531
|
-
private getBaseDependencies(): string[] {
|
|
532
|
-
// Find the dependencies of the dependencies
|
|
533
|
-
const reducer = (acc: Set<string>, variableName: string) => {
|
|
534
|
-
if (acc.has(variableName)) {
|
|
535
|
-
return acc;
|
|
536
|
-
}
|
|
537
|
-
const deps = this.dictionary?.get(variableName)?.getDependencies();
|
|
538
|
-
if (!deps || deps.length === 0) {
|
|
539
|
-
acc.add(variableName);
|
|
540
|
-
} else {
|
|
541
|
-
deps?.reduce(reducer, acc);
|
|
542
|
-
}
|
|
543
|
-
return acc;
|
|
544
|
-
};
|
|
545
|
-
if (this.baseDependencies === undefined) {
|
|
546
|
-
this.baseDependencies = [
|
|
547
|
-
...this.getDependencies().reduce(reducer, new Set<string>()),
|
|
548
|
-
];
|
|
549
|
-
}
|
|
550
|
-
return this.baseDependencies;
|
|
551
|
-
}
|
|
552
|
-
|
|
553
613
|
private getDependencies(): string[] {
|
|
554
614
|
// Calculate dependencies from expression on the fly if necessary
|
|
555
615
|
if (this.dependencies === undefined) {
|
|
@@ -564,9 +624,12 @@ class LunaticVariable {
|
|
|
564
624
|
try {
|
|
565
625
|
return Object.fromEntries(
|
|
566
626
|
this.getDependencies().map((dep) => {
|
|
567
|
-
|
|
568
|
-
|
|
627
|
+
// The variable is a global variable with no dependency that we can
|
|
628
|
+
// manually compute on the fly.
|
|
629
|
+
if (dep === GLOBAL_ITERATION_INDEX && iteration) {
|
|
630
|
+
return computeGlobalIterationIndexValue(iteration);
|
|
569
631
|
}
|
|
632
|
+
|
|
570
633
|
const dependencyIteration =
|
|
571
634
|
isNumber(this.iterationDepth) && Array.isArray(iteration)
|
|
572
635
|
? [iteration[this.iterationDepth]]
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export type IterationLevel = number[];
|