@strictly/react-form 0.0.1 → 0.0.3
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/.out/core/mobx/field_adapter.d.ts +7 -6
- package/.out/core/mobx/field_adapter_builder.d.ts +12 -13
- package/.out/core/mobx/field_adapter_builder.js +8 -12
- package/.out/core/mobx/field_adapters_of_values.d.ts +4 -0
- package/.out/core/mobx/flattened_adapters_of_fields.d.ts +2 -2
- package/.out/core/mobx/flattened_list_types_of_type.d.ts +8 -0
- package/.out/core/mobx/form_fields_of_field_adapters.d.ts +8 -0
- package/.out/core/mobx/form_presenter.d.ts +21 -24
- package/.out/core/mobx/form_presenter.js +64 -69
- package/.out/core/mobx/merge_field_adapters_with_two_way_converter.d.ts +13 -0
- package/.out/core/mobx/merge_field_adapters_with_two_way_converter.js +11 -0
- package/.out/core/mobx/merge_field_adapters_with_validators.d.ts +11 -0
- package/.out/core/mobx/merge_field_adapters_with_validators.js +45 -0
- package/.out/core/mobx/specs/fixtures.d.ts +7 -0
- package/.out/core/mobx/specs/fixtures.js +20 -0
- package/.out/core/mobx/specs/flattened_adapters_of_fields.tests.js +5 -2
- package/.out/core/mobx/specs/{flattened_list_type_defs_of.tests.js → flattened_list_types_of_types.tests.js} +7 -7
- package/.out/core/mobx/specs/form_presenter.tests.js +162 -60
- package/.out/core/mobx/specs/merge_field_adapters_with_two_way_converter.js +89 -0
- package/.out/core/mobx/specs/merge_field_adapters_with_validators.tests.js +172 -0
- package/.out/core/mobx/types.d.ts +2 -2
- package/.out/field_converters/chain_field_converter.d.ts +3 -3
- package/.out/field_converters/chain_field_converter.js +17 -12
- package/.out/field_converters/identity_converter.d.ts +3 -3
- package/.out/field_converters/identity_converter.js +10 -6
- package/.out/field_converters/integer_to_string_converter.d.ts +5 -4
- package/.out/field_converters/integer_to_string_converter.js +13 -6
- package/.out/field_converters/list_converter.d.ts +2 -2
- package/.out/field_converters/list_converter.js +6 -1
- package/.out/field_converters/maybe_identity_converter.d.ts +3 -3
- package/.out/field_converters/maybe_identity_converter.js +3 -1
- package/.out/field_converters/nullable_to_boolean_converter.d.ts +9 -8
- package/.out/field_converters/nullable_to_boolean_converter.js +13 -7
- package/.out/field_converters/select_value_type_converter.d.ts +20 -15
- package/.out/field_converters/select_value_type_converter.js +29 -14
- package/.out/field_converters/specs/chain_field_converter.tests.d.ts +1 -0
- package/.out/field_converters/specs/chain_field_converter.tests.js +251 -0
- package/.out/field_converters/trimming_string_converter.d.ts +3 -3
- package/.out/field_converters/trimming_string_converter.js +7 -3
- package/.out/field_converters/validating_converter.d.ts +3 -3
- package/.out/field_converters/validating_converter.js +7 -5
- package/.out/index.d.ts +9 -2
- package/.out/index.js +9 -2
- package/.out/mantine/create_checkbox.d.ts +2 -3
- package/.out/mantine/create_checkbox.js +6 -5
- package/.out/mantine/create_pill.js +2 -2
- package/.out/mantine/create_radio.js +1 -1
- package/.out/mantine/create_radio_group.d.ts +2 -3
- package/.out/mantine/create_radio_group.js +4 -3
- package/.out/mantine/create_text_input.d.ts +2 -3
- package/.out/mantine/create_text_input.js +6 -5
- package/.out/mantine/create_value_input.d.ts +2 -3
- package/.out/mantine/create_value_input.js +6 -5
- package/.out/mantine/error_renderer.d.ts +6 -0
- package/.out/mantine/error_renderer.js +5 -0
- package/.out/mantine/hooks.d.ts +9 -13
- package/.out/mantine/hooks.js +10 -15
- package/.out/mantine/specs/checkbox_hooks.stories.d.ts +7 -2
- package/.out/mantine/specs/checkbox_hooks.stories.js +33 -6
- package/.out/mantine/specs/list_hooks.stories.js +2 -2
- package/.out/mantine/specs/radio_group_hooks.stories.d.ts +7 -2
- package/.out/mantine/specs/radio_group_hooks.stories.js +33 -6
- package/.out/mantine/specs/select_hooks.stories.d.ts +8 -2
- package/.out/mantine/specs/select_hooks.stories.js +45 -8
- package/.out/mantine/specs/text_input_hooks.stories.d.ts +5 -1
- package/.out/mantine/specs/text_input_hooks.stories.js +23 -8
- package/.out/mantine/specs/value_input_hooks.stories.d.ts +7 -2
- package/.out/mantine/specs/value_input_hooks.stories.js +49 -15
- package/.out/mantine/types.d.ts +4 -1
- package/.out/tsconfig.tsbuildinfo +1 -1
- package/.out/types/error_of_field.d.ts +2 -0
- package/.out/types/error_of_field.js +1 -0
- package/.out/types/field.d.ts +1 -1
- package/.out/types/field_converters.d.ts +17 -10
- package/.out/types/field_converters.js +5 -5
- package/.out/types/flattened_validators_of_fields.d.ts +8 -0
- package/.out/types/flattened_validators_of_fields.js +1 -0
- package/.out/types/merge_validators.d.ts +7 -0
- package/.out/types/merge_validators.js +38 -0
- package/.out/types/specs/flattened_validators_of_fields.tests.d.ts +1 -0
- package/.out/types/specs/flattened_validators_of_fields.tests.js +16 -0
- package/.out/types/specs/merge_validators.tests.d.ts +1 -0
- package/.out/types/specs/merge_validators.tests.js +192 -0
- package/.out/util/partial.d.ts +11 -5
- package/.out/util/partial.js +55 -15
- package/.turbo/turbo-build.log +9 -9
- package/.turbo/turbo-check-types.log +1 -1
- package/.turbo/turbo-release$colon$exports.log +1 -1
- package/README.md +5 -1
- package/core/mobx/field_adapter.ts +15 -7
- package/core/mobx/field_adapter_builder.ts +39 -75
- package/core/mobx/field_adapters_of_values.ts +17 -0
- package/core/mobx/flattened_adapters_of_fields.ts +3 -3
- package/core/mobx/flattened_list_types_of_type.ts +17 -0
- package/core/mobx/form_fields_of_field_adapters.ts +16 -0
- package/core/mobx/form_presenter.ts +117 -104
- package/core/mobx/merge_field_adapters_with_two_way_converter.ts +68 -0
- package/core/mobx/merge_field_adapters_with_validators.ts +99 -0
- package/core/mobx/specs/fixtures.ts +73 -0
- package/core/mobx/specs/flattened_adapters_of_fields.tests.ts +23 -2
- package/core/mobx/specs/flattened_list_types_of_types.tests.ts +35 -0
- package/core/mobx/specs/form_presenter.tests.ts +248 -124
- package/core/mobx/specs/merge_field_adapters_with_two_way_converter.ts +140 -0
- package/core/mobx/specs/merge_field_adapters_with_validators.tests.ts +259 -0
- package/core/mobx/types.ts +3 -3
- package/dist/index.cjs +527 -10412
- package/dist/index.d.cts +153 -111
- package/dist/index.d.ts +153 -111
- package/dist/index.js +527 -10420
- package/field_converters/chain_field_converter.ts +37 -23
- package/field_converters/identity_converter.ts +14 -10
- package/field_converters/integer_to_string_converter.ts +15 -9
- package/field_converters/list_converter.ts +8 -3
- package/field_converters/maybe_identity_converter.ts +7 -4
- package/field_converters/nullable_to_boolean_converter.ts +23 -16
- package/field_converters/select_value_type_converter.ts +86 -26
- package/field_converters/specs/chain_field_converter.tests.ts +302 -0
- package/field_converters/trimming_string_converter.ts +11 -6
- package/field_converters/validating_converter.ts +21 -11
- package/index.ts +9 -2
- package/mantine/create_checkbox.tsx +15 -8
- package/mantine/create_list.tsx +1 -4
- package/mantine/create_pill.tsx +2 -2
- package/mantine/create_radio.tsx +1 -1
- package/mantine/create_radio_group.tsx +8 -6
- package/mantine/create_text_input.tsx +20 -8
- package/mantine/create_value_input.tsx +17 -8
- package/mantine/error_renderer.ts +15 -0
- package/mantine/hooks.tsx +25 -51
- package/mantine/specs/__snapshots__/checkbox_hooks.tests.tsx.snap +126 -0
- package/mantine/specs/__snapshots__/radio_group_hooks.tests.tsx.snap +356 -0
- package/mantine/specs/__snapshots__/select_hooks.tests.tsx.snap +208 -12
- package/mantine/specs/__snapshots__/text_input_hooks.tests.tsx.snap +45 -0
- package/mantine/specs/__snapshots__/value_input_hooks.tests.tsx.snap +194 -8
- package/mantine/specs/checkbox_hooks.stories.tsx +47 -7
- package/mantine/specs/list_hooks.stories.tsx +2 -2
- package/mantine/specs/radio_group_hooks.stories.tsx +47 -7
- package/mantine/specs/select_hooks.stories.tsx +55 -8
- package/mantine/specs/text_input_hooks.stories.tsx +32 -7
- package/mantine/specs/value_input_hooks.stories.tsx +57 -16
- package/mantine/types.ts +5 -1
- package/package.json +20 -7
- package/tsconfig.json +1 -0
- package/types/error_of_field.ts +3 -0
- package/types/field.ts +1 -1
- package/types/field_converters.ts +21 -10
- package/types/flattened_validators_of_fields.ts +34 -0
- package/types/merge_validators.ts +80 -0
- package/types/specs/error_type_of_field.tests.ts +2 -2
- package/types/specs/flattened_validators_of_fields.tests.ts +93 -0
- package/types/specs/merge_validators.tests.ts +267 -0
- package/util/partial.tsx +200 -16
- package/.out/core/mobx/flattened_list_type_defs_of.d.ts +0 -8
- package/.out/field_validators/minimum_string_length_field_validator.d.ts +0 -2
- package/.out/field_validators/minimum_string_length_field_validator.js +0 -8
- package/.out/types/error_type_of_field.d.ts +0 -2
- package/.out/types/field_validator.d.ts +0 -3
- package/.out/types/flattened_form_fields_of.d.ts +0 -9
- package/.out/types/specs/flattened_form_fields_of.tests.js +0 -13
- package/core/mobx/flattened_list_type_defs_of.ts +0 -17
- package/core/mobx/specs/flattened_list_type_defs_of.tests.ts +0 -35
- package/field_validators/minimum_string_length_field_validator.ts +0 -13
- package/mantine/specs/__snapshots__/check_box_hooks.tests.tsx.snap +0 -227
- package/types/error_type_of_field.ts +0 -3
- package/types/field_validator.ts +0 -7
- package/types/flattened_form_fields_of.ts +0 -16
- package/types/specs/flattened_form_fields_of.tests.ts +0 -43
- /package/.out/core/mobx/{flattened_list_type_defs_of.js → field_adapters_of_values.js} +0 -0
- /package/.out/core/mobx/{specs/flattened_list_type_defs_of.tests.d.ts → flattened_list_types_of_type.js} +0 -0
- /package/.out/{types/error_type_of_field.js → core/mobx/form_fields_of_field_adapters.js} +0 -0
- /package/.out/{types/field_validator.js → core/mobx/specs/flattened_list_types_of_types.tests.d.ts} +0 -0
- /package/.out/{types/flattened_form_fields_of.js → core/mobx/specs/merge_field_adapters_with_two_way_converter.d.ts} +0 -0
- /package/.out/{types/specs/flattened_form_fields_of.tests.d.ts → core/mobx/specs/merge_field_adapters_with_validators.tests.d.ts} +0 -0
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { expectDefinedAndReturn } from '@strictly/base'
|
|
2
2
|
import {
|
|
3
3
|
booleanType,
|
|
4
|
-
type
|
|
4
|
+
type FlattenedValuesOfType,
|
|
5
5
|
list,
|
|
6
6
|
nullType,
|
|
7
7
|
numberType,
|
|
@@ -9,8 +9,8 @@ import {
|
|
|
9
9
|
record,
|
|
10
10
|
stringType,
|
|
11
11
|
union,
|
|
12
|
-
type
|
|
13
|
-
type
|
|
12
|
+
type ValueOfType,
|
|
13
|
+
type ValueToTypePathsOfType,
|
|
14
14
|
} from '@strictly/define'
|
|
15
15
|
import { type FieldAdapter } from 'core/mobx/field_adapter'
|
|
16
16
|
import {
|
|
@@ -25,56 +25,38 @@ import {
|
|
|
25
25
|
} from 'core/mobx/form_presenter'
|
|
26
26
|
import { IntegerToStringConverter } from 'field_converters/integer_to_string_converter'
|
|
27
27
|
import { NullableToBooleanConverter } from 'field_converters/nullable_to_boolean_converter'
|
|
28
|
+
import { SelectDiscriminatedUnionConverter } from 'field_converters/select_value_type_converter'
|
|
28
29
|
import { prototypingFieldValueFactory } from 'field_value_factories/prototyping_field_value_factory'
|
|
29
30
|
import { type Simplify } from 'type-fest'
|
|
30
31
|
import { type Field } from 'types/field'
|
|
31
32
|
import {
|
|
32
|
-
|
|
33
|
+
UnreliableFieldConversionType,
|
|
33
34
|
} from 'types/field_converters'
|
|
34
|
-
import { type Mocked } from 'vitest'
|
|
35
35
|
import {
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
} from '
|
|
36
|
+
createMockedAdapter,
|
|
37
|
+
resetMockAdapter,
|
|
38
|
+
} from './fixtures'
|
|
39
39
|
|
|
40
40
|
const IS_NAN_ERROR = 1
|
|
41
41
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
convert,
|
|
49
|
-
revert,
|
|
50
|
-
create,
|
|
51
|
-
}: FieldAdapter<From, To, E, ValuePath>): Mocked<
|
|
52
|
-
Required<FieldAdapter<From, To, E, ValuePath>>
|
|
53
|
-
> {
|
|
54
|
-
const mockedAdapter = mock<Required<FieldAdapter<From, To, E, ValuePath>>>()
|
|
55
|
-
if (revert) {
|
|
56
|
-
mockedAdapter.revert?.mockImplementation(revert)
|
|
57
|
-
}
|
|
58
|
-
mockedAdapter.convert.mockImplementation(convert)
|
|
59
|
-
mockedAdapter.create.mockImplementation(create)
|
|
60
|
-
|
|
61
|
-
return mockedAdapter
|
|
62
|
-
}
|
|
42
|
+
const originalIntegerToStringAdapter = adapterFromTwoWayConverter(
|
|
43
|
+
new IntegerToStringConverter(IS_NAN_ERROR),
|
|
44
|
+
prototypingFieldValueFactory(0),
|
|
45
|
+
)
|
|
46
|
+
|
|
47
|
+
const originalBooleanToBooleanAdapter = identityAdapter(false)
|
|
63
48
|
|
|
64
49
|
describe('all', function () {
|
|
65
50
|
const integerToStringAdapter = createMockedAdapter(
|
|
66
|
-
|
|
67
|
-
new IntegerToStringConverter(IS_NAN_ERROR),
|
|
68
|
-
prototypingFieldValueFactory(0),
|
|
69
|
-
),
|
|
51
|
+
originalIntegerToStringAdapter,
|
|
70
52
|
)
|
|
71
53
|
const booleanToBooleanAdapter = createMockedAdapter(
|
|
72
|
-
|
|
54
|
+
originalBooleanToBooleanAdapter,
|
|
73
55
|
)
|
|
74
56
|
|
|
75
57
|
beforeEach(function () {
|
|
76
|
-
|
|
77
|
-
|
|
58
|
+
resetMockAdapter(originalIntegerToStringAdapter, integerToStringAdapter)
|
|
59
|
+
resetMockAdapter(originalBooleanToBooleanAdapter, booleanToBooleanAdapter)
|
|
78
60
|
})
|
|
79
61
|
|
|
80
62
|
describe('FlattenedTypePathsToConvertersOf', function () {
|
|
@@ -99,14 +81,14 @@ describe('all', function () {
|
|
|
99
81
|
const typeDef = record<typeof numberType, 'a' | 'b'>(numberType)
|
|
100
82
|
type T = Simplify<
|
|
101
83
|
FlattenedTypePathsToAdaptersOf<
|
|
102
|
-
|
|
103
|
-
|
|
84
|
+
FlattenedValuesOfType<typeof typeDef>,
|
|
85
|
+
ValueOfType<typeof typeDef>
|
|
104
86
|
>
|
|
105
87
|
>
|
|
106
88
|
let t: Partial<{
|
|
107
|
-
readonly $: ConvenientFieldAdapter<Readonly<Record<'a' | 'b', number>>,
|
|
108
|
-
readonly ['$.a']: ConvenientFieldAdapter<number,
|
|
109
|
-
readonly ['$.b']: ConvenientFieldAdapter<number,
|
|
89
|
+
readonly $: ConvenientFieldAdapter<Readonly<Record<'a' | 'b', number>>, ValueOfType<typeof typeDef>>,
|
|
90
|
+
readonly ['$.a']: ConvenientFieldAdapter<number, ValueOfType<typeof typeDef>>,
|
|
91
|
+
readonly ['$.b']: ConvenientFieldAdapter<number, ValueOfType<typeof typeDef>>,
|
|
110
92
|
}>
|
|
111
93
|
|
|
112
94
|
it('equals expected type', function () {
|
|
@@ -116,16 +98,16 @@ describe('all', function () {
|
|
|
116
98
|
|
|
117
99
|
describe('object', function () {
|
|
118
100
|
const typeDef = object()
|
|
119
|
-
.
|
|
120
|
-
.
|
|
101
|
+
.field('x', stringType)
|
|
102
|
+
.field('y', booleanType)
|
|
121
103
|
type T = FlattenedTypePathsToAdaptersOf<
|
|
122
|
-
|
|
123
|
-
|
|
104
|
+
FlattenedValuesOfType<typeof typeDef>,
|
|
105
|
+
ValueOfType<typeof typeDef>
|
|
124
106
|
>
|
|
125
107
|
let t: Partial<{
|
|
126
|
-
readonly $: ConvenientFieldAdapter<{ readonly x: string, readonly y: boolean },
|
|
127
|
-
readonly ['$.x']: ConvenientFieldAdapter<string,
|
|
128
|
-
readonly ['$.y']: ConvenientFieldAdapter<boolean,
|
|
108
|
+
readonly $: ConvenientFieldAdapter<{ readonly x: string, readonly y: boolean }, ValueOfType<typeof typeDef>>,
|
|
109
|
+
readonly ['$.x']: ConvenientFieldAdapter<string, ValueOfType<typeof typeDef>>,
|
|
110
|
+
readonly ['$.y']: ConvenientFieldAdapter<boolean, ValueOfType<typeof typeDef>>,
|
|
129
111
|
}>
|
|
130
112
|
it('equals expected type', function () {
|
|
131
113
|
expectTypeOf(t).toEqualTypeOf<T>()
|
|
@@ -177,57 +159,100 @@ describe('all', function () {
|
|
|
177
159
|
|
|
178
160
|
describe('FormModel', function () {
|
|
179
161
|
describe('literal', function () {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
ValueToTypePathsOf<typeof typeDef>,
|
|
188
|
-
typeof adapters
|
|
189
|
-
>
|
|
190
|
-
beforeEach(function () {
|
|
191
|
-
originalValue = 5
|
|
192
|
-
model = new FormModel<
|
|
162
|
+
describe('optional', function () {
|
|
163
|
+
const typeDef = numberType
|
|
164
|
+
const adapters = {
|
|
165
|
+
$: integerToStringAdapter,
|
|
166
|
+
} as const
|
|
167
|
+
let originalValue: ValueOfType<typeof typeDef>
|
|
168
|
+
let model: FormModel<
|
|
193
169
|
typeof typeDef,
|
|
194
|
-
|
|
170
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
195
171
|
typeof adapters
|
|
196
|
-
>
|
|
197
|
-
|
|
198
|
-
originalValue
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
172
|
+
>
|
|
173
|
+
beforeEach(function () {
|
|
174
|
+
originalValue = 5
|
|
175
|
+
model = new FormModel<
|
|
176
|
+
typeof typeDef,
|
|
177
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
178
|
+
typeof adapters
|
|
179
|
+
>(
|
|
180
|
+
typeDef,
|
|
181
|
+
originalValue,
|
|
182
|
+
adapters,
|
|
183
|
+
)
|
|
184
|
+
})
|
|
202
185
|
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
186
|
+
describe('accessors', function () {
|
|
187
|
+
it('gets the expected value', function () {
|
|
188
|
+
const accessor = expectDefinedAndReturn(model.accessors.$)
|
|
189
|
+
expect(accessor.value).toEqual(originalValue)
|
|
190
|
+
})
|
|
191
|
+
|
|
192
|
+
it('sets the underlying value', function () {
|
|
193
|
+
const newValue = 1
|
|
194
|
+
const accessor = expectDefinedAndReturn(model.accessors.$)
|
|
195
|
+
accessor.set(newValue)
|
|
196
|
+
expect(model.value).toEqual(newValue)
|
|
197
|
+
})
|
|
207
198
|
})
|
|
208
199
|
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
200
|
+
describe('fields', function () {
|
|
201
|
+
it('equals expected value', function () {
|
|
202
|
+
expect(model.fields).toEqual(
|
|
203
|
+
expect.objectContaining({
|
|
204
|
+
$: expect.objectContaining({
|
|
205
|
+
value: '5',
|
|
206
|
+
}),
|
|
207
|
+
}),
|
|
208
|
+
)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('has the expected keys', function () {
|
|
212
|
+
expect(Object.keys(model.fields)).toEqual(['$'])
|
|
213
|
+
})
|
|
214
214
|
})
|
|
215
215
|
})
|
|
216
216
|
|
|
217
|
-
describe('
|
|
218
|
-
|
|
217
|
+
describe('required', function () {
|
|
218
|
+
const typeDef = numberType
|
|
219
|
+
const adapters = {
|
|
220
|
+
$: integerToStringAdapter,
|
|
221
|
+
} as const
|
|
222
|
+
let originalValue: ValueOfType<typeof typeDef>
|
|
223
|
+
let model: FormModel<
|
|
224
|
+
typeof typeDef,
|
|
225
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
226
|
+
typeof adapters
|
|
227
|
+
>
|
|
228
|
+
beforeEach(function () {
|
|
229
|
+
integerToStringAdapter.convert.mockReturnValue({
|
|
230
|
+
value: 'x',
|
|
231
|
+
required: true,
|
|
232
|
+
readonly: false,
|
|
233
|
+
})
|
|
234
|
+
originalValue = 5
|
|
235
|
+
model = new FormModel<
|
|
236
|
+
typeof typeDef,
|
|
237
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
238
|
+
typeof adapters
|
|
239
|
+
>(
|
|
240
|
+
typeDef,
|
|
241
|
+
originalValue,
|
|
242
|
+
adapters,
|
|
243
|
+
)
|
|
244
|
+
})
|
|
245
|
+
|
|
246
|
+
it('reports required status', function () {
|
|
219
247
|
expect(model.fields).toEqual(
|
|
220
248
|
expect.objectContaining({
|
|
221
249
|
$: expect.objectContaining({
|
|
222
|
-
value: '
|
|
250
|
+
value: 'x',
|
|
251
|
+
required: true,
|
|
223
252
|
}),
|
|
224
253
|
}),
|
|
225
254
|
)
|
|
226
255
|
})
|
|
227
|
-
|
|
228
|
-
it('has the expected keys', function () {
|
|
229
|
-
expect(Object.keys(model.fields)).toEqual(['$'])
|
|
230
|
-
})
|
|
231
256
|
})
|
|
232
257
|
})
|
|
233
258
|
|
|
@@ -236,10 +261,10 @@ describe('all', function () {
|
|
|
236
261
|
const adapters = {
|
|
237
262
|
'$.*': integerToStringAdapter,
|
|
238
263
|
} as const
|
|
239
|
-
let value:
|
|
264
|
+
let value: ValueOfType<typeof typeDef>
|
|
240
265
|
let model: FormModel<
|
|
241
266
|
typeof typeDef,
|
|
242
|
-
|
|
267
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
243
268
|
typeof adapters
|
|
244
269
|
>
|
|
245
270
|
beforeEach(function () {
|
|
@@ -250,7 +275,7 @@ describe('all', function () {
|
|
|
250
275
|
]
|
|
251
276
|
model = new FormModel<
|
|
252
277
|
typeof typeDef,
|
|
253
|
-
|
|
278
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
254
279
|
typeof adapters
|
|
255
280
|
>(
|
|
256
281
|
typeDef,
|
|
@@ -288,6 +313,25 @@ describe('all', function () {
|
|
|
288
313
|
])
|
|
289
314
|
})
|
|
290
315
|
})
|
|
316
|
+
|
|
317
|
+
describe('fields', function () {
|
|
318
|
+
it('equals the expected value', function () {
|
|
319
|
+
expect(model.fields).toEqual(expect.objectContaining({
|
|
320
|
+
'$.0': expect.objectContaining({
|
|
321
|
+
value: '1',
|
|
322
|
+
required: false,
|
|
323
|
+
}),
|
|
324
|
+
'$.1': expect.objectContaining({
|
|
325
|
+
value: '4',
|
|
326
|
+
required: false,
|
|
327
|
+
}),
|
|
328
|
+
'$.2': expect.objectContaining({
|
|
329
|
+
value: '17',
|
|
330
|
+
required: false,
|
|
331
|
+
}),
|
|
332
|
+
}))
|
|
333
|
+
})
|
|
334
|
+
})
|
|
291
335
|
})
|
|
292
336
|
|
|
293
337
|
describe('record', function () {
|
|
@@ -296,10 +340,10 @@ describe('all', function () {
|
|
|
296
340
|
'$.*': integerToStringAdapter,
|
|
297
341
|
// '$.*': booleanToBooleanConverter,
|
|
298
342
|
} as const
|
|
299
|
-
let value:
|
|
343
|
+
let value: ValueOfType<typeof typeDef>
|
|
300
344
|
let model: FormModel<
|
|
301
345
|
typeof typeDef,
|
|
302
|
-
|
|
346
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
303
347
|
typeof converters
|
|
304
348
|
>
|
|
305
349
|
beforeEach(function () {
|
|
@@ -309,7 +353,7 @@ describe('all', function () {
|
|
|
309
353
|
}
|
|
310
354
|
model = new FormModel<
|
|
311
355
|
typeof typeDef,
|
|
312
|
-
|
|
356
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
313
357
|
typeof converters
|
|
314
358
|
>(
|
|
315
359
|
typeDef,
|
|
@@ -360,16 +404,16 @@ describe('all', function () {
|
|
|
360
404
|
|
|
361
405
|
describe('object', function () {
|
|
362
406
|
const typeDef = object()
|
|
363
|
-
.
|
|
364
|
-
.
|
|
407
|
+
.field('a', numberType)
|
|
408
|
+
.field('b', booleanType)
|
|
365
409
|
const converters = {
|
|
366
410
|
'$.a': integerToStringAdapter,
|
|
367
411
|
'$.b': booleanToBooleanAdapter,
|
|
368
412
|
} as const
|
|
369
|
-
let value:
|
|
413
|
+
let value: ValueOfType<typeof typeDef>
|
|
370
414
|
let model: FormModel<
|
|
371
415
|
typeof typeDef,
|
|
372
|
-
|
|
416
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
373
417
|
typeof converters
|
|
374
418
|
>
|
|
375
419
|
beforeEach(function () {
|
|
@@ -379,7 +423,7 @@ describe('all', function () {
|
|
|
379
423
|
}
|
|
380
424
|
model = new FormModel<
|
|
381
425
|
typeof typeDef,
|
|
382
|
-
|
|
426
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
383
427
|
typeof converters
|
|
384
428
|
>(
|
|
385
429
|
typeDef,
|
|
@@ -437,16 +481,16 @@ describe('all', function () {
|
|
|
437
481
|
} as const
|
|
438
482
|
const presenter = new FormPresenter<
|
|
439
483
|
typeof typeDef,
|
|
440
|
-
|
|
484
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
441
485
|
typeof adapters
|
|
442
486
|
>(
|
|
443
487
|
typeDef,
|
|
444
488
|
adapters,
|
|
445
489
|
)
|
|
446
|
-
const originalValue:
|
|
490
|
+
const originalValue: ValueOfType<typeof typeDef> = 2
|
|
447
491
|
let model: FormModel<
|
|
448
492
|
typeof typeDef,
|
|
449
|
-
|
|
493
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
450
494
|
typeof adapters
|
|
451
495
|
>
|
|
452
496
|
beforeEach(function () {
|
|
@@ -467,7 +511,6 @@ describe('all', function () {
|
|
|
467
511
|
expect(model.fields).toEqual(expect.objectContaining({
|
|
468
512
|
$: expect.objectContaining({
|
|
469
513
|
value: '1',
|
|
470
|
-
// eslint-disable-next-line no-undefined
|
|
471
514
|
error: undefined,
|
|
472
515
|
}),
|
|
473
516
|
}))
|
|
@@ -499,7 +542,7 @@ describe('all', function () {
|
|
|
499
542
|
const errorCode = 65
|
|
500
543
|
beforeEach(function () {
|
|
501
544
|
integerToStringAdapter.revert?.mockReturnValueOnce({
|
|
502
|
-
type:
|
|
545
|
+
type: UnreliableFieldConversionType.Failure,
|
|
503
546
|
error: errorCode,
|
|
504
547
|
value: [newValue],
|
|
505
548
|
})
|
|
@@ -515,7 +558,7 @@ describe('all', function () {
|
|
|
515
558
|
$: expect.objectContaining({
|
|
516
559
|
value: '-1',
|
|
517
560
|
error: errorCode,
|
|
518
|
-
|
|
561
|
+
readonly: false,
|
|
519
562
|
}),
|
|
520
563
|
})
|
|
521
564
|
})
|
|
@@ -545,7 +588,6 @@ describe('all', function () {
|
|
|
545
588
|
expect(model.fields).toEqual(expect.objectContaining({
|
|
546
589
|
$: expect.objectContaining({
|
|
547
590
|
value: newValue,
|
|
548
|
-
// eslint-disable-next-line no-undefined
|
|
549
591
|
error: undefined,
|
|
550
592
|
}),
|
|
551
593
|
}))
|
|
@@ -560,16 +602,16 @@ describe('all', function () {
|
|
|
560
602
|
} as const
|
|
561
603
|
const presenter = new FormPresenter<
|
|
562
604
|
typeof typeDef,
|
|
563
|
-
|
|
605
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
564
606
|
typeof converters
|
|
565
607
|
>(
|
|
566
608
|
typeDef,
|
|
567
609
|
converters,
|
|
568
610
|
)
|
|
569
|
-
let originalValue:
|
|
611
|
+
let originalValue: ValueOfType<typeof typeDef>
|
|
570
612
|
let model: FormModel<
|
|
571
613
|
typeof typeDef,
|
|
572
|
-
|
|
614
|
+
ValueToTypePathsOfType<typeof typeDef>,
|
|
573
615
|
typeof converters
|
|
574
616
|
>
|
|
575
617
|
beforeEach(function () {
|
|
@@ -599,7 +641,6 @@ describe('all', function () {
|
|
|
599
641
|
expect(model.fields).toEqual(expect.objectContaining({
|
|
600
642
|
'$.0': expect.objectContaining({
|
|
601
643
|
value: '100',
|
|
602
|
-
// eslint-disable-next-line no-undefined
|
|
603
644
|
error: undefined,
|
|
604
645
|
}),
|
|
605
646
|
}))
|
|
@@ -642,7 +683,6 @@ describe('all', function () {
|
|
|
642
683
|
expect(model.fields).toEqual(expect.objectContaining({
|
|
643
684
|
'$.0': expect.objectContaining({
|
|
644
685
|
value: newValue,
|
|
645
|
-
// eslint-disable-next-line no-undefined
|
|
646
686
|
error: undefined,
|
|
647
687
|
}),
|
|
648
688
|
}))
|
|
@@ -665,7 +705,6 @@ describe('all', function () {
|
|
|
665
705
|
}),
|
|
666
706
|
'$.1': expect.objectContaining({
|
|
667
707
|
value: '2',
|
|
668
|
-
// eslint-disable-next-line no-undefined
|
|
669
708
|
error: undefined,
|
|
670
709
|
}),
|
|
671
710
|
'$.2': expect.objectContaining({
|
|
@@ -691,7 +730,7 @@ describe('all', function () {
|
|
|
691
730
|
integerToStringAdapter.revert.mockImplementationOnce(function (_value, _path, context) {
|
|
692
731
|
contextCopy = [...context]
|
|
693
732
|
return {
|
|
694
|
-
type:
|
|
733
|
+
type: UnreliableFieldConversionType.Success,
|
|
695
734
|
value: 1,
|
|
696
735
|
}
|
|
697
736
|
})
|
|
@@ -760,7 +799,6 @@ describe('all', function () {
|
|
|
760
799
|
it.each([
|
|
761
800
|
[
|
|
762
801
|
'$.0',
|
|
763
|
-
// eslint-disable-next-line no-undefined
|
|
764
802
|
undefined,
|
|
765
803
|
],
|
|
766
804
|
[
|
|
@@ -881,26 +919,26 @@ describe('all', function () {
|
|
|
881
919
|
describe('union', function () {
|
|
882
920
|
describe('non-discriminated', function () {
|
|
883
921
|
const listOfNumbersTypeDef = list(numberType)
|
|
884
|
-
const
|
|
885
|
-
.
|
|
886
|
-
.
|
|
922
|
+
const type = union()
|
|
923
|
+
.or('null', nullType)
|
|
924
|
+
.or('0', listOfNumbersTypeDef)
|
|
887
925
|
const adapters = {
|
|
888
|
-
$: adapterFromTwoWayConverter(new NullableToBooleanConverter(
|
|
926
|
+
$: adapterFromTwoWayConverter(new NullableToBooleanConverter(type, [1], null)),
|
|
889
927
|
'$.*': integerToStringAdapter,
|
|
890
928
|
} as const
|
|
891
|
-
type
|
|
929
|
+
type ValueToTypePaths = ValueToTypePathsOfType<typeof type>
|
|
892
930
|
const presenter = new FormPresenter<
|
|
893
|
-
typeof
|
|
894
|
-
|
|
931
|
+
typeof type,
|
|
932
|
+
ValueToTypePaths,
|
|
895
933
|
typeof adapters
|
|
896
934
|
>(
|
|
897
|
-
|
|
935
|
+
type,
|
|
898
936
|
adapters,
|
|
899
937
|
)
|
|
900
|
-
let originalValue:
|
|
938
|
+
let originalValue: ValueOfType<typeof type>
|
|
901
939
|
let model: FormModel<
|
|
902
|
-
typeof
|
|
903
|
-
|
|
940
|
+
typeof type,
|
|
941
|
+
ValueToTypePaths,
|
|
904
942
|
typeof adapters
|
|
905
943
|
>
|
|
906
944
|
beforeEach(function () {
|
|
@@ -911,8 +949,7 @@ describe('all', function () {
|
|
|
911
949
|
it('has the expected fields', function () {
|
|
912
950
|
expect(model.fields).toEqual({
|
|
913
951
|
$: {
|
|
914
|
-
|
|
915
|
-
// eslint-disable-next-line no-undefined
|
|
952
|
+
readonly: false,
|
|
916
953
|
error: undefined,
|
|
917
954
|
value: false,
|
|
918
955
|
required: false,
|
|
@@ -932,6 +969,93 @@ describe('all', function () {
|
|
|
932
969
|
})
|
|
933
970
|
})
|
|
934
971
|
})
|
|
972
|
+
|
|
973
|
+
describe('discriminated', function () {
|
|
974
|
+
const struct1 = object().field('a', numberType)
|
|
975
|
+
const struct2 = object().field('b', booleanType)
|
|
976
|
+
const type = union('d')
|
|
977
|
+
.or('x', struct1)
|
|
978
|
+
.or('y', struct2)
|
|
979
|
+
type ValueToTypePaths = ValueToTypePathsOfType<typeof type>
|
|
980
|
+
|
|
981
|
+
const adapters = {
|
|
982
|
+
$: adapterFromTwoWayConverter(new SelectDiscriminatedUnionConverter(
|
|
983
|
+
type,
|
|
984
|
+
{
|
|
985
|
+
x: {
|
|
986
|
+
d: 'x',
|
|
987
|
+
a: 0,
|
|
988
|
+
},
|
|
989
|
+
y: {
|
|
990
|
+
d: 'y',
|
|
991
|
+
b: false,
|
|
992
|
+
},
|
|
993
|
+
},
|
|
994
|
+
'x',
|
|
995
|
+
true,
|
|
996
|
+
)).narrow,
|
|
997
|
+
'$.x:a': identityAdapter(0).narrow,
|
|
998
|
+
'$.y:b': identityAdapter(false).narrow,
|
|
999
|
+
} as const
|
|
1000
|
+
const presenter = new FormPresenter<
|
|
1001
|
+
typeof type,
|
|
1002
|
+
ValueToTypePaths,
|
|
1003
|
+
typeof adapters
|
|
1004
|
+
>(
|
|
1005
|
+
type,
|
|
1006
|
+
adapters,
|
|
1007
|
+
)
|
|
1008
|
+
|
|
1009
|
+
describe('isValuePathActive', function () {
|
|
1010
|
+
describe('discriminator x', function () {
|
|
1011
|
+
const model = presenter.createModel({
|
|
1012
|
+
d: 'x',
|
|
1013
|
+
a: 1,
|
|
1014
|
+
})
|
|
1015
|
+
it.each([
|
|
1016
|
+
[
|
|
1017
|
+
'$',
|
|
1018
|
+
true,
|
|
1019
|
+
],
|
|
1020
|
+
[
|
|
1021
|
+
'$.x:a',
|
|
1022
|
+
true,
|
|
1023
|
+
],
|
|
1024
|
+
[
|
|
1025
|
+
'$.y:b',
|
|
1026
|
+
false,
|
|
1027
|
+
],
|
|
1028
|
+
] as const)('value path %s is active %s', function (path, expected) {
|
|
1029
|
+
const isValid = presenter.isValuePathActive(model, path)
|
|
1030
|
+
expect(isValid).toBe(expected)
|
|
1031
|
+
})
|
|
1032
|
+
})
|
|
1033
|
+
|
|
1034
|
+
describe('discriminator y', function () {
|
|
1035
|
+
const model = presenter.createModel({
|
|
1036
|
+
d: 'y',
|
|
1037
|
+
b: false,
|
|
1038
|
+
})
|
|
1039
|
+
it.each([
|
|
1040
|
+
[
|
|
1041
|
+
'$',
|
|
1042
|
+
true,
|
|
1043
|
+
],
|
|
1044
|
+
[
|
|
1045
|
+
'$.x:a',
|
|
1046
|
+
false,
|
|
1047
|
+
],
|
|
1048
|
+
[
|
|
1049
|
+
'$.y:b',
|
|
1050
|
+
true,
|
|
1051
|
+
],
|
|
1052
|
+
] as const)('value path %s is active %s', function (path, expected) {
|
|
1053
|
+
const isValid = presenter.isValuePathActive(model, path)
|
|
1054
|
+
expect(isValid).toBe(expected)
|
|
1055
|
+
})
|
|
1056
|
+
})
|
|
1057
|
+
})
|
|
1058
|
+
})
|
|
935
1059
|
})
|
|
936
1060
|
|
|
937
1061
|
describe('fake', function () {
|
|
@@ -952,7 +1076,7 @@ describe('all', function () {
|
|
|
952
1076
|
typeDef,
|
|
953
1077
|
converters,
|
|
954
1078
|
)
|
|
955
|
-
let originalValue:
|
|
1079
|
+
let originalValue: ValueOfType<typeof typeDef>
|
|
956
1080
|
let model: FormModel<
|
|
957
1081
|
typeof typeDef,
|
|
958
1082
|
JsonPaths,
|