@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.
Files changed (33) hide show
  1. package/coverage/clover.xml +867 -120
  2. package/coverage/coverage-final.json +16 -4
  3. package/coverage/lcov-report/index.html +28 -28
  4. package/coverage/lcov-report/src/controlBuilder.ts.html +889 -0
  5. package/coverage/lcov-report/src/controlDefinition.ts.html +1 -1
  6. package/coverage/lcov-report/src/controlRender.tsx.html +3532 -0
  7. package/coverage/lcov-report/src/createFormRenderer.tsx.html +721 -0
  8. package/coverage/lcov-report/src/defaultSchemaInterface.ts.html +658 -0
  9. package/coverage/lcov-report/src/dynamicHooks.ts.html +379 -0
  10. package/coverage/lcov-report/src/entityExpression.ts.html +199 -0
  11. package/coverage/lcov-report/src/hooks.tsx.html +1462 -0
  12. package/coverage/lcov-report/src/index.html +198 -18
  13. package/coverage/lcov-report/src/index.ts.html +127 -0
  14. package/coverage/lcov-report/src/renderers.tsx.html +679 -0
  15. package/coverage/lcov-report/src/schemaBuilder.ts.html +1039 -0
  16. package/coverage/lcov-report/src/schemaField.ts.html +35 -32
  17. package/coverage/lcov-report/src/schemaValidator.ts.html +181 -0
  18. package/coverage/lcov-report/src/util.ts.html +29 -131
  19. package/coverage/lcov-report/src/validators.ts.html +736 -0
  20. package/coverage/lcov-report/test/gen.ts.html +217 -82
  21. package/coverage/lcov-report/test/index.html +17 -17
  22. package/coverage/lcov.info +2091 -271
  23. package/jest.config.js +3 -2
  24. package/lib/index.cjs +1 -1
  25. package/lib/index.cjs.map +1 -1
  26. package/lib/index.js +1 -1
  27. package/lib/index.js.map +1 -1
  28. package/lib/util.d.ts +1 -1
  29. package/package.json +1 -1
  30. package/test/diff.test.ts +68 -88
  31. package/test/gen.ts +78 -33
  32. package/test/play.ts +45 -41
  33. 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, idField?: string | null): any;
246
+ export declare function getDiffObject(dataNode: SchemaDataNode, force?: boolean): any;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-typed-forms/schemas",
3
- "version": "14.0.4",
3
+ "version": "14.0.5",
4
4
  "description": "",
5
5
  "type": "module",
6
6
  "main": "lib/index.cjs",
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 { changeValue, makeDataNode, valueAndSchema } from "./gen";
3
+ import { makeDataNode, newIndexes, valueAndSchema } from "./gen";
4
+ import { getDiffObject, getTagParam, SchemaDataNode, SchemaTags } from "../src";
4
5
  import {
5
- getDiffObject,
6
- getTagParam,
7
- isCompoundNode,
8
- SchemaDataNode,
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) => changeValue(x, dataNode.schema.field));
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({ arrayChance: 0, forceCompound: true }),
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
- const result = { ...control.value };
45
- const newValue = { ...control.value };
46
- dataNode.schema.getChildNodes().forEach((child, i) => {
47
- const field = child.field;
48
- const fieldName = field.field;
49
- if (i % 2 == 0) {
50
- const nv = changeValue(newValue[fieldName], field);
51
- newValue[fieldName] = nv;
52
- result[fieldName] = nv;
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
- let results: any = undefined;
78
- arrayControl.as<any[]>().elements.forEach((control) => {
79
- const { newValue, result } = editCompound(control.value, dataNode);
80
- control.value = newValue;
81
- if (!results) results = [];
82
- results.push(result);
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(results);
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
- }).chain((fv) => {
99
- const len = ((fv.value as any[]) ?? []).length;
100
- return fc
101
- .record({
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
- let results: any = undefined;
111
- // if (fv.add || fv.index >= arrayControl.elements.length)
112
- // addElement(
113
- // arrayControl,
114
- // changeValue(undefined, dataNode.schema.field, true),
115
- // );
116
- arrayControl.as<any[]>().elements.forEach((control, i) => {
117
- let change = undefined;
118
- if (i % 2 == 0) {
119
- if (isCompoundNode(dataNode.schema)) {
120
- const { newValue, result } = editCompound(
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 editCompound(
145
- existing: Record<string, any>,
133
+ function objectDiff(
146
134
  dataNode: SchemaDataNode,
147
- ): { newValue: any; result: any } {
148
- const idField = getTagParam(dataNode.schema.field, SchemaTags.IdField);
149
- const result = { ...existing };
150
- const newValue = { ...existing };
151
- dataNode.schema.getChildNodes().forEach((child, i) => {
152
- const field = child.field;
153
- const fieldName = field.field;
154
- const shouldChange = i % 2 == 0;
155
- if (shouldChange || fieldName == idField) {
156
- let nv = newValue[fieldName];
157
- if (shouldChange) nv = changeValue(nv, field);
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 function valueAndSchema(
20
- options?: SchemaFieldGenOptions,
21
- ): Arbitrary<FieldAndValue> {
22
- return randomSchemaField(options).chain((schema) =>
23
- randomValueForField(schema).map((value) => ({ field: schema, value })),
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, undefined);
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
- if (field.collection && !element) {
150
- return [...(value ?? []), changeValue(undefined, field, true)];
151
- }
152
- switch (field.type) {
153
- case FieldType.Compound:
154
- const objValue = value ?? {};
155
- return Object.fromEntries(
156
- (field as CompoundField).children.map((x) => [
157
- x.field,
158
- changeValue(objValue[x.field], x),
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
- case FieldType.String:
162
- case FieldType.Date:
163
- case FieldType.DateTime:
164
- case FieldType.Time:
165
- return (value ?? "") + "x";
166
- case FieldType.Int:
167
- const v = value ?? 0;
168
- return !v ? 1 : -v;
169
- case FieldType.Double:
170
- const dv = value ?? 0;
171
- return !dv ? 1 : -dv;
172
- case FieldType.Bool:
173
- return !(value ?? false);
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 { changeValue, FieldAndValue, makeDataNode } from "./gen";
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
- const fv = {
6
- field: {
7
- field: "",
8
- type: "Compound",
9
- collection: true,
10
- notNullable: false,
11
- children: [
12
- {
13
- field: "",
14
- type: "String",
15
- collection: false,
16
- notNullable: false,
17
- children: null,
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
- value: [{ "": "" }],
22
- index: 0,
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
- let results: any = undefined;
29
- arrayControl.as<any[]>().elements.forEach((control) => {
30
- const result = { ...control.value };
31
- const newValue = { ...control.value };
32
- dataNode.schema.getChildNodes().forEach((child, i) => {
33
- const field = child.field;
34
- const fieldName = field.field;
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
- control.value = newValue;
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));
package/tsconfig.json CHANGED
@@ -13,7 +13,7 @@
13
13
  "moduleResolution": "node",
14
14
  "resolveJsonModule": true,
15
15
  "isolatedModules": true,
16
- "jsx": "preserve",
16
+ "jsx": "react",
17
17
  "outDir": "lib"
18
18
  },
19
19
  "include": ["src/**/*.ts", "src/**/*.tsx"],