@inseefr/lunatic 3.5.7 → 3.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/components/shared/Combobox/Combobox.stories.d.ts +3 -2
- package/components/shared/Combobox/Combobox.stories.js +26 -21
- package/components/shared/Combobox/Combobox.stories.js.map +1 -1
- package/esm/components/shared/Combobox/Combobox.stories.d.ts +3 -2
- package/esm/components/shared/Combobox/Combobox.stories.js +28 -24
- package/esm/components/shared/Combobox/Combobox.stories.js.map +1 -1
- package/esm/hooks/useLocalStorage.d.ts +1 -0
- package/esm/hooks/useLocalStorage.js +31 -0
- package/esm/hooks/useLocalStorage.js.map +1 -0
- package/esm/type.source.d.ts +8 -1
- package/esm/use-lunatic/commons/compile-controls.js +22 -14
- package/esm/use-lunatic/commons/compile-controls.js.map +1 -1
- package/esm/use-lunatic/commons/fill-components/fill-component-expressions.d.ts +1 -1
- package/esm/use-lunatic/commons/fill-components/fill-component-expressions.js +5 -2
- package/esm/use-lunatic/commons/fill-components/fill-component-expressions.js.map +1 -1
- package/esm/use-lunatic/commons/fill-components/fill-component.spec.js +42 -0
- package/esm/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
- package/esm/use-lunatic/commons/fill-components/fill-components.d.ts +2 -2
- package/esm/use-lunatic/commons/fill-components/fill-components.js +15 -3
- package/esm/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
- package/esm/use-lunatic/hooks/use-page-has-response.js +1 -1
- package/esm/use-lunatic/hooks/use-page-has-response.js.map +1 -1
- package/esm/use-lunatic/hooks/useOverview.spec.js +2 -2
- package/esm/use-lunatic/hooks/useOverview.spec.js.map +1 -1
- package/esm/use-lunatic/props/getComponentTypeProps.js +1 -1
- package/esm/use-lunatic/props/getComponentTypeProps.js.map +1 -1
- package/esm/utils/number.d.ts +4 -0
- package/esm/utils/number.js +12 -0
- package/esm/utils/number.js.map +1 -1
- package/esm/utils/object.d.ts +10 -0
- package/esm/utils/object.js +26 -0
- package/esm/utils/object.js.map +1 -1
- package/hooks/useLocalStorage.d.ts +1 -0
- package/hooks/useLocalStorage.js +34 -0
- package/hooks/useLocalStorage.js.map +1 -0
- package/package.json +76 -137
- package/src/components/shared/Combobox/Combobox.stories.tsx +48 -49
- package/src/hooks/useLocalStorage.ts +37 -0
- package/src/json.d.ts +16 -0
- package/src/stories/accordion/accordion.stories.tsx +21 -0
- package/src/stories/behaviour/cleaning/cleaning.stories.tsx +40 -0
- package/src/stories/behaviour/controls/controls.stories.tsx +51 -0
- package/src/stories/behaviour/disabled/disabled.stories.tsx +29 -0
- package/src/stories/behaviour/filter/filter.stories.tsx +34 -0
- package/src/stories/behaviour/missing/missing.stories.tsx +31 -0
- package/src/stories/behaviour/overview/overview.stories.tsx +61 -0
- package/src/stories/{overview/sourceWithHierarchy.json → behaviour/overview/source.json} +1 -1
- package/src/stories/{overview → behaviour/overview}/sourceLoop.json +1 -1
- package/src/stories/behaviour/performance/performance.stories.tsx +29 -0
- package/src/stories/behaviour/resizing/resizing.stories.tsx +34 -0
- package/src/stories/behaviour/slots.stories.tsx +34 -0
- package/src/stories/checkbox/checkbox.stories.tsx +75 -0
- package/src/stories/{checkbox-group/sourceLoop.json → checkbox/sourceGroupLoop.json} +1 -1
- package/src/stories/datepicker/datepicker.stories.tsx +21 -0
- package/src/stories/declaration/declaration.stories.tsx +27 -0
- package/src/stories/dropdown/dropdown.stories.tsx +27 -0
- package/src/stories/duration/duration.stories.tsx +27 -0
- package/src/stories/filter-description/filter-description.stories.tsx +28 -0
- package/src/stories/input/input.stories.tsx +21 -0
- package/src/stories/input-number/input-number.stories.tsx +35 -0
- package/src/stories/loop/loop.stories.tsx +35 -0
- package/src/stories/loop/roster-for-loop.stories.tsx +59 -0
- package/src/stories/pairwise/pairwise.stories.tsx +30 -0
- package/src/stories/paste.stories.tsx +85 -0
- package/src/stories/question/question.stories.tsx +21 -0
- package/src/stories/questionnaires/logement/logement.stories.tsx +26 -0
- package/src/stories/questionnaires/recensement/recensement.stories.tsx +28 -0
- package/src/stories/questionnaires/rp/rp.stories.tsx +21 -0
- package/src/stories/questionnaires/simpsons/simpsons.stories.tsx +31 -0
- package/src/stories/radio/radio.stories.tsx +53 -0
- package/src/stories/roundabout/roundabout.stories.tsx +37 -0
- package/src/stories/roundabout/source.json +1 -0
- package/src/stories/sequence/sequence.stories.tsx +28 -0
- package/src/stories/suggester/source-option-responses.json +1 -1
- package/src/stories/suggester/suggester.stories.tsx +68 -0
- package/src/stories/summary/source.json +22 -1
- package/src/stories/summary/summary.stories.tsx +31 -0
- package/src/stories/table/table.stories.tsx +35 -0
- package/src/stories/text/text.stories.tsx +38 -0
- package/src/stories/textarea/textarea.stories.tsx +21 -0
- package/src/stories/utils/Orchestrator.tsx +310 -0
- package/src/stories/utils/OrchestratorData.tsx +176 -0
- package/src/stories/utils/OrchestratorOverview.tsx +70 -0
- package/src/stories/utils/OrchestratorSidebar.tsx +119 -0
- package/src/stories/utils/SchemaValidator.tsx +29 -0
- package/src/stories/utils/referentiel.ts +9 -0
- package/src/type.source.ts +8 -1
- package/src/use-lunatic/commons/compile-controls.ts +36 -18
- package/src/use-lunatic/commons/fill-components/fill-component-expressions.ts +6 -2
- package/src/use-lunatic/commons/fill-components/fill-component.spec.ts +52 -0
- package/src/use-lunatic/commons/fill-components/fill-components.ts +19 -3
- package/src/use-lunatic/hooks/use-page-has-response.ts +1 -1
- package/src/use-lunatic/hooks/useOverview.spec.ts +3 -2
- package/src/use-lunatic/props/getComponentTypeProps.ts +2 -1
- package/src/use-lunatic/use-lunatic.test.ts +53 -40
- package/src/utils/number.ts +13 -0
- package/src/utils/object.ts +40 -0
- package/tsconfig.build.tsbuildinfo +1 -1
- package/type.source.d.ts +8 -1
- package/use-lunatic/commons/compile-controls.js +21 -13
- package/use-lunatic/commons/compile-controls.js.map +1 -1
- package/use-lunatic/commons/fill-components/fill-component-expressions.d.ts +1 -1
- package/use-lunatic/commons/fill-components/fill-component-expressions.js +6 -3
- package/use-lunatic/commons/fill-components/fill-component-expressions.js.map +1 -1
- package/use-lunatic/commons/fill-components/fill-component.spec.js +42 -0
- package/use-lunatic/commons/fill-components/fill-component.spec.js.map +1 -1
- package/use-lunatic/commons/fill-components/fill-components.d.ts +2 -2
- package/use-lunatic/commons/fill-components/fill-components.js +15 -3
- package/use-lunatic/commons/fill-components/fill-components.js.map +1 -1
- package/use-lunatic/hooks/use-page-has-response.js +2 -2
- package/use-lunatic/hooks/use-page-has-response.js.map +1 -1
- package/use-lunatic/hooks/useOverview.spec.js +8 -8
- package/use-lunatic/hooks/useOverview.spec.js.map +1 -1
- package/use-lunatic/props/getComponentTypeProps.js +1 -1
- package/use-lunatic/props/getComponentTypeProps.js.map +1 -1
- package/utils/number.d.ts +4 -0
- package/utils/number.js +13 -0
- package/utils/number.js.map +1 -1
- package/utils/object.d.ts +10 -0
- package/utils/object.js +30 -0
- package/utils/object.js.map +1 -1
- package/esm/stories/overview/sourceWithHierarchy.json +0 -5151
- package/esm/tests/utils/lunatic.d.ts +0 -15
- package/esm/tests/utils/lunatic.js +0 -27
- package/esm/tests/utils/lunatic.js.map +0 -1
- package/esm/use-lunatic/replace-component-sequence.d.ts +0 -36
- package/esm/use-lunatic/replace-component-sequence.js +0 -19
- package/esm/use-lunatic/replace-component-sequence.js.map +0 -1
- package/esm/use-lunatic/test.utils.d.ts +0 -2
- package/esm/use-lunatic/test.utils.js +0 -13
- package/esm/use-lunatic/test.utils.js.map +0 -1
- package/esm/utils/is-object.d.ts +0 -4
- package/esm/utils/is-object.js +0 -7
- package/esm/utils/is-object.js.map +0 -1
- package/esm/utils/to-number.d.ts +0 -4
- package/esm/utils/to-number.js +0 -13
- package/esm/utils/to-number.js.map +0 -1
- package/src/stories/accordion/accordion.stories.jsx +0 -17
- package/src/stories/behaviour/cleaning/cleaning.stories.jsx +0 -69
- package/src/stories/behaviour/controls/controls.stories.jsx +0 -81
- package/src/stories/behaviour/filter/dataLoop.json +0 -14
- package/src/stories/behaviour/filter/filter.stories.jsx +0 -36
- package/src/stories/behaviour/missing/missing.stories.jsx +0 -69
- package/src/stories/behaviour/others/V2_DeclarationsSimples.json +0 -908
- package/src/stories/behaviour/others/V2_MinMaxSum_Boucles.json +0 -489
- package/src/stories/behaviour/others/V2_QuestSimple_Boucles.json +0 -3919
- package/src/stories/behaviour/others/V2_TCMRallyeGames.json +0 -2760
- package/src/stories/behaviour/others/test-dylan.json +0 -538
- package/src/stories/behaviour/others/test.stories.jsx +0 -78
- package/src/stories/behaviour/paste/source.json +0 -32
- package/src/stories/behaviour/paste/test.stories.jsx +0 -62
- package/src/stories/behaviour/performance/performance.stories.jsx +0 -26
- package/src/stories/behaviour/resizing/resizing.stories.jsx +0 -60
- package/src/stories/behaviour/slots.stories.jsx +0 -32
- package/src/stories/checkbox-boolean/checkboxBoolean.stories.jsx +0 -17
- package/src/stories/checkbox-group/checkbox-group.stories.jsx +0 -77
- package/src/stories/checkbox-one/checkboxOne.stories.jsx +0 -53
- package/src/stories/date-picker/data.json +0 -3
- package/src/stories/date-picker/datepicker.stories.jsx +0 -26
- package/src/stories/declaration/data.json +0 -1
- package/src/stories/declaration/input.stories.jsx +0 -18
- package/src/stories/disabled/data.json +0 -16
- package/src/stories/disabled/disabled.stories.jsx +0 -18
- package/src/stories/dropdown/data.json +0 -8
- package/src/stories/dropdown/dropdown.stories.jsx +0 -25
- package/src/stories/duration/duration.stories.jsx +0 -25
- package/src/stories/filter-description/filter-description.stories.jsx +0 -37
- package/src/stories/input/data.json +0 -1
- package/src/stories/input/input.stories.jsx +0 -18
- package/src/stories/input-number/input-number.stories.jsx +0 -23
- package/src/stories/loop/loop.stories.jsx +0 -29
- package/src/stories/loop/roster-for-loop.stories.jsx +0 -46
- package/src/stories/markdown/markdown.stories.jsx +0 -20
- package/src/stories/overview/data.json +0 -1
- package/src/stories/overview/dataLoop.json +0 -93
- package/src/stories/overview/overview.stories.jsx +0 -44
- package/src/stories/overview/source.json +0 -25
- package/src/stories/pairwise/data.json +0 -12
- package/src/stories/pairwise/pairwise-links.stories.jsx +0 -48
- package/src/stories/question/question.stories.jsx +0 -16
- package/src/stories/questionnaires/logement/logement.stories.jsx +0 -59
- package/src/stories/questionnaires/recensement/data.json +0 -12
- package/src/stories/questionnaires/recensement/recensement.stories.jsx +0 -35
- package/src/stories/questionnaires/rp/data.json +0 -5
- package/src/stories/questionnaires/rp/rp.stories.jsx +0 -23
- package/src/stories/questionnaires/simpsons/simpsons.stories.jsx +0 -246
- package/src/stories/radio/radio.stories.jsx +0 -78
- package/src/stories/roundabout/data1.json +0 -13
- package/src/stories/roundabout/data2.json +0 -16
- package/src/stories/roundabout/roundabout.stories.jsx +0 -32
- package/src/stories/sequence/sequence.stories.jsx +0 -29
- package/src/stories/suggester/suggester.stories.jsx +0 -71
- package/src/stories/summary/data.json +0 -16
- package/src/stories/summary/summary.stories.jsx +0 -23
- package/src/stories/switch/README.md +0 -29
- package/src/stories/switch/data-forced.json +0 -40
- package/src/stories/switch/source.json +0 -64
- package/src/stories/switch/switch.stories.jsx +0 -17
- package/src/stories/table/data.json +0 -1
- package/src/stories/table/table.stories.jsx +0 -30
- package/src/stories/text/data-roster.json +0 -5
- package/src/stories/text/text.stories.jsx +0 -20
- package/src/stories/textarea/data.json +0 -1
- package/src/stories/textarea/textarea.stories.jsx +0 -18
- package/src/stories/utils/SchemaValidator.jsx +0 -40
- package/src/stories/utils/default-arg-types.js +0 -39
- package/src/stories/utils/default-args.js +0 -3
- package/src/stories/utils/options.js +0 -19
- package/src/stories/utils/orchestrator.jsx +0 -267
- package/src/stories/utils/orchestrator.scss +0 -66
- package/src/stories/utils/overview.jsx +0 -39
- package/src/stories/utils/overview.scss +0 -37
- package/src/stories/utils/referentiel.js +0 -7
- package/src/tests/utils/e2e.js +0 -91
- package/src/tests/utils/lunatic.ts +0 -33
- package/src/use-lunatic/replace-component-sequence.ts +0 -25
- package/src/use-lunatic/test.utils.ts +0 -17
- package/src/utils/is-object.ts +0 -6
- package/src/utils/to-number.ts +0 -12
- package/stories/overview/sourceWithHierarchy.json +0 -5151
- package/tests/utils/lunatic.d.ts +0 -15
- package/tests/utils/lunatic.js +0 -31
- package/tests/utils/lunatic.js.map +0 -1
- package/use-lunatic/replace-component-sequence.d.ts +0 -36
- package/use-lunatic/replace-component-sequence.js +0 -22
- package/use-lunatic/replace-component-sequence.js.map +0 -1
- package/use-lunatic/test.utils.d.ts +0 -2
- package/use-lunatic/test.utils.js +0 -17
- package/use-lunatic/test.utils.js.map +0 -1
- package/utils/is-object.d.ts +0 -4
- package/utils/is-object.js +0 -10
- package/utils/is-object.js.map +0 -1
- package/utils/to-number.d.ts +0 -4
- package/utils/to-number.js +0 -16
- package/utils/to-number.js.map +0 -1
- /package/src/stories/behaviour/cleaning/{loop.json → source-loop-scopes.json} +0 -0
- /package/src/stories/behaviour/controls/{boucles-n.json → source-boucles-n.json} +0 -0
- /package/src/stories/behaviour/controls/{loop.json → source-loop.json} +0 -0
- /package/src/stories/behaviour/controls/{roundabout.json → source-roundabout.json} +0 -0
- /package/src/stories/behaviour/controls/{simple-numeric.json → source-simple-numeric.json} +0 -0
- /package/src/stories/behaviour/controls/{simple.json → source-simple.json} +0 -0
- /package/src/stories/{disabled → behaviour/disabled}/source.json +0 -0
- /package/src/stories/{checkbox-boolean → checkbox}/source.json +0 -0
- /package/src/stories/{checkbox-group/source.json → checkbox/sourceGroup.json} +0 -0
- /package/src/stories/{checkbox-group/sourceCondition.json → checkbox/sourceGroupCondition.json} +0 -0
- /package/src/stories/{checkbox-group/sourceDetail.json → checkbox/sourceGroupDetail.json} +0 -0
- /package/src/stories/{checkbox-one/source.json → checkbox/sourceOne.json} +0 -0
- /package/src/stories/{checkbox-one/sourceDetail.json → checkbox/sourceOneDetail.json} +0 -0
- /package/src/stories/{date-picker → datepicker}/source.json +0 -0
- /package/src/stories/{markdown/source.json → declaration/sourceMarkdown.json} +0 -0
- /package/src/stories/duration/{mois.json → sourceMonths.json} +0 -0
- /package/src/stories/duration/{time.json → sourceTime.json} +0 -0
- /package/src/stories/filter-description/{source-options.json → sourceOptions.json} +0 -0
- /package/src/stories/table/{table-dynamique.json → source-dynamic.json} +0 -0
package/src/type.source.ts
CHANGED
|
@@ -239,6 +239,8 @@ export type Variable =
|
|
|
239
239
|
variableType: 'EXTERNAL';
|
|
240
240
|
name: string;
|
|
241
241
|
value: VariableValue;
|
|
242
|
+
iterationReference?: string;
|
|
243
|
+
dimension?: number;
|
|
242
244
|
}
|
|
243
245
|
| {
|
|
244
246
|
variableType: 'COLLECTED';
|
|
@@ -246,6 +248,8 @@ export type Variable =
|
|
|
246
248
|
values?: {
|
|
247
249
|
COLLECTED: VariableValue;
|
|
248
250
|
};
|
|
251
|
+
iterationReference?: string;
|
|
252
|
+
dimension?: number;
|
|
249
253
|
}
|
|
250
254
|
| {
|
|
251
255
|
variableType: 'CALCULATED';
|
|
@@ -253,6 +257,8 @@ export type Variable =
|
|
|
253
257
|
expression: VTLExpression;
|
|
254
258
|
bindingDependencies?: string[];
|
|
255
259
|
shapeFrom?: string[] | string;
|
|
260
|
+
iterationReference?: string;
|
|
261
|
+
dimension?: number;
|
|
256
262
|
};
|
|
257
263
|
export type VariableValue = VariableScalarValue | unknown[];
|
|
258
264
|
export type VariableScalarValue = string | number | null;
|
|
@@ -340,6 +346,7 @@ export type ComponentDefinitionBase = {
|
|
|
340
346
|
id: string;
|
|
341
347
|
isMandatory?: boolean;
|
|
342
348
|
missingResponse?: ResponseDefinition;
|
|
349
|
+
conditionReadOnly?: VTLScalarExpression;
|
|
343
350
|
};
|
|
344
351
|
export type Declaration = {
|
|
345
352
|
id: string;
|
|
@@ -371,7 +378,7 @@ export type VTLScalarExpression = {
|
|
|
371
378
|
export type ControlDefinition = {
|
|
372
379
|
id: string;
|
|
373
380
|
criticality: 'INFO' | 'WARN' | 'ERROR';
|
|
374
|
-
typeOfControl?: 'FORMAT' | 'CONSISTENCY';
|
|
381
|
+
typeOfControl?: 'FORMAT' | 'CONSISTENCY' | 'MANDATORY';
|
|
375
382
|
control: VTLExpression;
|
|
376
383
|
errorMessage: VTLExpression;
|
|
377
384
|
bindingDependencies?: string[];
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { replaceComponentSequence } from '../replace-component-sequence';
|
|
2
1
|
import type {
|
|
3
2
|
LunaticComponentDefinition,
|
|
4
3
|
LunaticControl,
|
|
@@ -27,22 +26,29 @@ type InterpretedLoopComponent = DeepTranslateExpression<
|
|
|
27
26
|
>;
|
|
28
27
|
|
|
29
28
|
const isLoopComponent = (
|
|
30
|
-
component: InterpretedComponent
|
|
29
|
+
component: ComponentDefinition | InterpretedComponent
|
|
31
30
|
): component is InterpretedLoopComponent => {
|
|
32
31
|
return ['Loop', 'RosterForLoop', 'Roundabout'].includes(
|
|
33
32
|
component.componentType
|
|
34
33
|
);
|
|
35
34
|
};
|
|
36
35
|
|
|
36
|
+
const isQuestionComponent = (
|
|
37
|
+
component: ComponentDefinition | InterpretedComponent
|
|
38
|
+
) => {
|
|
39
|
+
return 'Question' === component.componentType;
|
|
40
|
+
};
|
|
41
|
+
|
|
37
42
|
/**
|
|
38
43
|
* Check if components of the current page have errors, and return a map of
|
|
39
44
|
* errors (indexed by component ID).
|
|
40
45
|
*/
|
|
41
46
|
function checkComponents(
|
|
42
47
|
state: StateForControls,
|
|
43
|
-
components: InterpretedComponent[]
|
|
48
|
+
components: (ComponentDefinition | InterpretedComponent)[],
|
|
49
|
+
currentErrors?: Record<string, LunaticError[]>
|
|
44
50
|
): Record<string, LunaticError[]> {
|
|
45
|
-
let errors = {} as Record<string, LunaticError[]
|
|
51
|
+
let errors = currentErrors ?? ({} as Record<string, LunaticError[]>);
|
|
46
52
|
|
|
47
53
|
for (const component of components) {
|
|
48
54
|
// The component has global level controls
|
|
@@ -58,24 +64,36 @@ function checkComponents(
|
|
|
58
64
|
}
|
|
59
65
|
|
|
60
66
|
// For loop, inspect children
|
|
61
|
-
if (isLoopComponent(component))
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
errors
|
|
68
|
-
);
|
|
69
|
-
}
|
|
70
|
-
for (const child of component.components) {
|
|
71
|
-
errors = checkComponentInLoop(state, child, errors);
|
|
72
|
-
}
|
|
73
|
-
}
|
|
67
|
+
if (isLoopComponent(component))
|
|
68
|
+
errors = checkLoop(state, component, errors);
|
|
69
|
+
|
|
70
|
+
// For Question, loop over children
|
|
71
|
+
if (isQuestionComponent(component))
|
|
72
|
+
errors = checkComponents(state, component.components, errors);
|
|
74
73
|
}
|
|
75
74
|
|
|
76
75
|
return errors;
|
|
77
76
|
}
|
|
78
77
|
|
|
78
|
+
function checkLoop(
|
|
79
|
+
state: StateForControls,
|
|
80
|
+
component: InterpretedLoopComponent,
|
|
81
|
+
errors: Record<string, LunaticError[]>
|
|
82
|
+
) {
|
|
83
|
+
const rowControls = component.controls?.filter((c) => c.type === 'ROW');
|
|
84
|
+
if (rowControls?.length) {
|
|
85
|
+
errors = checkComponentInLoop(
|
|
86
|
+
state,
|
|
87
|
+
{ ...component, controls: rowControls },
|
|
88
|
+
errors
|
|
89
|
+
);
|
|
90
|
+
}
|
|
91
|
+
for (const child of component.components) {
|
|
92
|
+
errors = checkComponentInLoop(state, child, errors);
|
|
93
|
+
}
|
|
94
|
+
return errors;
|
|
95
|
+
}
|
|
96
|
+
|
|
79
97
|
function checkControls(
|
|
80
98
|
controls: LunaticControl[],
|
|
81
99
|
executeExpression: LunaticReducerState['executeExpression'],
|
|
@@ -214,7 +232,7 @@ function hasCriticalError(errors?: Record<string, LunaticError[]>): boolean {
|
|
|
214
232
|
* Check controls for currently visible components and output errors.
|
|
215
233
|
*/
|
|
216
234
|
export function compileControls(state: StateForControls) {
|
|
217
|
-
const components =
|
|
235
|
+
const components = getComponentsFromState(state);
|
|
218
236
|
const componentFiltered = components
|
|
219
237
|
.map((component) => fillComponentExpressions(component, state))
|
|
220
238
|
.filter((component) => {
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { ReactNode } from 'react';
|
|
2
|
-
import { isObject } from '../../../utils/is-object';
|
|
3
2
|
import type {
|
|
4
3
|
LunaticComponentDefinition,
|
|
5
4
|
LunaticExpression,
|
|
6
5
|
LunaticReducerState,
|
|
7
6
|
} from '../../type';
|
|
7
|
+
import { isObject } from '../../../utils/object';
|
|
8
8
|
|
|
9
9
|
const VTL_ATTRIBUTES = [
|
|
10
10
|
['label', null],
|
|
@@ -28,7 +28,7 @@ const VTL_ATTRIBUTES = [
|
|
|
28
28
|
['conditionFilter', castBool],
|
|
29
29
|
['header.label', null],
|
|
30
30
|
['disabled', castBool],
|
|
31
|
-
['
|
|
31
|
+
['conditionReadOnly', castBool],
|
|
32
32
|
// For suggesters
|
|
33
33
|
['arbitrary.label', castString],
|
|
34
34
|
['arbitrary.inputLabel', castString],
|
|
@@ -47,6 +47,9 @@ function castNumber(v: unknown): number {
|
|
|
47
47
|
if (Array.isArray(v) && v.length > 0) {
|
|
48
48
|
return castNumber(v[0]);
|
|
49
49
|
}
|
|
50
|
+
if (v === null) {
|
|
51
|
+
return 0;
|
|
52
|
+
}
|
|
50
53
|
throw new Error(`Cannot cast "${v}" to number`);
|
|
51
54
|
}
|
|
52
55
|
|
|
@@ -87,6 +90,7 @@ type UntranslatedProperties =
|
|
|
87
90
|
| 'item'
|
|
88
91
|
| 'controls'
|
|
89
92
|
| 'conditionFilter'
|
|
93
|
+
| 'conditionReadOnly'
|
|
90
94
|
| 'components';
|
|
91
95
|
export type DeepTranslateExpression<T> = T extends LunaticExpression
|
|
92
96
|
? ReactNode
|
|
@@ -704,4 +704,56 @@ describe('fillComponents', () => {
|
|
|
704
704
|
expect(radio.options[1].conditionFilter).toBe(undefined);
|
|
705
705
|
expect(radio.options[1].shouldBeFiltered).toBe(true);
|
|
706
706
|
});
|
|
707
|
+
|
|
708
|
+
it('should set component (and all its children) as readOnly if conditionReadOnly is evaluated to true', () => {
|
|
709
|
+
const components = [
|
|
710
|
+
{
|
|
711
|
+
id: 'question-m8ilvkbt',
|
|
712
|
+
componentType: 'Question',
|
|
713
|
+
page: '1',
|
|
714
|
+
label: {
|
|
715
|
+
value: '"Question label"',
|
|
716
|
+
type: 'VTL|MD',
|
|
717
|
+
},
|
|
718
|
+
conditionReadOnly: {
|
|
719
|
+
type: 'VTL',
|
|
720
|
+
value: 'true',
|
|
721
|
+
},
|
|
722
|
+
components: [
|
|
723
|
+
{
|
|
724
|
+
id: 'm8ilvkbt',
|
|
725
|
+
componentType: 'Input',
|
|
726
|
+
page: '1',
|
|
727
|
+
maxLength: 249,
|
|
728
|
+
response: {
|
|
729
|
+
name: 'TESTTEXTE',
|
|
730
|
+
},
|
|
731
|
+
},
|
|
732
|
+
],
|
|
733
|
+
},
|
|
734
|
+
];
|
|
735
|
+
|
|
736
|
+
const mockVariables = LunaticVariablesStore.makeFromObject({
|
|
737
|
+
TESTTEXTE: 'some value',
|
|
738
|
+
});
|
|
739
|
+
|
|
740
|
+
const mockState = {
|
|
741
|
+
...defaultMockState,
|
|
742
|
+
disableFilters: true,
|
|
743
|
+
variables: mockVariables,
|
|
744
|
+
};
|
|
745
|
+
|
|
746
|
+
const filledComponents = fillComponents(
|
|
747
|
+
components as LunaticComponentDefinition[],
|
|
748
|
+
mockState as unknown as FillComponentArgs
|
|
749
|
+
) as any;
|
|
750
|
+
|
|
751
|
+
const question = filledComponents[0];
|
|
752
|
+
|
|
753
|
+
expect(question.componentType).toBe('Question');
|
|
754
|
+
expect(question.readOnly).toBe(true);
|
|
755
|
+
|
|
756
|
+
const input = question.components[0];
|
|
757
|
+
expect(input.readOnly).toBe(true);
|
|
758
|
+
});
|
|
707
759
|
});
|
|
@@ -38,12 +38,24 @@ export const fillComponent = (
|
|
|
38
38
|
component: LunaticComponentDefinition,
|
|
39
39
|
state: FillComponentArgs,
|
|
40
40
|
// the given parentConditionFilter is typed as VTLScalarExpression, but it's actually a boolean or undefined
|
|
41
|
-
parentConditionFilter?: any
|
|
41
|
+
parentConditionFilter?: any,
|
|
42
|
+
// the given parentReadonly is typed as VTLScalarExpression, but it's actually a boolean or undefined
|
|
43
|
+
parentReadOnly?: any
|
|
42
44
|
): LunaticComponentProps & { conditionFilter?: boolean } => {
|
|
43
45
|
const interpretedProps = fillComponentExpressions(component, state);
|
|
44
46
|
|
|
45
47
|
const shouldParentBeFiltered = parentConditionFilter === false;
|
|
46
48
|
|
|
49
|
+
const isParentReadOnly = parentReadOnly === true;
|
|
50
|
+
|
|
51
|
+
// if a parent component is readOnly, then the children also are
|
|
52
|
+
const readOnly =
|
|
53
|
+
isParentReadOnly ||
|
|
54
|
+
('conditionReadOnly' in interpretedProps
|
|
55
|
+
? interpretedProps.conditionReadOnly
|
|
56
|
+
: false);
|
|
57
|
+
|
|
58
|
+
// if a parent component is filtered, then the children also are
|
|
47
59
|
const shouldBeFiltered =
|
|
48
60
|
shouldParentBeFiltered ||
|
|
49
61
|
('conditionFilter' in interpretedProps
|
|
@@ -60,6 +72,7 @@ export const fillComponent = (
|
|
|
60
72
|
shortcut: state.shortcut,
|
|
61
73
|
goNextPage: state.goNextPage,
|
|
62
74
|
goPreviousPage: state.goPreviousPage,
|
|
75
|
+
readOnly: readOnly,
|
|
63
76
|
shouldBeFiltered: shouldBeFiltered,
|
|
64
77
|
iteration: state.pager.iteration,
|
|
65
78
|
required: 'isMandatory' in component ? component.isMandatory : false,
|
|
@@ -89,7 +102,8 @@ export function fillComponents(
|
|
|
89
102
|
components: LunaticComponentDefinition[],
|
|
90
103
|
state: FillComponentArgs,
|
|
91
104
|
parentType?: LunaticComponentDefinition['componentType'],
|
|
92
|
-
parentConditionFilter?: VTLScalarExpression
|
|
105
|
+
parentConditionFilter?: VTLScalarExpression,
|
|
106
|
+
parentReadOnly?: VTLScalarExpression
|
|
93
107
|
): LunaticComponentProps[] {
|
|
94
108
|
// Flatmap to directly remove FilterDescription components if disableFiltersDescription is true
|
|
95
109
|
const filledComponents = components.flatMap((component) => {
|
|
@@ -100,7 +114,9 @@ export function fillComponents(
|
|
|
100
114
|
return [];
|
|
101
115
|
}
|
|
102
116
|
|
|
103
|
-
return [
|
|
117
|
+
return [
|
|
118
|
+
fillComponent(component, state, parentConditionFilter, parentReadOnly),
|
|
119
|
+
];
|
|
104
120
|
});
|
|
105
121
|
|
|
106
122
|
if (state.disableFilters) {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { useCallback } from 'react';
|
|
2
|
-
import { isObject } from '../../utils/is-object';
|
|
3
2
|
import type { LunaticComponentDefinition, LunaticReducerState } from '../type';
|
|
4
3
|
import type { LunaticComponentProps } from '../../components/type';
|
|
4
|
+
import { isObject } from '../../utils/object';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Check if a page has one response (value is filled for at least one field).
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { renderHook } from '@testing-library/react';
|
|
2
2
|
import { describe, expect, it } from 'vitest';
|
|
3
|
-
import source from '../../stories/overview/
|
|
3
|
+
import source from '../../stories/behaviour/overview/source.json';
|
|
4
4
|
import { useLunatic } from '../use-lunatic';
|
|
5
|
-
|
|
5
|
+
|
|
6
|
+
import { dataFromObject } from '../../utils/object';
|
|
6
7
|
|
|
7
8
|
describe('use-overview test with useLunatic()', () => {
|
|
8
9
|
it('should initialize correctly with disableFilters: false (without data)', () => {
|
|
@@ -1,25 +1,19 @@
|
|
|
1
1
|
import { act, renderHook } from '@testing-library/react';
|
|
2
2
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
3
|
|
|
4
|
-
import sourceWithoutHierarchy from '../stories/overview/source.json';
|
|
5
4
|
import sourceLogement from '../stories/questionnaires/logement/source.json';
|
|
6
5
|
import sourceSimpsons from '../stories/questionnaires/simpsons/source.json';
|
|
7
|
-
import sourceOverview from '../stories/overview/sourceLoop.json';
|
|
8
|
-
import sourceCheckboxGroup from '../stories/checkbox
|
|
9
|
-
import dataOverview from '../stories/overview/dataLoop.json';
|
|
6
|
+
import sourceOverview from '../stories/behaviour/overview/sourceLoop.json';
|
|
7
|
+
import sourceCheckboxGroup from '../stories/checkbox/sourceGroup.json';
|
|
10
8
|
import sourceCleaningLoop from '../stories/behaviour/cleaning/source-loop.json';
|
|
11
9
|
import sourceCleaningResizing from '../stories/behaviour/resizing/source-resizing-cleaning.json';
|
|
12
10
|
import type { PageTag } from './type';
|
|
13
11
|
import { useLunatic } from './use-lunatic';
|
|
14
12
|
import { useCallback } from 'react';
|
|
15
|
-
import { dataFromObject } from '
|
|
13
|
+
import { dataFromObject } from '../utils/object';
|
|
16
14
|
|
|
17
15
|
describe('use-lunatic()', () => {
|
|
18
|
-
const defaultParams = [
|
|
19
|
-
sourceSimpsons as any,
|
|
20
|
-
dataFromObject({}),
|
|
21
|
-
{},
|
|
22
|
-
] as const;
|
|
16
|
+
const defaultParams = [sourceSimpsons, dataFromObject({}), {}] as const;
|
|
23
17
|
|
|
24
18
|
it('should initialize correctly', () => {
|
|
25
19
|
const { result } = renderHook(() => useLunatic(...defaultParams));
|
|
@@ -39,7 +33,7 @@ describe('use-lunatic()', () => {
|
|
|
39
33
|
});
|
|
40
34
|
it('should jump to a specific page', () => {
|
|
41
35
|
const params = [
|
|
42
|
-
sourceSimpsons
|
|
36
|
+
sourceSimpsons,
|
|
43
37
|
dataFromObject({
|
|
44
38
|
COMMENT: 'Hello world',
|
|
45
39
|
READY: true,
|
|
@@ -102,7 +96,7 @@ describe('use-lunatic()', () => {
|
|
|
102
96
|
it('should not generate a new Provider every render', () => {
|
|
103
97
|
const { result } = renderHook(() => {
|
|
104
98
|
const missingStrategy = useCallback(() => {}, []);
|
|
105
|
-
return useLunatic(sourceSimpsons
|
|
99
|
+
return useLunatic(sourceSimpsons, undefined, {
|
|
106
100
|
management: false,
|
|
107
101
|
missing: false,
|
|
108
102
|
missingStrategy,
|
|
@@ -146,7 +140,7 @@ describe('use-lunatic()', () => {
|
|
|
146
140
|
it('should not calculate overview by default', function () {
|
|
147
141
|
const { result } = renderHook(() =>
|
|
148
142
|
useLunatic(
|
|
149
|
-
sourceLogement
|
|
143
|
+
sourceLogement,
|
|
150
144
|
undefined,
|
|
151
145
|
lunaticConfigurationWithoutOverview
|
|
152
146
|
)
|
|
@@ -156,7 +150,7 @@ describe('use-lunatic()', () => {
|
|
|
156
150
|
});
|
|
157
151
|
it('should make the first sequence visible', function () {
|
|
158
152
|
const { result } = renderHook(() =>
|
|
159
|
-
useLunatic(sourceLogement
|
|
153
|
+
useLunatic(sourceLogement, undefined, {
|
|
160
154
|
...lunaticConfiguration,
|
|
161
155
|
})
|
|
162
156
|
);
|
|
@@ -167,11 +161,7 @@ describe('use-lunatic()', () => {
|
|
|
167
161
|
});
|
|
168
162
|
it('should be empty when no hierarchy', function () {
|
|
169
163
|
const { result } = renderHook(() =>
|
|
170
|
-
useLunatic(
|
|
171
|
-
sourceWithoutHierarchy as any,
|
|
172
|
-
undefined,
|
|
173
|
-
lunaticConfiguration
|
|
174
|
-
)
|
|
164
|
+
useLunatic(sourceCheckboxGroup, undefined, lunaticConfiguration)
|
|
175
165
|
);
|
|
176
166
|
expect(result.current.overview).toHaveLength(0);
|
|
177
167
|
});
|
|
@@ -179,7 +169,7 @@ describe('use-lunatic()', () => {
|
|
|
179
169
|
describe('with initial data', function () {
|
|
180
170
|
it('should make second sequence visible', function () {
|
|
181
171
|
const { result } = renderHook(() =>
|
|
182
|
-
useLunatic(sourceLogement
|
|
172
|
+
useLunatic(sourceLogement, advancedQestionnaireData, {
|
|
183
173
|
...lunaticConfiguration,
|
|
184
174
|
initialPage: '16',
|
|
185
175
|
})
|
|
@@ -192,19 +182,42 @@ describe('use-lunatic()', () => {
|
|
|
192
182
|
});
|
|
193
183
|
|
|
194
184
|
describe('with loop', function () {
|
|
185
|
+
const data = dataFromObject({
|
|
186
|
+
ETAT: '1',
|
|
187
|
+
SATISFAIT: '1',
|
|
188
|
+
T_NHAB: 3,
|
|
189
|
+
T_PRENOM: ['Quentin', 'Luna', 'Paul'],
|
|
190
|
+
COMMCOMPO: 'super',
|
|
191
|
+
T_SEXE: ['1', '2', '1'],
|
|
192
|
+
T_DATENAIS: [null, null, null],
|
|
193
|
+
REMARQUES: [null, 'a', 'b'],
|
|
194
|
+
SUPERQUEST: ['ok', 'ok', null],
|
|
195
|
+
AUTRESUPERQUEST: ['a', 'c', 'ras'],
|
|
196
|
+
ENCOREUNEQ: ['wow', 'b', null],
|
|
197
|
+
COMMENT_QE: null,
|
|
198
|
+
ETAT_MISSING: null,
|
|
199
|
+
SATISFAIT_MISSING: null,
|
|
200
|
+
T_NHAB_MISSING: null,
|
|
201
|
+
T_PRENOM_MISSING: null,
|
|
202
|
+
COMMCOMPO_MISSING: null,
|
|
203
|
+
T_SEXE_MISSING: null,
|
|
204
|
+
T_DATENAIS_MISSING: [null, 'DK', 'RF'],
|
|
205
|
+
REMARQUES_MISSING: [null, null, null],
|
|
206
|
+
SUPERQUEST_MISSING: [null, null, 'DK'],
|
|
207
|
+
ENCOREUNEQ_MISSING: [null, null, 'RF'],
|
|
208
|
+
AUTRESUPERQUEST_MISSING: null,
|
|
209
|
+
COMMENT_QE_MISSING: null,
|
|
210
|
+
});
|
|
211
|
+
|
|
195
212
|
it('should work with loop', async () => {
|
|
196
213
|
const { result } = renderHook(() =>
|
|
197
|
-
useLunatic(
|
|
198
|
-
sourceOverview as any,
|
|
199
|
-
dataOverview.data,
|
|
200
|
-
lunaticConfiguration
|
|
201
|
-
)
|
|
214
|
+
useLunatic(sourceOverview, data, lunaticConfiguration)
|
|
202
215
|
);
|
|
203
216
|
expect(result.current.overview).toMatchSnapshot();
|
|
204
217
|
});
|
|
205
218
|
it('should handle initialPage', async () => {
|
|
206
219
|
const { result } = renderHook(() =>
|
|
207
|
-
useLunatic(sourceOverview
|
|
220
|
+
useLunatic(sourceOverview, data, {
|
|
208
221
|
...lunaticConfiguration,
|
|
209
222
|
initialPage: '10.1#1',
|
|
210
223
|
})
|
|
@@ -230,7 +243,7 @@ describe('use-lunatic()', () => {
|
|
|
230
243
|
it('should filter out some components by default', function () {
|
|
231
244
|
const { result } = renderHook(() =>
|
|
232
245
|
useLunatic(
|
|
233
|
-
sourceLogement
|
|
246
|
+
sourceLogement,
|
|
234
247
|
undefined,
|
|
235
248
|
lunaticConfigurationWithoutDisableFilters
|
|
236
249
|
)
|
|
@@ -241,7 +254,7 @@ describe('use-lunatic()', () => {
|
|
|
241
254
|
});
|
|
242
255
|
it('should filter out some components when false', function () {
|
|
243
256
|
const { result } = renderHook(() =>
|
|
244
|
-
useLunatic(sourceLogement
|
|
257
|
+
useLunatic(sourceLogement, undefined, {
|
|
245
258
|
...lunaticConfigurationWithoutDisableFilters,
|
|
246
259
|
disableFilters: false,
|
|
247
260
|
})
|
|
@@ -252,7 +265,7 @@ describe('use-lunatic()', () => {
|
|
|
252
265
|
});
|
|
253
266
|
it('should not filter any component when true', function () {
|
|
254
267
|
const { result } = renderHook(() =>
|
|
255
|
-
useLunatic(sourceLogement
|
|
268
|
+
useLunatic(sourceLogement, undefined, {
|
|
256
269
|
...lunaticConfigurationWithoutDisableFilters,
|
|
257
270
|
disableFilters: true,
|
|
258
271
|
})
|
|
@@ -269,7 +282,7 @@ describe('use-lunatic()', () => {
|
|
|
269
282
|
describe('cleaning', () => {
|
|
270
283
|
it('should handle cleaning in a loop', () => {
|
|
271
284
|
const { result } = renderHook(() =>
|
|
272
|
-
useLunatic(sourceCleaningLoop
|
|
285
|
+
useLunatic(sourceCleaningLoop, undefined)
|
|
273
286
|
);
|
|
274
287
|
act(() => {
|
|
275
288
|
result.current.handleChanges([
|
|
@@ -284,9 +297,9 @@ describe('use-lunatic()', () => {
|
|
|
284
297
|
result.current.goNextPage();
|
|
285
298
|
});
|
|
286
299
|
const expectCollectedAgeToEqual = (expectation: unknown[]) => {
|
|
287
|
-
expect(
|
|
288
|
-
|
|
289
|
-
)
|
|
300
|
+
expect(result.current.getData(false).COLLECTED?.AGE.COLLECTED).toEqual(
|
|
301
|
+
expectation
|
|
302
|
+
);
|
|
290
303
|
};
|
|
291
304
|
expectCollectedAgeToEqual([18, 18, 18]);
|
|
292
305
|
act(() => {
|
|
@@ -306,17 +319,17 @@ describe('use-lunatic()', () => {
|
|
|
306
319
|
it('should resize after cleaning', () => {
|
|
307
320
|
const spy = vi.fn();
|
|
308
321
|
const { result } = renderHook(() =>
|
|
309
|
-
useLunatic(sourceCleaningResizing
|
|
322
|
+
useLunatic(sourceCleaningResizing, undefined, {
|
|
310
323
|
onChange: spy,
|
|
311
324
|
})
|
|
312
325
|
);
|
|
313
326
|
act(() => result.current.handleChanges([{ name: 'NB', value: 3 }]));
|
|
314
327
|
expect(
|
|
315
|
-
|
|
328
|
+
result.current.getData(true).COLLECTED?.PRENOMS?.COLLECTED
|
|
316
329
|
).toEqual([null, null, null]);
|
|
317
330
|
act(() => result.current.handleChanges([{ name: 'NB', value: 2 }]));
|
|
318
331
|
expect(
|
|
319
|
-
|
|
332
|
+
result.current.getData(true).COLLECTED?.PRENOMS?.COLLECTED
|
|
320
333
|
).toEqual([null, null]);
|
|
321
334
|
});
|
|
322
335
|
});
|
|
@@ -325,7 +338,7 @@ describe('use-lunatic()', () => {
|
|
|
325
338
|
let hookRef: { current: ReturnType<typeof useLunatic> };
|
|
326
339
|
beforeEach(() => {
|
|
327
340
|
const { result } = renderHook(() =>
|
|
328
|
-
useLunatic(sourceSimpsons
|
|
341
|
+
useLunatic(sourceSimpsons, undefined, {})
|
|
329
342
|
);
|
|
330
343
|
act(() => {
|
|
331
344
|
result.current.handleChanges([
|
|
@@ -353,7 +366,7 @@ describe('use-lunatic()', () => {
|
|
|
353
366
|
let hookRef: { current: ReturnType<typeof useLunatic> };
|
|
354
367
|
beforeEach(() => {
|
|
355
368
|
const { result } = renderHook(() =>
|
|
356
|
-
useLunatic(sourceSimpsons
|
|
369
|
+
useLunatic(sourceSimpsons, undefined, { trackChanges: true })
|
|
357
370
|
);
|
|
358
371
|
hookRef = result;
|
|
359
372
|
});
|
|
@@ -425,7 +438,7 @@ describe('use-lunatic()', () => {
|
|
|
425
438
|
describe('pageHasResponse', () => {
|
|
426
439
|
it('should detect change on a field', () => {
|
|
427
440
|
const { result } = renderHook(() =>
|
|
428
|
-
useLunatic(sourceCheckboxGroup
|
|
441
|
+
useLunatic(sourceCheckboxGroup, undefined, {})
|
|
429
442
|
);
|
|
430
443
|
act(() => {
|
|
431
444
|
result.current.handleChanges([{ name: 'NATIO1N1', value: true }]);
|
|
@@ -434,7 +447,7 @@ describe('use-lunatic()', () => {
|
|
|
434
447
|
});
|
|
435
448
|
it('should not detect unchecked box has a response', () => {
|
|
436
449
|
const { result } = renderHook(() =>
|
|
437
|
-
useLunatic(sourceCheckboxGroup
|
|
450
|
+
useLunatic(sourceCheckboxGroup, undefined, {})
|
|
438
451
|
);
|
|
439
452
|
act(() => {
|
|
440
453
|
result.current.handleChanges([{ name: 'NATIO1N1', value: false }]);
|
package/src/utils/number.ts
CHANGED
|
@@ -31,3 +31,16 @@ export function between(n: number, min: number, max: number): number {
|
|
|
31
31
|
export function isNumber(n: unknown): n is number {
|
|
32
32
|
return typeof n === 'number' && Number.isFinite(n);
|
|
33
33
|
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Convert an unknown value into a number
|
|
37
|
+
*/
|
|
38
|
+
export function toNumber(v: unknown): number | null {
|
|
39
|
+
if (typeof v === 'number') {
|
|
40
|
+
return v;
|
|
41
|
+
}
|
|
42
|
+
if (typeof v === 'string') {
|
|
43
|
+
return parseInt(v, 10);
|
|
44
|
+
}
|
|
45
|
+
return null;
|
|
46
|
+
}
|
package/src/utils/object.ts
CHANGED
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { LunaticData } from '../use-lunatic/type';
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Array.map() but for objet
|
|
3
5
|
*/
|
|
@@ -18,6 +20,21 @@ export function objectMap<T extends Record<string, any>, V>(
|
|
|
18
20
|
{} as Record<keyof T, V>
|
|
19
21
|
);
|
|
20
22
|
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Filter items from an object
|
|
26
|
+
*/
|
|
27
|
+
export function objectFilter<T extends Record<string, any>>(
|
|
28
|
+
object: T,
|
|
29
|
+
callback: (k: keyof T, v: T[keyof T]) => boolean
|
|
30
|
+
): T {
|
|
31
|
+
return Object.fromEntries(
|
|
32
|
+
Object.entries(object).filter(([k, v]) => {
|
|
33
|
+
return callback(k, v);
|
|
34
|
+
})
|
|
35
|
+
) as T;
|
|
36
|
+
}
|
|
37
|
+
|
|
21
38
|
// Adds the possibility of preserving the original type of the object's keys.
|
|
22
39
|
// The native function produces an array of strings. (Object.keys)
|
|
23
40
|
export function objectKeys<T extends Record<string, unknown>>(object: T) {
|
|
@@ -33,3 +50,26 @@ export function mergeDefault<
|
|
|
33
50
|
return [k, obj[k] ?? defaults[k]] as const;
|
|
34
51
|
});
|
|
35
52
|
}
|
|
53
|
+
|
|
54
|
+
export const dataFromObject = (o: Record<string, unknown>): LunaticData => {
|
|
55
|
+
return {
|
|
56
|
+
EXTERNAL: {},
|
|
57
|
+
COLLECTED: Object.keys(o).reduce(
|
|
58
|
+
(acc, k) => ({
|
|
59
|
+
...acc,
|
|
60
|
+
[k]: {
|
|
61
|
+
COLLECTED: o[k],
|
|
62
|
+
},
|
|
63
|
+
}),
|
|
64
|
+
{}
|
|
65
|
+
),
|
|
66
|
+
CALCULATED: {},
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
|
|
70
|
+
/**
|
|
71
|
+
* isObject function with type narrowing
|
|
72
|
+
*/
|
|
73
|
+
export function isObject(v: unknown): v is Record<string, unknown> {
|
|
74
|
+
return typeof v === 'object' && v !== null;
|
|
75
|
+
}
|