@react-typed-forms/schemas 14.0.4 → 14.0.5
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/coverage/clover.xml +867 -120
- package/coverage/coverage-final.json +16 -4
- package/coverage/lcov-report/index.html +28 -28
- package/coverage/lcov-report/src/controlBuilder.ts.html +889 -0
- package/coverage/lcov-report/src/controlDefinition.ts.html +1 -1
- package/coverage/lcov-report/src/controlRender.tsx.html +3532 -0
- package/coverage/lcov-report/src/createFormRenderer.tsx.html +721 -0
- package/coverage/lcov-report/src/defaultSchemaInterface.ts.html +658 -0
- package/coverage/lcov-report/src/dynamicHooks.ts.html +379 -0
- package/coverage/lcov-report/src/entityExpression.ts.html +199 -0
- package/coverage/lcov-report/src/hooks.tsx.html +1462 -0
- package/coverage/lcov-report/src/index.html +198 -18
- package/coverage/lcov-report/src/index.ts.html +127 -0
- package/coverage/lcov-report/src/renderers.tsx.html +679 -0
- package/coverage/lcov-report/src/schemaBuilder.ts.html +1039 -0
- package/coverage/lcov-report/src/schemaField.ts.html +35 -32
- package/coverage/lcov-report/src/schemaValidator.ts.html +181 -0
- package/coverage/lcov-report/src/util.ts.html +29 -131
- package/coverage/lcov-report/src/validators.ts.html +736 -0
- package/coverage/lcov-report/test/gen.ts.html +217 -82
- package/coverage/lcov-report/test/index.html +17 -17
- package/coverage/lcov.info +2091 -271
- package/jest.config.js +3 -2
- package/lib/index.cjs +1 -1
- package/lib/index.cjs.map +1 -1
- package/lib/index.js +1 -1
- package/lib/index.js.map +1 -1
- package/lib/util.d.ts +1 -1
- package/package.json +1 -1
- package/test/diff.test.ts +68 -88
- package/test/gen.ts +78 -33
- package/test/play.ts +45 -41
- package/tsconfig.json +1 -1
package/lib/util.d.ts
CHANGED
|
@@ -243,4 +243,4 @@ export declare function isControlDisplayOnly(def: ControlDefinition): boolean;
|
|
|
243
243
|
* @returns {ControlActionHandler} - The combined action handler.
|
|
244
244
|
*/
|
|
245
245
|
export declare function actionHandlers(...handlers: (ControlActionHandler | undefined)[]): ControlActionHandler;
|
|
246
|
-
export declare function getDiffObject(dataNode: SchemaDataNode,
|
|
246
|
+
export declare function getDiffObject(dataNode: SchemaDataNode, force?: boolean): any;
|
package/package.json
CHANGED
package/test/diff.test.ts
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
import { describe, expect, it } from "@jest/globals";
|
|
2
2
|
import fc from "fast-check";
|
|
3
|
-
import {
|
|
3
|
+
import { makeDataNode, newIndexes, valueAndSchema } from "./gen";
|
|
4
|
+
import { getDiffObject, getTagParam, SchemaDataNode, SchemaTags } from "../src";
|
|
4
5
|
import {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
SchemaTags,
|
|
10
|
-
} from "../src";
|
|
11
|
-
import { Control } from "@react-typed-forms/core";
|
|
6
|
+
deepEquals,
|
|
7
|
+
newElement,
|
|
8
|
+
updateElements,
|
|
9
|
+
} from "@react-typed-forms/core";
|
|
12
10
|
|
|
13
11
|
describe("diff", () => {
|
|
14
12
|
it("unchanged value always returns undefined", () => {
|
|
@@ -27,7 +25,7 @@ describe("diff", () => {
|
|
|
27
25
|
(fv) => {
|
|
28
26
|
const dataNode = makeDataNode(fv);
|
|
29
27
|
const control = dataNode.control!;
|
|
30
|
-
control.setValue((x) =>
|
|
28
|
+
control.setValue((x) => fv.newValue);
|
|
31
29
|
expect(getDiffObject(dataNode)).toBe(control.value);
|
|
32
30
|
},
|
|
33
31
|
),
|
|
@@ -37,25 +35,23 @@ describe("diff", () => {
|
|
|
37
35
|
it("compound fields only return changed values", () => {
|
|
38
36
|
fc.assert(
|
|
39
37
|
fc.property(
|
|
40
|
-
valueAndSchema({
|
|
38
|
+
valueAndSchema({
|
|
39
|
+
arrayChance: 0,
|
|
40
|
+
compoundChance: 0,
|
|
41
|
+
forceCompound: true,
|
|
42
|
+
}),
|
|
41
43
|
(fv) => {
|
|
42
44
|
const dataNode = makeDataNode(fv);
|
|
43
45
|
const control = dataNode.control!;
|
|
44
|
-
|
|
45
|
-
const
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
} else {
|
|
54
|
-
delete result[fieldName];
|
|
55
|
-
}
|
|
56
|
-
});
|
|
57
|
-
control.value = newValue;
|
|
58
|
-
expect(getDiffObject(dataNode)).toStrictEqual(result);
|
|
46
|
+
control.value = fv.newValue;
|
|
47
|
+
const changed = dataNode.schema
|
|
48
|
+
.getChildNodes()
|
|
49
|
+
.map((x) => x.field.field)
|
|
50
|
+
.filter((x) => fv.value?.[x] !== fv.newValue?.[x])
|
|
51
|
+
.map((x) => [x, fv.newValue?.[x]]);
|
|
52
|
+
expect(getDiffObject(dataNode)).toStrictEqual(
|
|
53
|
+
changed.length ? Object.fromEntries(changed) : undefined,
|
|
54
|
+
);
|
|
59
55
|
},
|
|
60
56
|
),
|
|
61
57
|
);
|
|
@@ -74,14 +70,20 @@ describe("diff", () => {
|
|
|
74
70
|
(fv) => {
|
|
75
71
|
const dataNode = makeDataNode(fv);
|
|
76
72
|
const arrayControl = dataNode.control!;
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
73
|
+
arrayControl.value = fv.newValue;
|
|
74
|
+
const idField = getTagParam(
|
|
75
|
+
dataNode.schema.field,
|
|
76
|
+
SchemaTags.IdField,
|
|
77
|
+
);
|
|
78
|
+
const origValues = (fv.value ?? []) as any[];
|
|
79
|
+
const newValues = (fv.newValue ?? []) as any[];
|
|
80
|
+
const expected = newValues.map((nv, i) => {
|
|
81
|
+
if (nv == null) return null;
|
|
82
|
+
return objectDiff(dataNode, origValues[i], nv, idField);
|
|
83
83
|
});
|
|
84
|
-
expect(getDiffObject(dataNode)).toStrictEqual(
|
|
84
|
+
expect(getDiffObject(dataNode)).toStrictEqual(
|
|
85
|
+
arrayControl.dirty ? expected : undefined,
|
|
86
|
+
);
|
|
85
87
|
},
|
|
86
88
|
),
|
|
87
89
|
);
|
|
@@ -95,44 +97,31 @@ describe("diff", () => {
|
|
|
95
97
|
forceCompound: true,
|
|
96
98
|
arrayChance: 0,
|
|
97
99
|
compoundChance: 0,
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
index: fc.integer({ min: 0, max: len }),
|
|
103
|
-
add: len ? fc.boolean() : fc.constant(true),
|
|
104
|
-
})
|
|
105
|
-
.map((x) => ({ ...fv, ...x }));
|
|
106
|
-
}),
|
|
107
|
-
(fv) => {
|
|
100
|
+
})
|
|
101
|
+
.filter((x) => !deepEquals(x.newValue, x.value) && x.value != null)
|
|
102
|
+
.chain((x) => newIndexes(x.value.length).map((i) => [x, i] as const)),
|
|
103
|
+
([fv, indexes]) => {
|
|
108
104
|
const dataNode = makeDataNode(fv);
|
|
109
105
|
const arrayControl = dataNode.control!.as<any[]>();
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
control.value,
|
|
122
|
-
dataNode,
|
|
123
|
-
);
|
|
124
|
-
control.value = newValue;
|
|
125
|
-
change = result;
|
|
126
|
-
} else {
|
|
127
|
-
change = changeValue(control.value, dataNode.schema.field);
|
|
128
|
-
control.value = change;
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
if (!results) results = [];
|
|
132
|
-
results.push({
|
|
133
|
-
old: i,
|
|
134
|
-
edit: change,
|
|
106
|
+
const newValue = fv.newValue as any[];
|
|
107
|
+
const results = Array.from({ length: newValue.length });
|
|
108
|
+
updateElements(arrayControl, (x) => {
|
|
109
|
+
const sorted = indexes.map((ni, i) => {
|
|
110
|
+
const c = x[ni];
|
|
111
|
+
c.value = newValue[i];
|
|
112
|
+
results[i] = {
|
|
113
|
+
old: ni,
|
|
114
|
+
edit: objectDiff(dataNode, c.initialValue, c.value),
|
|
115
|
+
};
|
|
116
|
+
return c;
|
|
135
117
|
});
|
|
118
|
+
while (newValue.length > sorted.length) {
|
|
119
|
+
const ne = newElement(arrayControl, undefined);
|
|
120
|
+
ne.value = newValue[sorted.length];
|
|
121
|
+
results[sorted.length] = { old: undefined, edit: ne.value };
|
|
122
|
+
sorted.push(ne);
|
|
123
|
+
}
|
|
124
|
+
return sorted;
|
|
136
125
|
});
|
|
137
126
|
expect(getDiffObject(dataNode)).toStrictEqual(results);
|
|
138
127
|
},
|
|
@@ -141,26 +130,17 @@ describe("diff", () => {
|
|
|
141
130
|
});
|
|
142
131
|
});
|
|
143
132
|
|
|
144
|
-
function
|
|
145
|
-
existing: Record<string, any>,
|
|
133
|
+
function objectDiff(
|
|
146
134
|
dataNode: SchemaDataNode,
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
if (nv === undefined) nv = null;
|
|
159
|
-
newValue[fieldName] = nv;
|
|
160
|
-
result[fieldName] = nv;
|
|
161
|
-
} else {
|
|
162
|
-
delete result[fieldName];
|
|
163
|
-
}
|
|
164
|
-
});
|
|
165
|
-
return { newValue, result };
|
|
135
|
+
oldValue: Record<string, any> | undefined | null,
|
|
136
|
+
newValue: Record<string, any> | undefined | null,
|
|
137
|
+
idField?: string,
|
|
138
|
+
) {
|
|
139
|
+
if (newValue == null) return oldValue == null ? undefined : newValue;
|
|
140
|
+
const changed = dataNode.schema
|
|
141
|
+
.getChildNodes()
|
|
142
|
+
.map((x) => x.field.field)
|
|
143
|
+
.filter((x) => x == idField || oldValue?.[x] !== newValue[x])
|
|
144
|
+
.map((x) => [x, newValue[x]]);
|
|
145
|
+
return changed.length ? Object.fromEntries(changed) : undefined;
|
|
166
146
|
}
|
package/test/gen.ts
CHANGED
|
@@ -3,6 +3,7 @@ import {
|
|
|
3
3
|
CompoundField,
|
|
4
4
|
createSchemaLookup,
|
|
5
5
|
FieldType,
|
|
6
|
+
getTagParam,
|
|
6
7
|
isCompoundField,
|
|
7
8
|
makeSchemaDataNode,
|
|
8
9
|
SchemaDataNode,
|
|
@@ -16,13 +17,39 @@ export interface FieldAndValue {
|
|
|
16
17
|
value: any;
|
|
17
18
|
}
|
|
18
19
|
|
|
19
|
-
export
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
20
|
+
export interface FieldAndValueChanged extends FieldAndValue {
|
|
21
|
+
newValue: any;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export function newIndexes(arr: number): Arbitrary<number[]> {
|
|
25
|
+
return fc.array(fc.integer(), { minLength: arr, maxLength: arr }).map((x) =>
|
|
26
|
+
x
|
|
27
|
+
.map((n, i) => ({ n, i }))
|
|
28
|
+
.sort((a, b) => a.n - b.n)
|
|
29
|
+
.map((x) => x.i),
|
|
24
30
|
);
|
|
25
31
|
}
|
|
32
|
+
export function valueAndSchema(
|
|
33
|
+
schemaOptions?: SchemaFieldGenOptions,
|
|
34
|
+
): Arbitrary<FieldAndValueChanged> {
|
|
35
|
+
return randomSchemaField(schemaOptions)
|
|
36
|
+
.chain((schema) =>
|
|
37
|
+
randomValueForField(schema).map((value) => ({
|
|
38
|
+
field: schema,
|
|
39
|
+
value,
|
|
40
|
+
})),
|
|
41
|
+
)
|
|
42
|
+
.chain(changedValue);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export function changedValue(
|
|
46
|
+
val: FieldAndValue,
|
|
47
|
+
): Arbitrary<FieldAndValueChanged> {
|
|
48
|
+
return changeValue(val.value, val.field, true).map((newValue) => ({
|
|
49
|
+
...val,
|
|
50
|
+
newValue,
|
|
51
|
+
}));
|
|
52
|
+
}
|
|
26
53
|
|
|
27
54
|
export function makeDataNode(fv: FieldAndValue): SchemaDataNode {
|
|
28
55
|
return makeSchemaDataNode(
|
|
@@ -122,7 +149,7 @@ function randomValueForField(
|
|
|
122
149
|
}
|
|
123
150
|
if (f.type === FieldType.String) return fc.string();
|
|
124
151
|
if (f.type === FieldType.Int) return fc.integer();
|
|
125
|
-
if (f.type === FieldType.Double) return fc.double();
|
|
152
|
+
if (f.type === FieldType.Double) return fc.double({ noNaN: true });
|
|
126
153
|
if (f.type === FieldType.Bool) return fc.boolean();
|
|
127
154
|
if (f.type === FieldType.Date)
|
|
128
155
|
return fc.date().map((x) => x.toISOString().substring(0, 10));
|
|
@@ -137,39 +164,57 @@ function randomValueForField(
|
|
|
137
164
|
),
|
|
138
165
|
);
|
|
139
166
|
}
|
|
140
|
-
return fc.constantFrom(null
|
|
167
|
+
return fc.constantFrom(null);
|
|
141
168
|
}) as (x: number) => Arbitrary<any>);
|
|
142
169
|
}
|
|
143
170
|
|
|
144
171
|
export function changeValue(
|
|
145
172
|
value: any,
|
|
146
173
|
field: SchemaField,
|
|
174
|
+
forceChange: boolean | undefined,
|
|
147
175
|
element?: boolean,
|
|
148
|
-
): any {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
return
|
|
156
|
-
(
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
176
|
+
): Arbitrary<any> {
|
|
177
|
+
return fc.boolean().chain((shouldChange) => {
|
|
178
|
+
if (forceChange === false || (!shouldChange && !forceChange))
|
|
179
|
+
return fc.constant(value);
|
|
180
|
+
if (field.collection && !element) {
|
|
181
|
+
if (!value || !value.length)
|
|
182
|
+
return changeValue(undefined, field, true, true).map((x) => [x]);
|
|
183
|
+
return (value as any[]).reduce(
|
|
184
|
+
(acc, x) =>
|
|
185
|
+
acc.chain((nx: any[]) =>
|
|
186
|
+
changeValue(x, field, undefined, true).map((v) => [...nx, v]),
|
|
187
|
+
),
|
|
188
|
+
fc.constant([] as any[]),
|
|
189
|
+
);
|
|
190
|
+
}
|
|
191
|
+
if (isCompoundField(field)) {
|
|
192
|
+
return fc.record(
|
|
193
|
+
Object.fromEntries(
|
|
194
|
+
field.children.map((x) => [
|
|
195
|
+
x.field,
|
|
196
|
+
changeValue(value?.[x.field], x, value == null ? true : undefined),
|
|
197
|
+
]),
|
|
198
|
+
),
|
|
160
199
|
);
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
200
|
+
}
|
|
201
|
+
return fc.constant(changePrim() as any);
|
|
202
|
+
function changePrim() {
|
|
203
|
+
switch (field.type) {
|
|
204
|
+
case FieldType.String:
|
|
205
|
+
case FieldType.Date:
|
|
206
|
+
case FieldType.DateTime:
|
|
207
|
+
case FieldType.Time:
|
|
208
|
+
return (value ?? "") + "x";
|
|
209
|
+
case FieldType.Int:
|
|
210
|
+
const v = value ?? 0;
|
|
211
|
+
return !v ? 1 : -v;
|
|
212
|
+
case FieldType.Double:
|
|
213
|
+
const dv = value ?? 0;
|
|
214
|
+
return !dv ? 1 : -dv;
|
|
215
|
+
case FieldType.Bool:
|
|
216
|
+
return !(value ?? false);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
});
|
|
175
220
|
}
|
package/test/play.ts
CHANGED
|
@@ -1,50 +1,54 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
changeValue,
|
|
3
|
+
FieldAndValue,
|
|
4
|
+
FieldAndValueChanged,
|
|
5
|
+
makeDataNode,
|
|
6
|
+
} from "./gen";
|
|
2
7
|
import { getDiffObject } from "../src";
|
|
8
|
+
import { updateElements } from "@react-typed-forms/core";
|
|
3
9
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
10
|
+
const testData = [
|
|
11
|
+
{
|
|
12
|
+
field: {
|
|
13
|
+
field: ")W",
|
|
14
|
+
type: "Compound",
|
|
15
|
+
collection: true,
|
|
16
|
+
notNullable: true,
|
|
17
|
+
children: [
|
|
18
|
+
{
|
|
19
|
+
field: "4N`rCgnDXm",
|
|
20
|
+
type: "DateTime",
|
|
21
|
+
collection: false,
|
|
22
|
+
notNullable: false,
|
|
23
|
+
children: null,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
value: [
|
|
28
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Z" },
|
|
29
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Z" },
|
|
30
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Z" },
|
|
31
|
+
],
|
|
32
|
+
newValue: [
|
|
33
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Zx" },
|
|
34
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Z" },
|
|
35
|
+
{ "4N`rCgnDXm": "1970-01-01T00:00:00.000Zz" },
|
|
19
36
|
],
|
|
20
|
-
},
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
add: false,
|
|
24
|
-
} as FieldAndValue;
|
|
37
|
+
} as FieldAndValueChanged,
|
|
38
|
+
[2, 0, 1],
|
|
39
|
+
] as [FieldAndValueChanged, number[]];
|
|
25
40
|
|
|
41
|
+
const [fv, indexes] = testData;
|
|
26
42
|
const dataNode = makeDataNode(fv);
|
|
27
43
|
const arrayControl = dataNode.control!;
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
const
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
if (i % 2 == 0) {
|
|
36
|
-
const nv = changeValue(newValue[fieldName], field);
|
|
37
|
-
newValue[fieldName] = nv;
|
|
38
|
-
result[fieldName] = nv;
|
|
39
|
-
} else {
|
|
40
|
-
delete result[fieldName];
|
|
41
|
-
}
|
|
44
|
+
|
|
45
|
+
const newValue = fv.newValue as any[];
|
|
46
|
+
updateElements(arrayControl.as<any[]>(), (x) => {
|
|
47
|
+
const sorted = indexes.map((ni, i) => {
|
|
48
|
+
const c = x[ni];
|
|
49
|
+
c.value = newValue[i];
|
|
50
|
+
return c;
|
|
42
51
|
});
|
|
43
|
-
|
|
44
|
-
if (!results) results = [];
|
|
45
|
-
results.push(result);
|
|
52
|
+
return sorted;
|
|
46
53
|
});
|
|
47
|
-
console.log(fv.value);
|
|
48
|
-
console.log(arrayControl.value);
|
|
49
|
-
console.log(results);
|
|
50
54
|
console.log(getDiffObject(dataNode));
|