@player-ui/player 0.8.0--canary.307.9621 → 0.8.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Player.native.js +11630 -0
- package/dist/Player.native.js.map +1 -0
- package/dist/cjs/index.cjs +5626 -0
- package/dist/cjs/index.cjs.map +1 -0
- package/dist/{index.esm.js → index.legacy-esm.js} +2044 -1667
- package/dist/{index.cjs.js → index.mjs} +2052 -1761
- package/dist/index.mjs.map +1 -0
- package/package.json +29 -63
- package/src/__tests__/data.test.ts +498 -0
- package/src/__tests__/flow.test.ts +312 -0
- package/src/__tests__/helpers/action-exp.plugin.ts +22 -0
- package/src/__tests__/helpers/actions.flow.ts +67 -0
- package/src/__tests__/helpers/binding.plugin.ts +125 -0
- package/src/__tests__/helpers/expression.plugin.ts +88 -0
- package/src/__tests__/helpers/transform-plugin.ts +19 -0
- package/src/__tests__/helpers/validation.flow.ts +56 -0
- package/src/__tests__/player.test.ts +597 -0
- package/src/__tests__/string-resolver.test.ts +186 -0
- package/src/__tests__/validation.test.ts +3555 -0
- package/src/__tests__/view.test.ts +715 -0
- package/src/binding/__tests__/binding.test.ts +113 -0
- package/src/binding/__tests__/index.test.ts +208 -0
- package/src/binding/__tests__/resolver.test.ts +83 -0
- package/src/binding/binding.ts +6 -6
- package/src/binding/index.ts +34 -34
- package/src/binding/resolver.ts +19 -19
- package/src/binding/utils.ts +7 -7
- package/src/binding-grammar/__tests__/parser.test.ts +64 -0
- package/src/binding-grammar/__tests__/test-utils/ast-cases.ts +198 -0
- package/src/binding-grammar/__tests__/test-utils/perf-test.ts +66 -0
- package/src/binding-grammar/ast.ts +11 -11
- package/src/binding-grammar/custom/index.ts +19 -22
- package/src/binding-grammar/ebnf/index.ts +20 -21
- package/src/binding-grammar/ebnf/types.ts +13 -13
- package/src/binding-grammar/index.ts +4 -4
- package/src/binding-grammar/parsimmon/index.ts +14 -14
- package/src/controllers/constants/__tests__/index.test.ts +106 -0
- package/src/controllers/constants/index.ts +3 -3
- package/src/controllers/constants/utils.ts +4 -4
- package/src/controllers/data/controller.ts +22 -22
- package/src/controllers/data/index.ts +1 -1
- package/src/controllers/data/utils.ts +7 -7
- package/src/controllers/flow/__tests__/controller.test.ts +195 -0
- package/src/controllers/flow/__tests__/flow.test.ts +381 -0
- package/src/controllers/flow/controller.ts +13 -13
- package/src/controllers/flow/flow.ts +23 -23
- package/src/controllers/flow/index.ts +2 -2
- package/src/controllers/index.ts +5 -5
- package/src/controllers/validation/binding-tracker.ts +71 -59
- package/src/controllers/validation/controller.ts +104 -104
- package/src/controllers/validation/index.ts +2 -2
- package/src/controllers/view/asset-transform.ts +20 -20
- package/src/controllers/view/controller.ts +27 -27
- package/src/controllers/view/index.ts +4 -4
- package/src/controllers/view/store.ts +3 -3
- package/src/controllers/view/types.ts +7 -7
- package/src/data/__tests__/__snapshots__/dependency-tracker.test.ts.snap +64 -0
- package/src/data/__tests__/dependency-tracker.test.ts +146 -0
- package/src/data/__tests__/local-model.test.ts +46 -0
- package/src/data/__tests__/model.test.ts +78 -0
- package/src/data/dependency-tracker.ts +16 -16
- package/src/data/index.ts +4 -4
- package/src/data/local-model.ts +6 -6
- package/src/data/model.ts +17 -17
- package/src/data/noop-model.ts +1 -1
- package/src/expressions/__tests__/__snapshots__/parser.test.ts.snap +854 -0
- package/src/expressions/__tests__/evaluator-functions.test.ts +47 -0
- package/src/expressions/__tests__/evaluator.test.ts +410 -0
- package/src/expressions/__tests__/parser.test.ts +115 -0
- package/src/expressions/__tests__/utils.test.ts +44 -0
- package/src/expressions/evaluator-functions.ts +6 -6
- package/src/expressions/evaluator.ts +71 -67
- package/src/expressions/index.ts +4 -4
- package/src/expressions/parser.ts +102 -105
- package/src/expressions/types.ts +29 -21
- package/src/expressions/utils.ts +32 -21
- package/src/index.ts +13 -13
- package/src/logger/__tests__/consoleLogger.test.ts +46 -0
- package/src/logger/__tests__/noopLogger.test.ts +13 -0
- package/src/logger/__tests__/proxyLogger.test.ts +31 -0
- package/src/logger/__tests__/tapableLogger.test.ts +41 -0
- package/src/logger/consoleLogger.ts +9 -9
- package/src/logger/index.ts +5 -5
- package/src/logger/noopLogger.ts +1 -1
- package/src/logger/proxyLogger.ts +6 -6
- package/src/logger/tapableLogger.ts +7 -7
- package/src/logger/types.ts +2 -2
- package/src/player.ts +60 -58
- package/src/plugins/default-exp-plugin.ts +10 -10
- package/src/plugins/default-view-plugin.ts +29 -0
- package/src/plugins/flow-exp-plugin.ts +6 -6
- package/src/schema/__tests__/schema.test.ts +243 -0
- package/src/schema/index.ts +2 -2
- package/src/schema/schema.ts +24 -24
- package/src/schema/types.ts +4 -4
- package/src/string-resolver/__tests__/index.test.ts +361 -0
- package/src/string-resolver/index.ts +17 -17
- package/src/types.ts +17 -17
- package/src/utils/__tests__/replaceParams.test.ts +33 -0
- package/src/utils/index.ts +1 -1
- package/src/utils/replaceParams.ts +1 -1
- package/src/validator/__tests__/binding-map-splice.test.ts +53 -0
- package/src/validator/__tests__/validation-middleware.test.ts +127 -0
- package/src/validator/binding-map-splice.ts +5 -5
- package/src/validator/index.ts +4 -4
- package/src/validator/registry.ts +1 -1
- package/src/validator/types.ts +13 -13
- package/src/validator/validation-middleware.ts +15 -15
- package/src/view/__tests__/view.immutable.test.ts +269 -0
- package/src/view/__tests__/view.test.ts +959 -0
- package/src/view/builder/index.test.ts +69 -0
- package/src/view/builder/index.ts +3 -3
- package/src/view/index.ts +5 -5
- package/src/view/parser/__tests__/__snapshots__/parser.test.ts.snap +394 -0
- package/src/view/parser/__tests__/parser.test.ts +264 -0
- package/src/view/parser/index.ts +43 -33
- package/src/view/parser/types.ts +11 -11
- package/src/view/parser/utils.ts +5 -5
- package/src/view/plugins/__tests__/__snapshots__/template.test.ts.snap +278 -0
- package/src/view/plugins/__tests__/applicability.test.ts +265 -0
- package/src/view/plugins/__tests__/string.test.ts +122 -0
- package/src/view/plugins/__tests__/template.test.ts +724 -0
- package/src/view/plugins/applicability.ts +19 -19
- package/src/view/plugins/index.ts +4 -5
- package/src/view/plugins/options.ts +1 -1
- package/src/view/plugins/string-resolver.ts +22 -22
- package/src/view/plugins/switch.ts +22 -23
- package/src/view/plugins/template-plugin.ts +26 -27
- package/src/view/resolver/__tests__/dependencies.test.ts +321 -0
- package/src/view/resolver/__tests__/edgecases.test.ts +626 -0
- package/src/view/resolver/index.ts +42 -42
- package/src/view/resolver/types.ts +21 -20
- package/src/view/resolver/utils.ts +9 -9
- package/src/view/view.ts +32 -22
- package/types/binding/binding.d.ts +50 -0
- package/types/binding/index.d.ts +29 -0
- package/types/binding/resolver.d.ts +26 -0
- package/types/binding/utils.d.ts +12 -0
- package/types/binding-grammar/ast.d.ts +67 -0
- package/types/binding-grammar/custom/index.d.ts +4 -0
- package/types/binding-grammar/ebnf/index.d.ts +4 -0
- package/types/binding-grammar/ebnf/types.d.ts +75 -0
- package/types/binding-grammar/index.d.ts +5 -0
- package/types/binding-grammar/parsimmon/index.d.ts +4 -0
- package/types/controllers/constants/index.d.ts +45 -0
- package/types/controllers/constants/utils.d.ts +6 -0
- package/types/controllers/data/controller.d.ts +45 -0
- package/types/controllers/data/index.d.ts +2 -0
- package/types/controllers/data/utils.d.ts +14 -0
- package/types/controllers/flow/controller.d.ts +25 -0
- package/types/controllers/flow/flow.d.ts +50 -0
- package/types/controllers/flow/index.d.ts +3 -0
- package/types/controllers/index.d.ts +6 -0
- package/types/controllers/validation/binding-tracker.d.ts +32 -0
- package/types/controllers/validation/controller.d.ts +151 -0
- package/types/controllers/validation/index.d.ts +3 -0
- package/types/controllers/view/asset-transform.d.ts +19 -0
- package/types/controllers/view/controller.d.ts +37 -0
- package/types/controllers/view/index.d.ts +5 -0
- package/types/controllers/view/store.d.ts +20 -0
- package/types/controllers/view/types.d.ts +16 -0
- package/types/data/dependency-tracker.d.ts +49 -0
- package/types/data/index.d.ts +5 -0
- package/types/data/local-model.d.ts +16 -0
- package/types/data/model.d.ts +86 -0
- package/types/data/noop-model.d.ts +13 -0
- package/types/expressions/evaluator-functions.d.ts +15 -0
- package/types/expressions/evaluator.d.ts +52 -0
- package/types/expressions/index.d.ts +5 -0
- package/types/expressions/parser.d.ts +10 -0
- package/types/expressions/types.d.ts +144 -0
- package/types/expressions/utils.d.ts +12 -0
- package/types/index.d.ts +14 -0
- package/types/logger/consoleLogger.d.ts +17 -0
- package/types/logger/index.d.ts +6 -0
- package/types/logger/noopLogger.d.ts +10 -0
- package/types/logger/proxyLogger.d.ts +15 -0
- package/types/logger/tapableLogger.d.ts +23 -0
- package/types/logger/types.d.ts +6 -0
- package/types/player.d.ts +101 -0
- package/types/plugins/default-exp-plugin.d.ts +9 -0
- package/types/plugins/default-view-plugin.d.ts +9 -0
- package/types/plugins/flow-exp-plugin.d.ts +11 -0
- package/types/schema/index.d.ts +3 -0
- package/types/schema/schema.d.ts +36 -0
- package/types/schema/types.d.ts +38 -0
- package/types/string-resolver/index.d.ts +30 -0
- package/types/types.d.ts +73 -0
- package/types/utils/index.d.ts +2 -0
- package/types/utils/replaceParams.d.ts +9 -0
- package/types/validator/binding-map-splice.d.ts +10 -0
- package/types/validator/index.d.ts +5 -0
- package/types/validator/registry.d.ts +11 -0
- package/types/validator/types.d.ts +53 -0
- package/types/validator/validation-middleware.d.ts +36 -0
- package/types/view/builder/index.d.ts +35 -0
- package/types/view/index.d.ts +6 -0
- package/types/view/parser/index.d.ts +52 -0
- package/types/view/parser/types.d.ts +109 -0
- package/types/view/parser/utils.d.ts +6 -0
- package/types/view/plugins/applicability.d.ts +10 -0
- package/types/view/plugins/index.d.ts +5 -0
- package/types/view/plugins/options.d.ts +4 -0
- package/types/view/plugins/string-resolver.d.ts +13 -0
- package/types/view/plugins/switch.d.ts +14 -0
- package/types/view/plugins/template-plugin.d.ts +33 -0
- package/types/view/resolver/index.d.ts +73 -0
- package/types/view/resolver/types.d.ts +129 -0
- package/types/view/resolver/utils.d.ts +11 -0
- package/types/view/view.d.ts +37 -0
- package/dist/index.d.ts +0 -1814
- package/dist/player.dev.js +0 -11472
- package/dist/player.prod.js +0 -2
- package/src/view/plugins/plugin.ts +0 -21
package/src/types.ts
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import type { Flow, FlowResult } from
|
|
2
|
-
import type { BindingParser, BindingLike } from
|
|
3
|
-
import type { SchemaController } from
|
|
4
|
-
import type { ExpressionEvaluator } from
|
|
5
|
-
import type { Logger } from
|
|
1
|
+
import type { Flow, FlowResult } from "@player-ui/types";
|
|
2
|
+
import type { BindingParser, BindingLike } from "./binding";
|
|
3
|
+
import type { SchemaController } from "./schema";
|
|
4
|
+
import type { ExpressionEvaluator } from "./expressions";
|
|
5
|
+
import type { Logger } from "./logger";
|
|
6
6
|
import type {
|
|
7
7
|
ViewController,
|
|
8
8
|
DataController,
|
|
9
9
|
ValidationController,
|
|
10
10
|
FlowController,
|
|
11
|
-
} from
|
|
12
|
-
import type { ReadOnlyDataController } from
|
|
11
|
+
} from "./controllers";
|
|
12
|
+
import type { ReadOnlyDataController } from "./controllers/data/utils";
|
|
13
13
|
|
|
14
14
|
/** The status for a flow's execution state */
|
|
15
15
|
export type PlayerFlowStatus =
|
|
16
|
-
|
|
|
17
|
-
|
|
|
18
|
-
|
|
|
19
|
-
|
|
|
16
|
+
| "not-started"
|
|
17
|
+
| "in-progress"
|
|
18
|
+
| "completed"
|
|
19
|
+
| "error";
|
|
20
20
|
|
|
21
21
|
/** Common interface for the state of Player's flow execution */
|
|
22
22
|
export interface BaseFlowState<T extends PlayerFlowStatus> {
|
|
@@ -28,11 +28,11 @@ export interface BaseFlowState<T extends PlayerFlowStatus> {
|
|
|
28
28
|
}
|
|
29
29
|
|
|
30
30
|
/** The beginning state of Player, before it's seen a flow */
|
|
31
|
-
export type NotStartedState = BaseFlowState<
|
|
31
|
+
export type NotStartedState = BaseFlowState<"not-started">;
|
|
32
32
|
|
|
33
33
|
export const NOT_STARTED_STATE: NotStartedState = {
|
|
34
|
-
ref: Symbol(
|
|
35
|
-
status:
|
|
34
|
+
ref: Symbol("not-started"),
|
|
35
|
+
status: "not-started",
|
|
36
36
|
};
|
|
37
37
|
|
|
38
38
|
/** Shared properties for a flow in any state of execution (in-progress, completed successfully, or errored out) */
|
|
@@ -65,7 +65,7 @@ export interface ControllerState {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
/** A flow is currently executing */
|
|
68
|
-
export type InProgressState = BaseFlowState<
|
|
68
|
+
export type InProgressState = BaseFlowState<"in-progress"> &
|
|
69
69
|
PlayerFlowExecutionData & {
|
|
70
70
|
/** A promise that resolves when the flow is completed */
|
|
71
71
|
flowResult: Promise<FlowResult>;
|
|
@@ -83,7 +83,7 @@ export type InProgressState = BaseFlowState<'in-progress'> &
|
|
|
83
83
|
};
|
|
84
84
|
|
|
85
85
|
/** The flow completed properly */
|
|
86
|
-
export type CompletedState = BaseFlowState<
|
|
86
|
+
export type CompletedState = BaseFlowState<"completed"> &
|
|
87
87
|
PlayerFlowExecutionData &
|
|
88
88
|
FlowResult & {
|
|
89
89
|
/** Readonly Player controllers to provide Player functionality after the flow has ended */
|
|
@@ -94,7 +94,7 @@ export type CompletedState = BaseFlowState<'completed'> &
|
|
|
94
94
|
};
|
|
95
95
|
|
|
96
96
|
/** The flow finished but not successfully */
|
|
97
|
-
export type ErrorState = BaseFlowState<
|
|
97
|
+
export type ErrorState = BaseFlowState<"error"> & {
|
|
98
98
|
/** The currently executing flow */
|
|
99
99
|
flow: Flow;
|
|
100
100
|
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, test, expect } from "vitest";
|
|
2
|
+
import { replaceParams } from "..";
|
|
3
|
+
|
|
4
|
+
describe("Replace Params", () => {
|
|
5
|
+
test("should replace strings correctly", () => {
|
|
6
|
+
const actual = replaceParams(
|
|
7
|
+
"The desired length of this field is %desiredLength. The current length is %currentLength.",
|
|
8
|
+
{ desiredLength: 5, currentLength: 10 },
|
|
9
|
+
);
|
|
10
|
+
const expected =
|
|
11
|
+
"The desired length of this field is 5. The current length is 10.";
|
|
12
|
+
expect(actual).toBe(expected);
|
|
13
|
+
});
|
|
14
|
+
|
|
15
|
+
test("do not replace strings for no match", () => {
|
|
16
|
+
const actual = replaceParams(
|
|
17
|
+
"The desired length of this field is %desiredLength. The current length is %currentLength.",
|
|
18
|
+
{ desiredLength: 5 },
|
|
19
|
+
);
|
|
20
|
+
const expected =
|
|
21
|
+
"The desired length of this field is 5. The current length is %currentLength.";
|
|
22
|
+
expect(actual).toBe(expected);
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
test("do not replace strings for no templates", () => {
|
|
26
|
+
const actual = replaceParams(
|
|
27
|
+
"No template in this string. Ignore parameters",
|
|
28
|
+
{ desiredLength: 5, currentLength: 10 },
|
|
29
|
+
);
|
|
30
|
+
const expected = "No template in this string. Ignore parameters";
|
|
31
|
+
expect(actual).toBe(expected);
|
|
32
|
+
});
|
|
33
|
+
});
|
package/src/utils/index.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export * from
|
|
1
|
+
export * from "./replaceParams";
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { BindingParser } from "../../binding";
|
|
3
|
+
import { removeBindingAndChildrenFromMap } from "../binding-map-splice";
|
|
4
|
+
|
|
5
|
+
const parser = new BindingParser({
|
|
6
|
+
get: () => undefined,
|
|
7
|
+
set: () => undefined,
|
|
8
|
+
evaluate: () => undefined,
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
describe("removeBindingAndChildrenFromMap", () => {
|
|
12
|
+
it("removes a binding and its chidlren", () => {
|
|
13
|
+
const sourceMap = new Map([
|
|
14
|
+
[parser.parse("foo.bar.baz"), 1],
|
|
15
|
+
[parser.parse("foo.bar"), 2],
|
|
16
|
+
[parser.parse("foo.baz"), 3],
|
|
17
|
+
]);
|
|
18
|
+
|
|
19
|
+
const result = removeBindingAndChildrenFromMap(
|
|
20
|
+
sourceMap,
|
|
21
|
+
parser.parse("foo.bar"),
|
|
22
|
+
);
|
|
23
|
+
|
|
24
|
+
expect(result).toStrictEqual(new Map([[parser.parse("foo.baz"), 3]]));
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it("splices a binding and its children", () => {
|
|
28
|
+
const sourceMap = new Map([
|
|
29
|
+
[parser.parse("foo.bar.0.aaa"), 1],
|
|
30
|
+
[parser.parse("foo.bar.0.aab"), 2],
|
|
31
|
+
[parser.parse("foo.bar.1.bba"), 3],
|
|
32
|
+
[parser.parse("foo.bar.1.bbb"), 4],
|
|
33
|
+
[parser.parse("foo.bar.2.cca"), 5],
|
|
34
|
+
[parser.parse("foo.bar.2.ccb"), 6],
|
|
35
|
+
[parser.parse("foo.baz"), 3],
|
|
36
|
+
]);
|
|
37
|
+
|
|
38
|
+
const result = removeBindingAndChildrenFromMap(
|
|
39
|
+
sourceMap,
|
|
40
|
+
parser.parse("foo.bar.1"),
|
|
41
|
+
);
|
|
42
|
+
|
|
43
|
+
expect(result).toStrictEqual(
|
|
44
|
+
new Map([
|
|
45
|
+
[parser.parse("foo.bar.0.aaa"), 1],
|
|
46
|
+
[parser.parse("foo.bar.0.aab"), 2],
|
|
47
|
+
[parser.parse("foo.bar.1.cca"), 5],
|
|
48
|
+
[parser.parse("foo.bar.1.ccb"), 6],
|
|
49
|
+
[parser.parse("foo.baz"), 3],
|
|
50
|
+
]),
|
|
51
|
+
);
|
|
52
|
+
});
|
|
53
|
+
});
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import { describe, it, expect, test, beforeEach } from "vitest";
|
|
2
|
+
import { BindingParser } from "../../binding";
|
|
3
|
+
import type { DataModelImpl } from "../../data";
|
|
4
|
+
import { PipelinedDataModel, LocalModel } from "../../data";
|
|
5
|
+
import type { MiddlewareChecker } from "..";
|
|
6
|
+
import { ValidationMiddleware } from "..";
|
|
7
|
+
|
|
8
|
+
const parser = new BindingParser({
|
|
9
|
+
get: () => undefined,
|
|
10
|
+
set: () => undefined,
|
|
11
|
+
evaluate: () => undefined,
|
|
12
|
+
});
|
|
13
|
+
const foo = parser.parse("foo");
|
|
14
|
+
const bar = parser.parse("bar");
|
|
15
|
+
|
|
16
|
+
describe("middleware", () => {
|
|
17
|
+
/**
|
|
18
|
+
* a sample validator that checks for non-vaz values.
|
|
19
|
+
*/
|
|
20
|
+
const validator: MiddlewareChecker = (binding, model) => {
|
|
21
|
+
if (model.get(binding) === "baz") {
|
|
22
|
+
return {
|
|
23
|
+
severity: "error",
|
|
24
|
+
message: "Wrong Value",
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
let baseDataModel: DataModelImpl;
|
|
30
|
+
let dataModelWithMiddleware: ValidationMiddleware;
|
|
31
|
+
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
baseDataModel = new LocalModel();
|
|
34
|
+
dataModelWithMiddleware = new ValidationMiddleware(validator);
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("allows valid data to fall through", () => {
|
|
38
|
+
// Any valid value should fall through
|
|
39
|
+
dataModelWithMiddleware.set([[foo, "bar"]], undefined, baseDataModel);
|
|
40
|
+
expect(
|
|
41
|
+
dataModelWithMiddleware.get(foo, undefined, baseDataModel),
|
|
42
|
+
).toStrictEqual("bar");
|
|
43
|
+
expect(baseDataModel.get(foo)).toStrictEqual("bar");
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
it("catches invalid data", () => {
|
|
47
|
+
// Any invalid data should stay in the middleware's cache
|
|
48
|
+
dataModelWithMiddleware.set([[foo, "bar"]], undefined, baseDataModel);
|
|
49
|
+
dataModelWithMiddleware.set([[foo, "baz"]], undefined, baseDataModel);
|
|
50
|
+
expect(
|
|
51
|
+
dataModelWithMiddleware.get(foo, { includeInvalid: true }, baseDataModel),
|
|
52
|
+
).toStrictEqual("baz");
|
|
53
|
+
expect(baseDataModel.get(foo)).toStrictEqual("bar");
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
it("only returns updates for bindings set in the same transaction", () => {
|
|
57
|
+
// Setup the invalid data
|
|
58
|
+
const invalidUpdates = dataModelWithMiddleware.set(
|
|
59
|
+
[[foo, "baz"]],
|
|
60
|
+
undefined,
|
|
61
|
+
baseDataModel,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
expect(invalidUpdates).toMatchInlineSnapshot(`
|
|
65
|
+
[
|
|
66
|
+
{
|
|
67
|
+
"binding": BindingInstance {
|
|
68
|
+
"factory": [Function],
|
|
69
|
+
"joined": "foo",
|
|
70
|
+
"split": [
|
|
71
|
+
"foo",
|
|
72
|
+
],
|
|
73
|
+
},
|
|
74
|
+
"force": true,
|
|
75
|
+
"newValue": "baz",
|
|
76
|
+
"oldValue": "baz",
|
|
77
|
+
},
|
|
78
|
+
]
|
|
79
|
+
`);
|
|
80
|
+
|
|
81
|
+
// Set some unrelated data
|
|
82
|
+
const validUpdates = dataModelWithMiddleware.set(
|
|
83
|
+
[[bar, "baz"]],
|
|
84
|
+
undefined,
|
|
85
|
+
baseDataModel,
|
|
86
|
+
);
|
|
87
|
+
|
|
88
|
+
expect(validUpdates).toHaveLength(1);
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
test("merges invalid", () => {
|
|
93
|
+
const model = new PipelinedDataModel([
|
|
94
|
+
new LocalModel({
|
|
95
|
+
valid: true,
|
|
96
|
+
invalid: false,
|
|
97
|
+
}),
|
|
98
|
+
new ValidationMiddleware((binding, validationModel) => {
|
|
99
|
+
if (
|
|
100
|
+
binding.asString() === "invalid" &&
|
|
101
|
+
validationModel.get(binding) !== false
|
|
102
|
+
) {
|
|
103
|
+
return {
|
|
104
|
+
severity: "error",
|
|
105
|
+
message: "Nope",
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
}),
|
|
109
|
+
]);
|
|
110
|
+
|
|
111
|
+
expect(model.get(parser.parse(""))).toStrictEqual({
|
|
112
|
+
valid: true,
|
|
113
|
+
invalid: false,
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
model.set([[parser.parse("invalid"), true]]);
|
|
117
|
+
|
|
118
|
+
expect(model.get(parser.parse(""), { includeInvalid: false })).toStrictEqual({
|
|
119
|
+
valid: true,
|
|
120
|
+
invalid: false,
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
expect(model.get(parser.parse(""), { includeInvalid: true })).toStrictEqual({
|
|
124
|
+
valid: true,
|
|
125
|
+
invalid: true,
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BindingInstance } from
|
|
1
|
+
import type { BindingInstance } from "../binding";
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Remove a binding, and any children from from the map
|
|
@@ -9,7 +9,7 @@ import type { BindingInstance } from '../binding';
|
|
|
9
9
|
*/
|
|
10
10
|
export function removeBindingAndChildrenFromMap<T>(
|
|
11
11
|
sourceMap: Map<BindingInstance, T>,
|
|
12
|
-
binding: BindingInstance
|
|
12
|
+
binding: BindingInstance,
|
|
13
13
|
): Map<BindingInstance, T> {
|
|
14
14
|
const targetMap = new Map(sourceMap);
|
|
15
15
|
|
|
@@ -24,7 +24,7 @@ export function removeBindingAndChildrenFromMap<T>(
|
|
|
24
24
|
}
|
|
25
25
|
});
|
|
26
26
|
|
|
27
|
-
if (typeof property ===
|
|
27
|
+
if (typeof property === "number") {
|
|
28
28
|
// Splice out this index from the rest
|
|
29
29
|
|
|
30
30
|
// Order matters here b/c we are shifting items in the array
|
|
@@ -33,7 +33,7 @@ export function removeBindingAndChildrenFromMap<T>(
|
|
|
33
33
|
.filter((b) => {
|
|
34
34
|
if (parentBinding.contains(b)) {
|
|
35
35
|
const [childIndex] = b.relative(parentBinding);
|
|
36
|
-
return typeof childIndex ===
|
|
36
|
+
return typeof childIndex === "number" && childIndex > property;
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
return false;
|
|
@@ -46,7 +46,7 @@ export function removeBindingAndChildrenFromMap<T>(
|
|
|
46
46
|
|
|
47
47
|
const [childIndex, ...childPath] = trackedBinding.relative(parentBinding);
|
|
48
48
|
|
|
49
|
-
if (typeof childIndex ===
|
|
49
|
+
if (typeof childIndex === "number") {
|
|
50
50
|
const newSegments = [childIndex - 1, ...childPath];
|
|
51
51
|
const newChildBinding = parentBinding.descendent(newSegments);
|
|
52
52
|
targetMap.set(newChildBinding, targetMap.get(trackedBinding) as T);
|
package/src/validator/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from
|
|
2
|
-
export * from
|
|
3
|
-
export * from
|
|
4
|
-
export * from
|
|
1
|
+
export * from "./validation-middleware";
|
|
2
|
+
export * from "./types";
|
|
3
|
+
export * from "./registry";
|
|
4
|
+
export * from "./binding-map-splice";
|
package/src/validator/types.ts
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import type { Schema, Validation } from
|
|
1
|
+
import type { Schema, Validation } from "@player-ui/types";
|
|
2
2
|
|
|
3
|
-
import type { BindingInstance, BindingFactory } from
|
|
4
|
-
import type { DataModelWithParser } from
|
|
5
|
-
import type { ExpressionEvaluatorFunction } from
|
|
6
|
-
import type { Logger } from
|
|
7
|
-
import type { ConstantsProvider } from
|
|
3
|
+
import type { BindingInstance, BindingFactory } from "../binding";
|
|
4
|
+
import type { DataModelWithParser } from "../data";
|
|
5
|
+
import type { ExpressionEvaluatorFunction } from "../expressions";
|
|
6
|
+
import type { Logger } from "../logger";
|
|
7
|
+
import type { ConstantsProvider } from "../controllers";
|
|
8
8
|
|
|
9
9
|
interface BaseValidationResponse<T = Validation.Severity> {
|
|
10
10
|
/** The validation message to show to the user */
|
|
@@ -20,22 +20,22 @@ interface BaseValidationResponse<T = Validation.Severity> {
|
|
|
20
20
|
displayTarget?: Validation.DisplayTarget;
|
|
21
21
|
|
|
22
22
|
/** The blocking state of this validation */
|
|
23
|
-
blocking?: boolean |
|
|
23
|
+
blocking?: boolean | "once";
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export interface WarningValidationResponse
|
|
27
|
-
extends BaseValidationResponse<
|
|
27
|
+
extends BaseValidationResponse<"warning"> {
|
|
28
28
|
/** Warning validations can be dismissed without correcting the error */
|
|
29
29
|
dismiss?: () => void;
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
export type ErrorValidationResponse = BaseValidationResponse<
|
|
32
|
+
export type ErrorValidationResponse = BaseValidationResponse<"error">;
|
|
33
33
|
|
|
34
34
|
export type ValidationResponse =
|
|
35
35
|
| ErrorValidationResponse
|
|
36
36
|
| WarningValidationResponse;
|
|
37
37
|
|
|
38
|
-
type RequiredValidationKeys =
|
|
38
|
+
type RequiredValidationKeys = "severity" | "trigger";
|
|
39
39
|
|
|
40
40
|
export type ValidationObject = Validation.Reference &
|
|
41
41
|
Required<Pick<Validation.Reference, RequiredValidationKeys>>;
|
|
@@ -47,7 +47,7 @@ export type ValidationObjectWithHandler = ValidationObject & {
|
|
|
47
47
|
|
|
48
48
|
export interface ValidationProvider {
|
|
49
49
|
getValidationsForBinding?(
|
|
50
|
-
binding: BindingInstance
|
|
50
|
+
binding: BindingInstance,
|
|
51
51
|
): Array<ValidationObjectWithHandler> | undefined;
|
|
52
52
|
|
|
53
53
|
getValidationsForView?(): Array<ValidationObjectWithHandler> | undefined;
|
|
@@ -79,5 +79,5 @@ export interface ValidatorContext {
|
|
|
79
79
|
export type ValidatorFunction<Options = unknown> = (
|
|
80
80
|
context: ValidatorContext,
|
|
81
81
|
value: any,
|
|
82
|
-
options?: Options
|
|
83
|
-
) => Omit<BaseValidationResponse,
|
|
82
|
+
options?: Options,
|
|
83
|
+
) => Omit<BaseValidationResponse, "severity"> | undefined;
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
import { setIn } from
|
|
2
|
-
import type { BindingInstance } from
|
|
1
|
+
import { setIn } from "timm";
|
|
2
|
+
import type { BindingInstance } from "../binding";
|
|
3
3
|
import type {
|
|
4
4
|
BatchSetTransaction,
|
|
5
5
|
DataModelImpl,
|
|
6
6
|
DataModelOptions,
|
|
7
7
|
DataModelMiddleware,
|
|
8
8
|
Updates,
|
|
9
|
-
} from
|
|
10
|
-
import { toModel } from
|
|
11
|
-
import type { Logger } from
|
|
9
|
+
} from "../data";
|
|
10
|
+
import { toModel } from "../data";
|
|
11
|
+
import type { Logger } from "../logger";
|
|
12
12
|
|
|
13
|
-
import type { ValidationResponse } from
|
|
14
|
-
import { removeBindingAndChildrenFromMap } from
|
|
13
|
+
import type { ValidationResponse } from "./types";
|
|
14
|
+
import { removeBindingAndChildrenFromMap } from "./binding-map-splice";
|
|
15
15
|
|
|
16
16
|
/**
|
|
17
17
|
* A BindingInstance with an indicator of whether or not it's a strong binding
|
|
@@ -28,7 +28,7 @@ export type StrongOrWeakBinding = {
|
|
|
28
28
|
*/
|
|
29
29
|
export type MiddlewareChecker = (
|
|
30
30
|
binding: BindingInstance,
|
|
31
|
-
model: DataModelImpl
|
|
31
|
+
model: DataModelImpl,
|
|
32
32
|
) => ValidationResponse | Set<StrongOrWeakBinding> | undefined;
|
|
33
33
|
|
|
34
34
|
/**
|
|
@@ -47,7 +47,7 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
47
47
|
logger?: Logger;
|
|
48
48
|
/** Optional function to include data staged in shadowModel */
|
|
49
49
|
shouldIncludeInvalid?: (options?: DataModelOptions) => boolean;
|
|
50
|
-
}
|
|
50
|
+
},
|
|
51
51
|
) {
|
|
52
52
|
this.validator = validator;
|
|
53
53
|
this.shadowModelPaths = new Map();
|
|
@@ -58,7 +58,7 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
58
58
|
public set(
|
|
59
59
|
transaction: BatchSetTransaction,
|
|
60
60
|
options?: DataModelOptions,
|
|
61
|
-
next?: DataModelImpl
|
|
61
|
+
next?: DataModelImpl,
|
|
62
62
|
): Updates {
|
|
63
63
|
const asModel = toModel(this, { ...options, includeInvalid: true }, next);
|
|
64
64
|
const nextTransaction: BatchSetTransaction = [];
|
|
@@ -92,7 +92,7 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
92
92
|
this.logger?.debug(
|
|
93
93
|
`Invalid value for path: ${binding.asString()} - ${
|
|
94
94
|
validations.severity
|
|
95
|
-
} - ${validations.message}
|
|
95
|
+
} - ${validations.message}`,
|
|
96
96
|
);
|
|
97
97
|
}
|
|
98
98
|
});
|
|
@@ -102,7 +102,7 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
102
102
|
if (next && nextTransaction.length > 0) {
|
|
103
103
|
// defer clearing the shadow model to prevent validations that are run twice due to weak binding refs still needing the data
|
|
104
104
|
nextTransaction.forEach(([binding]) =>
|
|
105
|
-
this.shadowModelPaths.delete(binding)
|
|
105
|
+
this.shadowModelPaths.delete(binding),
|
|
106
106
|
);
|
|
107
107
|
const result = next.set(nextTransaction, options);
|
|
108
108
|
if (invalidBindings.length === 0) {
|
|
@@ -127,7 +127,7 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
127
127
|
public get(
|
|
128
128
|
binding: BindingInstance,
|
|
129
129
|
options?: DataModelOptions,
|
|
130
|
-
next?: DataModelImpl
|
|
130
|
+
next?: DataModelImpl,
|
|
131
131
|
) {
|
|
132
132
|
let val = next?.get(binding, options);
|
|
133
133
|
|
|
@@ -154,11 +154,11 @@ export class ValidationMiddleware implements DataModelMiddleware {
|
|
|
154
154
|
public delete(
|
|
155
155
|
binding: BindingInstance,
|
|
156
156
|
options?: DataModelOptions,
|
|
157
|
-
next?: DataModelImpl
|
|
157
|
+
next?: DataModelImpl,
|
|
158
158
|
) {
|
|
159
159
|
this.shadowModelPaths = removeBindingAndChildrenFromMap(
|
|
160
160
|
this.shadowModelPaths,
|
|
161
|
-
binding
|
|
161
|
+
binding,
|
|
162
162
|
);
|
|
163
163
|
|
|
164
164
|
return next?.delete(binding, options);
|