ballerina-core 1.0.28 → 1.0.31
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/main.ts +2 -0
- package/package.json +1 -1
- package/src/async/domains/mirroring/domains/entity/domains/loaded-collection-entity/state.ts +2 -1
- package/src/async/domains/mirroring/domains/entity/domains/loaded-entity/state.ts +2 -1
- package/src/debounced/coroutines/debounce.ts +72 -36
- package/src/debounced/state.ts +5 -4
- package/src/forms/domains/launcher/domains/edit/coroutines/runner.ts +2 -2
- package/src/forms/domains/launcher/domains/edit/state.ts +10 -11
- package/src/forms/domains/launcher/domains/edit/template.tsx +30 -6
- package/src/forms/domains/launcher/state.ts +1 -1
- package/src/forms/domains/launcher/template.tsx +1 -2
- package/src/forms/domains/parser/domains/built-ins/state.ts +111 -33
- package/src/forms/domains/parser/domains/types/state.ts +17 -5
- package/src/forms/domains/parser/domains/validator/state.ts +121 -70
- package/src/forms/domains/parser/state.tsx +101 -34
- package/src/forms/domains/primitives/domains/boolean/template.tsx +4 -4
- package/src/forms/domains/primitives/domains/date/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/enum/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/enum-multiselect/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/list/template.tsx +3 -3
- package/src/forms/domains/primitives/domains/map/state.ts +55 -0
- package/src/forms/domains/primitives/domains/map/template.tsx +114 -0
- package/src/forms/domains/primitives/domains/number/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/searchable-infinite-stream/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/searchable-infinite-stream-multiselect/template.tsx +2 -2
- package/src/forms/domains/primitives/domains/string/template.tsx +2 -2
- package/src/forms/domains/singleton/template.tsx +6 -5
package/main.ts
CHANGED
|
@@ -91,6 +91,8 @@ export * from "./src/forms/domains/primitives/domains/searchable-infinite-stream
|
|
|
91
91
|
export * from "./src/forms/domains/primitives/domains/searchable-infinite-stream-multiselect/template"
|
|
92
92
|
export * from "./src/forms/domains/primitives/domains/list/state"
|
|
93
93
|
export * from "./src/forms/domains/primitives/domains/list/template"
|
|
94
|
+
export * from "./src/forms/domains/primitives/domains/map/state"
|
|
95
|
+
export * from "./src/forms/domains/primitives/domains/map/template"
|
|
94
96
|
export * from "./src/forms/domains/singleton/domains/mapping/state"
|
|
95
97
|
export * from "./src/forms/domains/singleton/domains/mapping/template"
|
|
96
98
|
export * from "./src/forms/domains/parser/state"
|
package/package.json
CHANGED
package/src/async/domains/mirroring/domains/entity/domains/loaded-collection-entity/state.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Sum } from "../../../../../../../../main";
|
|
1
2
|
import { DebouncedStatus, DirtyStatus } from "../../../../../../../debounced/state";
|
|
2
3
|
import { AsyncState } from "../../../../../../state";
|
|
3
4
|
import { CollectionEntity } from "../../../collection/state";
|
|
@@ -7,7 +8,7 @@ export type LoadedCollectionEntity<E> = LoadedEntity<E> & {
|
|
|
7
8
|
isRemoved:boolean;
|
|
8
9
|
lastUpdated: number;
|
|
9
10
|
dirty: DirtyStatus;
|
|
10
|
-
status: DebouncedStatus
|
|
11
|
+
status: Sum<DebouncedStatus, "debug off">;
|
|
11
12
|
};
|
|
12
13
|
export const LoadedCollectionEntity = {
|
|
13
14
|
Default:{
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Sum } from "../../../../../../../../main";
|
|
1
2
|
import { DebouncedStatus, DirtyStatus } from "../../../../../../../debounced/state";
|
|
2
3
|
import { AsyncState } from "../../../../../../state";
|
|
3
4
|
import { Entity } from "../../state";
|
|
@@ -10,7 +11,7 @@ export type LoadedEntity<E> = {
|
|
|
10
11
|
synchronizationErrors:Array<any>;
|
|
11
12
|
lastUpdated: number;
|
|
12
13
|
dirty: DirtyStatus;
|
|
13
|
-
status: DebouncedStatus
|
|
14
|
+
status: Sum<DebouncedStatus, "debug off">;
|
|
14
15
|
};
|
|
15
16
|
export const LoadedEntity = {
|
|
16
17
|
Default:{
|
|
@@ -26,11 +26,18 @@ export const Debounce = <value, context = Unit>(
|
|
|
26
26
|
Co.SetState(
|
|
27
27
|
updaters.Core.dirty(replaceWith<DirtyStatus>("dirty but being processed"))
|
|
28
28
|
),
|
|
29
|
-
Co.
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
Co.GetState().then((current) => {
|
|
30
|
+
if (current.status.kind == "l") {
|
|
31
|
+
return Co.SetState(
|
|
32
|
+
updaters.Core.status(
|
|
33
|
+
replaceWith<DebouncedStatus>(
|
|
34
|
+
"just detected dirty, starting processing"
|
|
35
|
+
)
|
|
36
|
+
)
|
|
37
|
+
);
|
|
38
|
+
}
|
|
39
|
+
else return Co.Do(() => {});
|
|
40
|
+
}),
|
|
34
41
|
Co.Any([
|
|
35
42
|
// shortcircuit the validation if it takes longer than the whole cycle in the presence of an underwater update of the field
|
|
36
43
|
Co.Seq([
|
|
@@ -40,22 +47,36 @@ export const Debounce = <value, context = Unit>(
|
|
|
40
47
|
Date.now() - current.lastUpdated <= debounceDurationInMs,
|
|
41
48
|
Co.Wait(debounceDurationInMs / 5)
|
|
42
49
|
),
|
|
43
|
-
Co.
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
50
|
+
Co.GetState().then((current) => {
|
|
51
|
+
if (current.status.kind == "l") {
|
|
52
|
+
return Co.SetState(
|
|
53
|
+
updaters.Core.status(
|
|
54
|
+
replaceWith<DebouncedStatus>(
|
|
55
|
+
"processing shortcircuited"
|
|
56
|
+
)
|
|
57
|
+
)
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
else return Co.Do(() => {});
|
|
61
|
+
}),
|
|
48
62
|
Co.Wait(debounceDurationInMs / 2),
|
|
49
63
|
]),
|
|
50
64
|
k
|
|
51
65
|
.embed((_: Debounced<value & context>) => _, updaters.Core.value)
|
|
52
66
|
.then((apiResult) => {
|
|
53
67
|
return Co.Seq([
|
|
54
|
-
Co.
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
68
|
+
Co.GetState().then((current) => {
|
|
69
|
+
if (current.status.kind == "l") {
|
|
70
|
+
return Co.SetState(
|
|
71
|
+
updaters.Core.status(
|
|
72
|
+
replaceWith<DebouncedStatus>(
|
|
73
|
+
"processing finished"
|
|
74
|
+
)
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
else return Co.Do(() => {});
|
|
79
|
+
}),
|
|
59
80
|
// Co.Wait(250)
|
|
60
81
|
]).then(() => {
|
|
61
82
|
return Co.GetState().then((current) => {
|
|
@@ -64,13 +85,18 @@ export const Debounce = <value, context = Unit>(
|
|
|
64
85
|
// maybe a new change has already reset dirty, in that case we need to start all over again
|
|
65
86
|
if (current.dirty == "dirty but being processed") {
|
|
66
87
|
return Co.Seq([
|
|
67
|
-
Co.
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
88
|
+
Co.GetState().then((current) => {
|
|
89
|
+
if (current.status.kind == "l") {
|
|
90
|
+
return Co.SetState(
|
|
91
|
+
updaters.Core.status(
|
|
92
|
+
replaceWith<DebouncedStatus>(
|
|
93
|
+
"state was still dirty but being processed, resetting to not dirty"
|
|
94
|
+
)
|
|
95
|
+
)
|
|
96
|
+
);
|
|
97
|
+
}
|
|
98
|
+
else return Co.Do(() => {});
|
|
99
|
+
}),
|
|
74
100
|
// use UpdateState to make sure that we look up the state at the last possible moment to account for delays
|
|
75
101
|
Co.UpdateState((state) =>
|
|
76
102
|
state.dirty == "dirty but being processed"
|
|
@@ -82,13 +108,18 @@ export const Debounce = <value, context = Unit>(
|
|
|
82
108
|
]);
|
|
83
109
|
} else {
|
|
84
110
|
return Co.Seq([
|
|
85
|
-
Co.
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
111
|
+
Co.GetState().then((current) => {
|
|
112
|
+
if (current.status.kind == "l") {
|
|
113
|
+
return Co.SetState(
|
|
114
|
+
updaters.Core.status(
|
|
115
|
+
replaceWith<DebouncedStatus>(
|
|
116
|
+
"state was changed underwater back to dirty, leaving the dirty flag alone"
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
}
|
|
121
|
+
else return Co.Do(() => {});
|
|
122
|
+
}),
|
|
92
123
|
Co.SetState(
|
|
93
124
|
updaters.Core.dirty(replaceWith<DirtyStatus>("dirty"))
|
|
94
125
|
),
|
|
@@ -97,13 +128,18 @@ export const Debounce = <value, context = Unit>(
|
|
|
97
128
|
}
|
|
98
129
|
} else {
|
|
99
130
|
return Co.Seq([
|
|
100
|
-
Co.
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
131
|
+
Co.GetState().then((current) => {
|
|
132
|
+
if (current.status.kind == "l") {
|
|
133
|
+
return Co.SetState(
|
|
134
|
+
updaters.Core.status(
|
|
135
|
+
replaceWith<DebouncedStatus>(
|
|
136
|
+
"inner call failed with transient failure"
|
|
137
|
+
)
|
|
138
|
+
)
|
|
139
|
+
);
|
|
140
|
+
}
|
|
141
|
+
else return Co.Do(() => {});
|
|
142
|
+
}),
|
|
107
143
|
Co.SetState(
|
|
108
144
|
updaters.Core.dirty(replaceWith<DirtyStatus>("dirty"))
|
|
109
145
|
),
|
package/src/debounced/state.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { Sum } from "../../main";
|
|
1
2
|
import { replaceWith } from "../fun/domains/updater/domains/replaceWith/state";
|
|
2
3
|
import { BasicUpdater, Updater } from "../fun/domains/updater/state";
|
|
3
4
|
|
|
@@ -7,19 +8,19 @@ export type DebouncedStatus = "waiting for dirty" | "just detected dirty, starti
|
|
|
7
8
|
| "processing shortcircuited"
|
|
8
9
|
| "state was changed underwater back to dirty, leaving the dirty flag alone"
|
|
9
10
|
| "inner call failed with transient failure"
|
|
10
|
-
export type Debounced<Value> = Value & { lastUpdated: number; dirty: DirtyStatus; status:DebouncedStatus };
|
|
11
|
+
export type Debounced<Value> = Value & { lastUpdated: number; dirty: DirtyStatus; status: Sum<DebouncedStatus, "debug off"> };
|
|
11
12
|
export const Debounced = {
|
|
12
|
-
Default: <v>(initialValue: v): Debounced<v> => ({
|
|
13
|
+
Default: <v>(initialValue: v, debug?: boolean): Debounced<v> => ({
|
|
13
14
|
...initialValue,
|
|
14
15
|
lastUpdated: 0,
|
|
15
16
|
dirty: "not dirty",
|
|
16
|
-
status: "waiting for dirty"
|
|
17
|
+
status: debug ? Sum.Default.left("waiting for dirty") : Sum.Default.right("debug off")
|
|
17
18
|
}),
|
|
18
19
|
Updaters: {
|
|
19
20
|
Core:{
|
|
20
21
|
status: <v>(_: BasicUpdater<DebouncedStatus>): Updater<Debounced<v>> => Updater<Debounced<v>>(current => ({
|
|
21
22
|
...current,
|
|
22
|
-
status: _(current.status),
|
|
23
|
+
status: current.status.kind == "l" ? Sum.Default.left(_(current.status.value)) : Sum.Default.right("debug off"),
|
|
23
24
|
})),
|
|
24
25
|
dirty: <v>(_: BasicUpdater<DirtyStatus>): Updater<Debounced<v>> => Updater<Debounced<v>>(current => ({
|
|
25
26
|
...current,
|
|
@@ -23,7 +23,7 @@ export const editFormRunner = <E, FS>() => {
|
|
|
23
23
|
|
|
24
24
|
const init = Co.GetState().then((current) =>
|
|
25
25
|
Synchronize<Unit, E>(
|
|
26
|
-
() => current.api.get(),
|
|
26
|
+
() => current.api.get(current.entityId),
|
|
27
27
|
(_) => "transient failure",
|
|
28
28
|
5,
|
|
29
29
|
50
|
|
@@ -46,7 +46,7 @@ export const editFormRunner = <E, FS>() => {
|
|
|
46
46
|
5,
|
|
47
47
|
50
|
|
48
48
|
),
|
|
49
|
-
|
|
49
|
+
15
|
|
50
50
|
).embed(
|
|
51
51
|
(_) => ({ ..._, ..._.apiRunner }),
|
|
52
52
|
EditFormState<E, FS>().Updaters.Core.apiRunner
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ApiResponseChecker, AsyncState, BasicUpdater, Debounced, ForeignMutationsInput, id, SimpleCallback, simpleUpdater, Synchronized, Template, unit, Unit, Updater, Value } from "../../../../../../main"
|
|
1
|
+
import { ApiResponseChecker, AsyncState, BasicUpdater, Debounced, ForeignMutationsInput, Guid, id, SimpleCallback, simpleUpdater, Synchronized, Template, unit, Unit, Updater, Value } from "../../../../../../main"
|
|
2
2
|
import { BasicFun } from "../../../../../fun/state"
|
|
3
3
|
|
|
4
4
|
export type ApiErrors = Array<string>
|
|
@@ -6,11 +6,10 @@ export type ApiErrors = Array<string>
|
|
|
6
6
|
export type EditFormContext<E,FS> = {
|
|
7
7
|
entityId:string,
|
|
8
8
|
api:{
|
|
9
|
-
get:() => Promise<E>,
|
|
9
|
+
get:(id: Guid) => Promise<E>,
|
|
10
10
|
update:BasicFun<E, Promise<ApiErrors>>
|
|
11
11
|
},
|
|
12
|
-
actualForm:Template<Value<E> & FS, FS, { onChange:SimpleCallback<BasicUpdater<E>>
|
|
13
|
-
debounceRateMs?: number
|
|
12
|
+
actualForm:Template<Value<E> & FS, FS, { onChange:SimpleCallback<BasicUpdater<E>>}>
|
|
14
13
|
}
|
|
15
14
|
|
|
16
15
|
export type EditFormState<E,FS> = {
|
|
@@ -39,19 +38,19 @@ export const EditFormState = <E,FS>() => ({
|
|
|
39
38
|
toChecked: () => ApiResponseChecker.Updaters.toChecked<EditFormState<E, FS>>(),
|
|
40
39
|
toUnchecked: () => ApiResponseChecker.Updaters.toUnchecked<EditFormState<E, FS>>(),
|
|
41
40
|
entity:(_:BasicUpdater<E>) : Updater<EditFormState<E,FS>> =>
|
|
42
|
-
|
|
43
|
-
Debounced.Updaters.Template.value(
|
|
41
|
+
EditFormState<E,FS>().Updaters.Core.entity(
|
|
44
42
|
Synchronized.Updaters.sync(
|
|
45
43
|
AsyncState.Operations.map(
|
|
46
|
-
|
|
44
|
+
_
|
|
47
45
|
)
|
|
48
46
|
)
|
|
49
|
-
)
|
|
50
|
-
|
|
51
|
-
|
|
47
|
+
),
|
|
48
|
+
submit: () : Updater<EditFormState<E,FS>> =>
|
|
49
|
+
EditFormState<E,FS>().Updaters.Core.apiRunner(
|
|
50
|
+
Debounced.Updaters.Template.value(
|
|
52
51
|
Synchronized.Updaters.sync(
|
|
53
52
|
AsyncState.Operations.map(
|
|
54
|
-
|
|
53
|
+
id
|
|
55
54
|
)
|
|
56
55
|
)
|
|
57
56
|
)
|
|
@@ -1,19 +1,41 @@
|
|
|
1
|
-
import { AsyncState, editFormRunner, replaceWith, unit } from "../../../../../../main";
|
|
1
|
+
import { AsyncState, editFormRunner, replaceWith, SimpleCallback, unit } from "../../../../../../main";
|
|
2
2
|
import { Template } from "../../../../../template/state";
|
|
3
3
|
import { EditFormContext, EditFormForeignMutationsExpected, EditFormState, EditFormWritableState } from "./state";
|
|
4
4
|
|
|
5
|
+
export type EditFormView<E, FS> =
|
|
6
|
+
Template<
|
|
7
|
+
EditFormContext<E, FS> & EditFormWritableState<E, FS>,
|
|
8
|
+
EditFormWritableState<E, FS>,
|
|
9
|
+
EditFormForeignMutationsExpected<E, FS> & { onSubmit: SimpleCallback<void> },
|
|
10
|
+
{
|
|
11
|
+
actualForm: JSX.Element | undefined
|
|
12
|
+
}>
|
|
5
13
|
export type EditFormTemplate<E, FS> =
|
|
6
14
|
Template<
|
|
7
15
|
EditFormContext<E, FS> & EditFormWritableState<E, FS>,
|
|
8
16
|
EditFormWritableState<E, FS>,
|
|
9
|
-
EditFormForeignMutationsExpected<E, FS
|
|
17
|
+
EditFormForeignMutationsExpected<E, FS>,
|
|
18
|
+
EditFormView<E, FS>>
|
|
10
19
|
export const EditFormTemplate = <E, FS>() : EditFormTemplate<E,FS> =>
|
|
11
20
|
Template.Default<
|
|
12
21
|
EditFormContext<E, FS> & EditFormWritableState<E, FS>,
|
|
13
22
|
EditFormWritableState<E, FS>,
|
|
14
|
-
EditFormForeignMutationsExpected<E, FS
|
|
23
|
+
EditFormForeignMutationsExpected<E, FS>,
|
|
24
|
+
EditFormView<E, FS>
|
|
25
|
+
>(props =>
|
|
15
26
|
<>
|
|
16
|
-
|
|
27
|
+
{
|
|
28
|
+
props.view({
|
|
29
|
+
...props,
|
|
30
|
+
foreignMutations: {
|
|
31
|
+
...props.foreignMutations,
|
|
32
|
+
onSubmit: () => {
|
|
33
|
+
props.setState(EditFormState<E, FS>().Updaters.Template.submit())
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
view: {
|
|
37
|
+
...props.view,
|
|
38
|
+
actualForm:
|
|
17
39
|
!AsyncState.Operations.hasValue(props.context.entity.sync) ? undefined :
|
|
18
40
|
props.context.actualForm({
|
|
19
41
|
context: {
|
|
@@ -28,11 +50,13 @@ export const EditFormTemplate = <E, FS>() : EditFormTemplate<E,FS> =>
|
|
|
28
50
|
foreignMutations: {
|
|
29
51
|
onChange: (e) => {
|
|
30
52
|
props.setState(EditFormState<E, FS>().Updaters.Template.entity(e))
|
|
31
|
-
}
|
|
53
|
+
},
|
|
32
54
|
},
|
|
33
55
|
view: unit
|
|
34
56
|
})
|
|
35
|
-
|
|
57
|
+
}
|
|
58
|
+
})
|
|
59
|
+
}
|
|
36
60
|
</>
|
|
37
61
|
).any([
|
|
38
62
|
editFormRunner<E, FS>().mapContextFromProps(props => ({
|
|
@@ -25,7 +25,6 @@ export const FormRunnerTemplate =
|
|
|
25
25
|
<props.context.form.value.form
|
|
26
26
|
context={{
|
|
27
27
|
...props.context.form.value.formState,
|
|
28
|
-
debounceRateMs: props.context.formRef.kind == "edit" ? props.context.formRef.debounceRateMs : undefined,
|
|
29
28
|
entityId: props.context.formRef.kind == "edit" ? props.context.formRef.entityId : undefined,
|
|
30
29
|
value: props.context.formRef.kind == "map" ? props.context.formRef.value : undefined,
|
|
31
30
|
formState: props.context.formRef.kind == "map" ? props.context.form.value.formState : props.context.form.value.formState.formState,
|
|
@@ -35,7 +34,7 @@ export const FormRunnerTemplate =
|
|
|
35
34
|
props.context.formRef.kind == "map" ? props.context.form.value.mapping.from(props.context.formRef.value) :
|
|
36
35
|
props.context.form.value.formState?.entity.sync?.value,
|
|
37
36
|
},
|
|
38
|
-
submitButtonWrapper: props.context.formRef.kind == "create" ? props.context.formRef.submitButtonWrapper : undefined
|
|
37
|
+
submitButtonWrapper: (props.context.formRef.kind == "create" || props.context.formRef.kind == "edit" ) ? props.context.formRef.submitButtonWrapper : undefined
|
|
39
38
|
}}
|
|
40
39
|
setState={(_: BasicUpdater<any>) => props.setState(
|
|
41
40
|
FormRunnerState.Updaters.form(
|
|
@@ -16,7 +16,8 @@ export type PrimitiveType = (typeof PrimitiveTypes)[number]
|
|
|
16
16
|
export const GenericTypes = [
|
|
17
17
|
"SingleSelection",
|
|
18
18
|
"MultiSelection",
|
|
19
|
-
"List"
|
|
19
|
+
"List",
|
|
20
|
+
"Map"] as const
|
|
20
21
|
export type GenericType = (typeof GenericTypes)[number]
|
|
21
22
|
|
|
22
23
|
export type ApiConverter<T> = { fromAPIRawValue: BasicFun<any, T>, toAPIRawValue: BasicFun<T, any> }
|
|
@@ -30,6 +31,7 @@ export type ApiConverters = {
|
|
|
30
31
|
"SingleSelection": ApiConverter<CollectionSelection<any>>
|
|
31
32
|
"MultiSelection": ApiConverter<OrderedMap<string, any>>
|
|
32
33
|
"List": ApiConverter<List<any>>
|
|
34
|
+
"Map": ApiConverter<List<[any, any]>>
|
|
33
35
|
}
|
|
34
36
|
|
|
35
37
|
export type PrimitiveBuiltIn = { renderers: Set<keyof BuiltIns["renderers"]>, apiConverters: ApiConverter<any>, defaultValue: any }
|
|
@@ -48,6 +50,7 @@ export type BuiltIns = {
|
|
|
48
50
|
streamSingleSelection: Set<string>;
|
|
49
51
|
streamMultiSelection: Set<string>;
|
|
50
52
|
list: Set<string>;
|
|
53
|
+
map: Set<string>;
|
|
51
54
|
};
|
|
52
55
|
};
|
|
53
56
|
|
|
@@ -65,7 +68,8 @@ export const builtInsFromFieldViews = (fieldViews: any, fieldTypeConverters: Api
|
|
|
65
68
|
"generics": Map([
|
|
66
69
|
["SingleSelection", { apiConverters: fieldTypeConverters["SingleSelection"], defaultValue: CollectionSelection().Default.right("no selection") }] as [string, GenericBuiltIn],
|
|
67
70
|
["Multiselection", { apiConverters: fieldTypeConverters["SingleSelection"], defaultValue: Map() }] as [string, GenericBuiltIn],
|
|
68
|
-
["List", { apiConverters: fieldTypeConverters["SingleSelection"], defaultValue: List() }] as [string, GenericBuiltIn]
|
|
71
|
+
["List", { apiConverters: fieldTypeConverters["SingleSelection"], defaultValue: List() }] as [string, GenericBuiltIn],
|
|
72
|
+
["Map", { apiConverters: fieldTypeConverters["SingleSelection"], defaultValue: List() }] as [string, GenericBuiltIn]
|
|
69
73
|
]),
|
|
70
74
|
"renderers": {
|
|
71
75
|
"boolean": Set(),
|
|
@@ -78,6 +82,7 @@ export const builtInsFromFieldViews = (fieldViews: any, fieldTypeConverters: Api
|
|
|
78
82
|
"number": Set(),
|
|
79
83
|
"string": Set(),
|
|
80
84
|
"list": Set(),
|
|
85
|
+
"map": Set(),
|
|
81
86
|
}
|
|
82
87
|
}
|
|
83
88
|
Object.keys(builtins.renderers).forEach((_categoryName) => {
|
|
@@ -92,31 +97,53 @@ export const builtInsFromFieldViews = (fieldViews: any, fieldTypeConverters: Api
|
|
|
92
97
|
}
|
|
93
98
|
|
|
94
99
|
|
|
95
|
-
export const defaultValue = (types:Map<TypeName, TypeDefinition>, builtIns:BuiltIns) => (t: TypeName): any => {
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
let generic = builtIns.generics.get(t)
|
|
101
|
-
if (generic != undefined) {
|
|
102
|
-
return generic.defaultValue
|
|
100
|
+
export const defaultValue = (types: Map<TypeName, TypeDefinition>, builtIns: BuiltIns) => (t: TypeName | Type): any => {
|
|
101
|
+
if (typeof t == "string") {
|
|
102
|
+
let primitive = builtIns.primitives.get(t)
|
|
103
|
+
if (primitive != undefined) {
|
|
104
|
+
return primitive.defaultValue
|
|
103
105
|
} else {
|
|
104
|
-
let
|
|
105
|
-
if (
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
106
|
+
let generic = builtIns.generics.get(t)
|
|
107
|
+
if (generic != undefined) {
|
|
108
|
+
return generic.defaultValue
|
|
109
|
+
} else {
|
|
110
|
+
let custom = types.get(t)
|
|
111
|
+
if (custom != undefined) {
|
|
112
|
+
let res = {} as any
|
|
113
|
+
custom.fields.forEach((field, fieldName) => {
|
|
114
|
+
res[fieldName] = defaultValue(types, builtIns)(field.kind == "primitive" ? field.value : field.kind == "lookup" ? field.name : field.value)
|
|
115
|
+
}
|
|
116
|
+
)
|
|
117
|
+
return res
|
|
118
|
+
} else {
|
|
119
|
+
debugger
|
|
120
|
+
throw `cannot find type ${t} when resolving defaultValue`
|
|
109
121
|
}
|
|
110
|
-
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
} else {
|
|
125
|
+
if (t.kind == "application") {
|
|
126
|
+
const generic = builtIns.generics.get(t.value)
|
|
127
|
+
if (generic) {
|
|
128
|
+
const res = generic.defaultValue
|
|
111
129
|
return res
|
|
112
|
-
} else {
|
|
113
|
-
throw `cannot find type ${t} when resolving defaultValue`
|
|
114
130
|
}
|
|
115
131
|
}
|
|
132
|
+
debugger
|
|
133
|
+
throw `cannot find type ${t} when resolving defaultValue`
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
|
|
138
|
+
const parseTypeIShouldBePartOfFormValidation = (t:any) : TypeName | Type => {
|
|
139
|
+
if (typeof t == "string") return t
|
|
140
|
+
if ("fun" in t && "args" in t && Array.isArray(t.args)) {
|
|
141
|
+
return { kind:"application", value:t.fun, args:t.args }
|
|
116
142
|
}
|
|
143
|
+
return null!
|
|
117
144
|
}
|
|
118
145
|
|
|
119
|
-
export const fromAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, builtIns:BuiltIns, converters:ApiConverters, isKeywordsReplaced: boolean = false) => (raw:any)
|
|
146
|
+
export const fromAPIRawValue = (t: Type, types: Map<TypeName, TypeDefinition>, builtIns: BuiltIns, converters: ApiConverters, isKeywordsReplaced: boolean = false) => (raw: any): any => {
|
|
120
147
|
// alert(JSON.stringify(t))
|
|
121
148
|
if (raw == undefined) {
|
|
122
149
|
console.warn(`instantiating default value for type ${JSON.stringify(t)}: the value was undefined so something is missing from the API response`)
|
|
@@ -131,25 +158,49 @@ export const fromAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, bui
|
|
|
131
158
|
if (t.value == "SingleSelection" && t.args.length == 1) {
|
|
132
159
|
let result = converters[t.value].fromAPIRawValue(obj)
|
|
133
160
|
result = CollectionSelection().Updaters.left(
|
|
134
|
-
fromAPIRawValue({ kind:"lookup", name:t.args[0] }, types, builtIns, converters, true))(result)
|
|
161
|
+
fromAPIRawValue({ kind: "lookup", name: t.args[0] }, types, builtIns, converters, true))(result)
|
|
135
162
|
return result
|
|
136
163
|
}
|
|
137
164
|
if ((t.value == "Multiselection" || t.value == "MultiSelection") && t.args.length == 1) {
|
|
138
165
|
let result = converters["MultiSelection"].fromAPIRawValue(obj)
|
|
139
|
-
result = result.map(fromAPIRawValue({ kind:"lookup", name:t.args[0] }, types, builtIns, converters, true))
|
|
166
|
+
result = result.map(fromAPIRawValue({ kind: "lookup", name: t.args[0] }, types, builtIns, converters, true))
|
|
140
167
|
return result
|
|
141
168
|
}
|
|
142
169
|
if (t.value == "List" && t.args.length == 1) {
|
|
143
170
|
let result = converters[t.value].fromAPIRawValue(obj)
|
|
144
171
|
result = result.map(fromAPIRawValue(
|
|
145
172
|
PrimitiveTypes.some(_ => _ == t.args[0]) ?
|
|
146
|
-
{ kind:"primitive", value:t.args[0] as PrimitiveType }
|
|
147
|
-
|
|
173
|
+
{ kind: "primitive", value: t.args[0] as PrimitiveType }
|
|
174
|
+
: { kind: "lookup", name: t.args[0] }
|
|
148
175
|
, types, builtIns, converters, true))
|
|
149
176
|
return result
|
|
150
177
|
}
|
|
178
|
+
if (t.value == "Map" && t.args.length == 2) {
|
|
179
|
+
let result = converters[t.value].fromAPIRawValue(obj)
|
|
180
|
+
let t_args = t.args.map(parseTypeIShouldBePartOfFormValidation)
|
|
181
|
+
result = result.map(keyValue => ([
|
|
182
|
+
fromAPIRawValue(
|
|
183
|
+
typeof t_args[0] == "string" ?
|
|
184
|
+
PrimitiveTypes.some(_ => _ == t_args[0]) ?
|
|
185
|
+
{ kind: "primitive", value: t_args[0] as PrimitiveType }
|
|
186
|
+
: { kind: "lookup", name: t_args[0] }
|
|
187
|
+
:
|
|
188
|
+
t_args[0],
|
|
189
|
+
types, builtIns, converters, true)(keyValue[0]),
|
|
190
|
+
fromAPIRawValue(
|
|
191
|
+
typeof t_args[1] == "string" ?
|
|
192
|
+
PrimitiveTypes.some(_ => _ == t_args[1]) ?
|
|
193
|
+
{ kind: "primitive", value: t_args[1] as PrimitiveType }
|
|
194
|
+
: { kind: "lookup", name: t_args[1] }
|
|
195
|
+
:
|
|
196
|
+
t_args[1],
|
|
197
|
+
types, builtIns, converters, true)(keyValue[1]),
|
|
198
|
+
])
|
|
199
|
+
)
|
|
200
|
+
return result
|
|
201
|
+
}
|
|
151
202
|
} else { // t.kind == lookup: we are dealing with a record/object
|
|
152
|
-
let result:any = {...obj}
|
|
203
|
+
let result: any = { ...obj }
|
|
153
204
|
const tDef = types.get(t.name)!
|
|
154
205
|
tDef.fields.forEach((fieldType, fieldName) => {
|
|
155
206
|
const replacedFieldName = replaceKeyword(fieldName)
|
|
@@ -163,8 +214,8 @@ export const fromAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, bui
|
|
|
163
214
|
}
|
|
164
215
|
|
|
165
216
|
|
|
166
|
-
export const toAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, builtIns:BuiltIns, converters:ApiConverters, isKeywordsReverted: boolean = false) => (raw:any)
|
|
167
|
-
|
|
217
|
+
export const toAPIRawValue = (t: Type, types: Map<TypeName, TypeDefinition>, builtIns: BuiltIns, converters: ApiConverters, isKeywordsReverted: boolean = false) => (raw: any): any => {
|
|
218
|
+
|
|
168
219
|
const obj = !isKeywordsReverted ? replaceKeywords(raw, "to api") : raw
|
|
169
220
|
|
|
170
221
|
if (t.kind == "primitive") {
|
|
@@ -173,7 +224,7 @@ export const toAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, built
|
|
|
173
224
|
if (t.value == "SingleSelection" && t.args.length == 1) {
|
|
174
225
|
let result = converters[t.value].toAPIRawValue(obj)
|
|
175
226
|
if (result != undefined && typeof result == "object")
|
|
176
|
-
result = toAPIRawValue({ kind:"lookup", name:t.args[0] }, types, builtIns, converters, true)(result)
|
|
227
|
+
result = toAPIRawValue({ kind: "lookup", name: t.args[0] }, types, builtIns, converters, true)(result)
|
|
177
228
|
return result
|
|
178
229
|
}
|
|
179
230
|
if ((t.value == "Multiselection" || t.value == "MultiSelection") && t.args.length == 1) {
|
|
@@ -181,8 +232,8 @@ export const toAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, built
|
|
|
181
232
|
let result = converters["MultiSelection"].toAPIRawValue(obj)
|
|
182
233
|
// alert(`MultiSelect result1 = ${JSON.stringify(result)}`)
|
|
183
234
|
// alert(`${JSON.stringify(t.args[0])}`)
|
|
184
|
-
result = result.map((_:any) =>
|
|
185
|
-
typeof _ == "object" ? toAPIRawValue({ kind:"lookup", name:t.args[0] }, types, builtIns, converters, true)(_) : _)
|
|
235
|
+
result = result.map((_: any) =>
|
|
236
|
+
typeof _ == "object" ? toAPIRawValue({ kind: "lookup", name: t.args[0] }, types, builtIns, converters, true)(_) : _)
|
|
186
237
|
// alert(`MultiSelect result2 = ${JSON.stringify(result)}`)
|
|
187
238
|
return result
|
|
188
239
|
}
|
|
@@ -190,14 +241,41 @@ export const toAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, built
|
|
|
190
241
|
let result = converters[t.value].toAPIRawValue(obj)
|
|
191
242
|
result = result.map(toAPIRawValue(
|
|
192
243
|
PrimitiveTypes.some(_ => _ == t.args[0]) ?
|
|
193
|
-
{ kind:"primitive", value:t.args[0] as PrimitiveType }
|
|
194
|
-
|
|
244
|
+
{ kind: "primitive", value: t.args[0] as PrimitiveType }
|
|
245
|
+
: { kind: "lookup", name: t.args[0] },
|
|
195
246
|
// { kind:"lookup", name:t.args[0] },
|
|
196
247
|
types, builtIns, converters, true))
|
|
197
248
|
return result
|
|
198
249
|
}
|
|
250
|
+
if (t.value == "Map" && t.args.length == 2) {
|
|
251
|
+
let result = converters[t.value].toAPIRawValue(obj)
|
|
252
|
+
|
|
253
|
+
let t_args = t.args.map(parseTypeIShouldBePartOfFormValidation)
|
|
254
|
+
result = result.map((keyValue: any) => ([
|
|
255
|
+
toAPIRawValue(
|
|
256
|
+
typeof t_args[0] == "string" ?
|
|
257
|
+
PrimitiveTypes.some(_ => _ == t_args[0]) ?
|
|
258
|
+
{ kind: "primitive", value: t_args[0] as PrimitiveType }
|
|
259
|
+
: { kind: "lookup", name: t_args[0] }
|
|
260
|
+
:
|
|
261
|
+
t_args[0],
|
|
262
|
+
types, builtIns, converters, true)(keyValue[0]),
|
|
263
|
+
toAPIRawValue(
|
|
264
|
+
typeof t_args[1] == "string" ?
|
|
265
|
+
PrimitiveTypes.some(_ => _ == t_args[1]) ?
|
|
266
|
+
{ kind: "primitive", value: t_args[1] as PrimitiveType }
|
|
267
|
+
: { kind: "lookup", name: t_args[1] }
|
|
268
|
+
:
|
|
269
|
+
t_args[1],
|
|
270
|
+
types, builtIns, converters, true)(keyValue[1]),
|
|
271
|
+
])
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
return result
|
|
275
|
+
}
|
|
276
|
+
|
|
199
277
|
} else { // t.kind == lookup: we are dealing with a record/object
|
|
200
|
-
let result:any = {...obj}
|
|
278
|
+
let result: any = { ...obj }
|
|
201
279
|
const tDef = types.get(t.name)!
|
|
202
280
|
tDef.fields.forEach((fieldType, fieldName) => {
|
|
203
281
|
const revertedFieldName = revertKeyword(fieldName)
|
|
@@ -206,5 +284,5 @@ export const toAPIRawValue = (t:Type, types:Map<TypeName, TypeDefinition>, built
|
|
|
206
284
|
})
|
|
207
285
|
return result
|
|
208
286
|
}
|
|
209
|
-
return defaultValue(types, builtIns)(t.value)
|
|
287
|
+
return defaultValue(types, builtIns)(t.value)
|
|
210
288
|
}
|