@player-ui/player 0.3.0-next.2 → 0.3.0-next.4
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/index.cjs.js +4128 -891
- package/dist/index.d.ts +1227 -50
- package/dist/index.esm.js +4065 -836
- package/package.json +9 -15
- package/src/binding/binding.ts +108 -0
- package/src/binding/index.ts +188 -0
- package/src/binding/resolver.ts +157 -0
- package/src/binding/utils.ts +51 -0
- package/src/binding-grammar/ast.ts +113 -0
- package/src/binding-grammar/custom/index.ts +304 -0
- package/src/binding-grammar/ebnf/binding.ebnf +22 -0
- package/src/binding-grammar/ebnf/index.ts +186 -0
- package/src/binding-grammar/ebnf/types.ts +104 -0
- package/src/binding-grammar/index.ts +4 -0
- package/src/binding-grammar/parsimmon/index.ts +78 -0
- package/src/controllers/constants/index.ts +85 -0
- package/src/controllers/constants/utils.ts +37 -0
- package/src/{data.ts → controllers/data.ts} +6 -6
- package/src/controllers/flow/controller.ts +95 -0
- package/src/controllers/flow/flow.ts +205 -0
- package/src/controllers/flow/index.ts +2 -0
- package/src/controllers/index.ts +5 -0
- package/src/{validation → controllers/validation}/binding-tracker.ts +5 -5
- package/src/{validation → controllers/validation}/controller.ts +15 -14
- package/src/{validation → controllers/validation}/index.ts +0 -0
- package/src/{view → controllers/view}/asset-transform.ts +2 -3
- package/src/{view → controllers/view}/controller.ts +9 -8
- package/src/controllers/view/index.ts +4 -0
- package/src/{view → controllers/view}/store.ts +0 -0
- package/src/{view → controllers/view}/types.ts +2 -1
- package/src/data/dependency-tracker.ts +187 -0
- package/src/data/index.ts +4 -0
- package/src/data/local-model.ts +41 -0
- package/src/data/model.ts +216 -0
- package/src/data/noop-model.ts +18 -0
- package/src/expressions/evaluator-functions.ts +29 -0
- package/src/expressions/evaluator.ts +405 -0
- package/src/expressions/index.ts +3 -0
- package/src/expressions/parser.ts +889 -0
- package/src/expressions/types.ts +200 -0
- package/src/expressions/utils.ts +8 -0
- package/src/index.ts +9 -12
- package/src/logger/consoleLogger.ts +49 -0
- package/src/logger/index.ts +5 -0
- package/src/logger/noopLogger.ts +13 -0
- package/src/logger/proxyLogger.ts +25 -0
- package/src/logger/tapableLogger.ts +38 -0
- package/src/logger/types.ts +6 -0
- package/src/player.ts +21 -18
- package/src/plugins/flow-exp-plugin.ts +2 -3
- package/src/schema/index.ts +2 -0
- package/src/schema/schema.ts +220 -0
- package/src/schema/types.ts +60 -0
- package/src/string-resolver/index.ts +188 -0
- package/src/types.ts +11 -13
- package/src/utils/index.ts +1 -0
- package/src/utils/replaceParams.ts +17 -0
- package/src/validator/index.ts +3 -0
- package/src/validator/registry.ts +20 -0
- package/src/validator/types.ts +75 -0
- package/src/validator/validation-middleware.ts +114 -0
- package/src/view/builder/index.ts +81 -0
- package/src/view/index.ts +5 -4
- package/src/view/parser/index.ts +318 -0
- package/src/view/parser/types.ts +141 -0
- package/src/view/plugins/applicability.ts +78 -0
- package/src/view/plugins/index.ts +5 -0
- package/src/view/plugins/options.ts +4 -0
- package/src/view/plugins/plugin.ts +21 -0
- package/src/view/plugins/string-resolver.ts +149 -0
- package/src/view/plugins/switch.ts +120 -0
- package/src/view/plugins/template-plugin.ts +172 -0
- package/src/view/resolver/index.ts +397 -0
- package/src/view/resolver/types.ts +161 -0
- package/src/view/resolver/utils.ts +57 -0
- package/src/view/view.ts +149 -0
- package/src/utils/desc.d.ts +0 -2
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
import { LocalModel } from '../../data';
|
|
2
|
+
import { BindingInstance } from '../../binding';
|
|
3
|
+
import { objectToBatchSet } from './utils';
|
|
4
|
+
|
|
5
|
+
export interface ConstantsProvider {
|
|
6
|
+
/**
|
|
7
|
+
* Function to add constants to the providers store
|
|
8
|
+
* - @param data values to add to the constants store
|
|
9
|
+
*/
|
|
10
|
+
addConstants(data: Record<string, any>, namespace: string): void;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Function to retreive constants from the providers store
|
|
14
|
+
* - @param key Key used for the store access
|
|
15
|
+
* - @param namespace namespace values were loaded under (defined in the plugin)
|
|
16
|
+
* - @param fallback Optional - if key doesn't exist in namespace what to return (will return unknown if not provided)
|
|
17
|
+
*/
|
|
18
|
+
getConstants(key: any, namespace: string, fallback?: any): any;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Function to set values to temporarily override certain keys in the perminant store
|
|
22
|
+
* - @param data values to override store with
|
|
23
|
+
* - @param namespace namespace to override
|
|
24
|
+
*/
|
|
25
|
+
setTemporaryValues(data: any, namespace: string): void;
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Clears any temporary values that were previously set
|
|
29
|
+
*/
|
|
30
|
+
clearTemporaryValues(): void;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Key/Value store for constants and context for Player
|
|
35
|
+
*/
|
|
36
|
+
export class ConstantsController implements ConstantsProvider {
|
|
37
|
+
/**
|
|
38
|
+
* Data store is basically a map of namespaces to DataModels to provide some data isolation
|
|
39
|
+
*/
|
|
40
|
+
private store: Map<string, LocalModel>;
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Separate store for temporary flow specific overrides.
|
|
44
|
+
* They are kept in a separate data model to make clearing it easier between flows
|
|
45
|
+
* and so there is no confusion on what is static and what is temporary
|
|
46
|
+
*/
|
|
47
|
+
private tempStore: Map<string, LocalModel>;
|
|
48
|
+
|
|
49
|
+
constructor() {
|
|
50
|
+
this.store = new Map();
|
|
51
|
+
this.tempStore = new Map();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
addConstants(data: any, namespace: string): void {
|
|
55
|
+
if (this.store.has(namespace)) {
|
|
56
|
+
this.store.get(namespace)?.set(objectToBatchSet(data));
|
|
57
|
+
} else {
|
|
58
|
+
this.store.set(namespace, new LocalModel(data));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
getConstants(key: string, namespace: string, fallback?: any): any {
|
|
63
|
+
const path = new BindingInstance(key);
|
|
64
|
+
|
|
65
|
+
return (
|
|
66
|
+
this.tempStore.get(namespace)?.get(path) ??
|
|
67
|
+
this.store.get(namespace)?.get(path) ??
|
|
68
|
+
fallback
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
setTemporaryValues(data: any, namespace: string): void {
|
|
73
|
+
if (this.tempStore.has(namespace)) {
|
|
74
|
+
this.tempStore.get(namespace)?.set(objectToBatchSet(data));
|
|
75
|
+
} else {
|
|
76
|
+
this.tempStore.set(namespace, new LocalModel(data));
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
clearTemporaryValues(): void {
|
|
81
|
+
this.tempStore.forEach((value: LocalModel) => {
|
|
82
|
+
value.reset();
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { BindingInstance } from '../../binding';
|
|
2
|
+
|
|
3
|
+
/** Recursively flattens a nested object to be an object of depth 1 with keys being the full path in the orginal object */
|
|
4
|
+
export function flatten(obj: any, roots: [string][] = [], sep = '.'): any {
|
|
5
|
+
return (
|
|
6
|
+
Object
|
|
7
|
+
// find props of given object
|
|
8
|
+
.keys(obj)
|
|
9
|
+
// return an object by iterating props
|
|
10
|
+
.reduce(
|
|
11
|
+
(memo, prop) => ({
|
|
12
|
+
// create a new object
|
|
13
|
+
|
|
14
|
+
// include previously returned object
|
|
15
|
+
...memo,
|
|
16
|
+
...(Object.prototype.toString.call(obj[prop]) === '[object Object]'
|
|
17
|
+
? // keep working if value is an object
|
|
18
|
+
flatten(obj[prop], roots.concat([prop]))
|
|
19
|
+
: // include current prop and value and prefix prop with the roots
|
|
20
|
+
{ [roots.concat([prop]).join(sep)]: obj[prop] }),
|
|
21
|
+
}),
|
|
22
|
+
{}
|
|
23
|
+
)
|
|
24
|
+
);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/** Converts an object into a list of binding/value tuples to use with a LocalModel object */
|
|
28
|
+
export function objectToBatchSet(obj: any): [BindingInstance, any][] {
|
|
29
|
+
const flattenedObj = flatten(obj);
|
|
30
|
+
const batchTxn: [BindingInstance, any][] = [];
|
|
31
|
+
|
|
32
|
+
Object.keys(flattenedObj).forEach((key) => {
|
|
33
|
+
batchTxn.push([new BindingInstance(key), flattenedObj[key]]);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
return batchTxn;
|
|
37
|
+
}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
import { SyncHook, SyncWaterfallHook, SyncBailHook } from 'tapable-ts';
|
|
2
|
-
import type { Logger } from '@player-ui/logger';
|
|
3
2
|
import { omit, removeAt } from 'timm';
|
|
4
3
|
import { dequal } from 'dequal';
|
|
5
|
-
import type {
|
|
6
|
-
import {
|
|
4
|
+
import type { Logger } from '../logger';
|
|
5
|
+
import type { BindingParser, BindingLike } from '../binding';
|
|
6
|
+
import { BindingInstance } from '../binding';
|
|
7
7
|
import type {
|
|
8
8
|
BatchSetTransaction,
|
|
9
9
|
Updates,
|
|
@@ -11,9 +11,9 @@ import type {
|
|
|
11
11
|
DataModelWithParser,
|
|
12
12
|
DataPipeline,
|
|
13
13
|
DataModelMiddleware,
|
|
14
|
-
} from '
|
|
15
|
-
import { PipelinedDataModel, LocalModel } from '
|
|
16
|
-
import type { RawSetTransaction } from '
|
|
14
|
+
} from '../data';
|
|
15
|
+
import { PipelinedDataModel, LocalModel } from '../data';
|
|
16
|
+
import type { RawSetTransaction } from '../types';
|
|
17
17
|
|
|
18
18
|
/** The orchestrator for player data */
|
|
19
19
|
export class DataController implements DataModelWithParser<DataModelOptions> {
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { SyncHook } from 'tapable-ts';
|
|
2
|
+
import type { Navigation, NavigationFlowEndState } from '@player-ui/types';
|
|
3
|
+
import type { Logger } from '../../logger';
|
|
4
|
+
import type { NamedState, TransitionOptions } from './flow';
|
|
5
|
+
import { FlowInstance } from './flow';
|
|
6
|
+
|
|
7
|
+
/** A manager for the navigation section of a Content blob */
|
|
8
|
+
export class FlowController {
|
|
9
|
+
public readonly hooks = {
|
|
10
|
+
flow: new SyncHook<[FlowInstance]>(),
|
|
11
|
+
};
|
|
12
|
+
|
|
13
|
+
private readonly log?: Logger;
|
|
14
|
+
private navigation: Navigation;
|
|
15
|
+
private navStack: FlowInstance[];
|
|
16
|
+
public current?: FlowInstance;
|
|
17
|
+
|
|
18
|
+
constructor(
|
|
19
|
+
navigation: Navigation,
|
|
20
|
+
options?: {
|
|
21
|
+
/** A logger instance to use */
|
|
22
|
+
logger?: Logger;
|
|
23
|
+
}
|
|
24
|
+
) {
|
|
25
|
+
this.navigation = navigation;
|
|
26
|
+
this.navStack = [];
|
|
27
|
+
this.log = options?.logger;
|
|
28
|
+
|
|
29
|
+
this.start = this.start.bind(this);
|
|
30
|
+
this.run = this.run.bind(this);
|
|
31
|
+
this.transition = this.transition.bind(this);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Navigate to another state in the state-machine */
|
|
35
|
+
public transition(stateTransition: string, options?: TransitionOptions) {
|
|
36
|
+
if (this.current === undefined) {
|
|
37
|
+
throw new Error('Not currently in a flow. Cannot transition.');
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
this.current.transition(stateTransition, options);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
private async addNewFlow(flow: FlowInstance) {
|
|
44
|
+
this.navStack.push(flow);
|
|
45
|
+
this.current = flow;
|
|
46
|
+
flow.hooks.transition.tap(
|
|
47
|
+
'flow-controller',
|
|
48
|
+
async (_oldState, newState: NamedState) => {
|
|
49
|
+
if (newState.value.state_type === 'FLOW') {
|
|
50
|
+
this.log?.debug(`Got FLOW state. Loading flow ${newState.value.ref}`);
|
|
51
|
+
const endState = await this.run(newState.value.ref);
|
|
52
|
+
this.log?.debug(`Flow ended. Using outcome: ${endState.outcome}`);
|
|
53
|
+
flow.transition(endState.outcome);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
);
|
|
57
|
+
this.hooks.flow.call(flow);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
private async run(startState: string): Promise<NavigationFlowEndState> {
|
|
61
|
+
if (!Object.prototype.hasOwnProperty.call(this.navigation, startState)) {
|
|
62
|
+
return Promise.reject(new Error(`No flow defined for: ${startState}`));
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
const startFlow = this.navigation[startState];
|
|
66
|
+
|
|
67
|
+
if (startFlow === null || typeof startFlow !== 'object') {
|
|
68
|
+
return Promise.reject(
|
|
69
|
+
new Error(`Flow: ${startState} needs to be an object`)
|
|
70
|
+
);
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
this.log?.debug(`Starting flow: ${startState}`);
|
|
74
|
+
|
|
75
|
+
const flow = new FlowInstance(startState, startFlow, { logger: this.log });
|
|
76
|
+
this.addNewFlow(flow);
|
|
77
|
+
const end = await flow.start();
|
|
78
|
+
this.navStack.pop();
|
|
79
|
+
|
|
80
|
+
if (this.navStack.length > 0) {
|
|
81
|
+
const firstItem = 0;
|
|
82
|
+
this.current = this.navStack[firstItem];
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
return end;
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
public async start(): Promise<NavigationFlowEndState> {
|
|
89
|
+
if (!this.navigation.BEGIN) {
|
|
90
|
+
return Promise.reject(new Error('Must supply a BEGIN state'));
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
return this.run(this.navigation.BEGIN);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
@@ -0,0 +1,205 @@
|
|
|
1
|
+
import { SyncBailHook, SyncHook, SyncWaterfallHook } from 'tapable-ts';
|
|
2
|
+
import type { DeferredPromise } from 'p-defer';
|
|
3
|
+
import defer from 'p-defer';
|
|
4
|
+
import type {
|
|
5
|
+
NavigationFlow,
|
|
6
|
+
NavigationFlowState,
|
|
7
|
+
NavigationFlowEndState,
|
|
8
|
+
} from '@player-ui/types';
|
|
9
|
+
import type { Logger } from '../../logger';
|
|
10
|
+
|
|
11
|
+
export interface NamedState {
|
|
12
|
+
/** The name of the navigation node */
|
|
13
|
+
name: string;
|
|
14
|
+
|
|
15
|
+
/** The nav node */
|
|
16
|
+
value: NavigationFlowState;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface TransitionOptions {
|
|
20
|
+
/** Ignore any validations or other signals preventing the transition from taking place */
|
|
21
|
+
force?: boolean;
|
|
22
|
+
}
|
|
23
|
+
export type TransitionFunction = (
|
|
24
|
+
name: string,
|
|
25
|
+
options?: TransitionOptions
|
|
26
|
+
) => void;
|
|
27
|
+
|
|
28
|
+
/** The Content navigation state machine */
|
|
29
|
+
export class FlowInstance {
|
|
30
|
+
private flow: NavigationFlow;
|
|
31
|
+
private log?: Logger;
|
|
32
|
+
private history: string[];
|
|
33
|
+
private flowPromise?: DeferredPromise<NavigationFlowEndState>;
|
|
34
|
+
public readonly id: string;
|
|
35
|
+
public currentState?: NamedState;
|
|
36
|
+
public readonly hooks = {
|
|
37
|
+
beforeStart: new SyncBailHook<[NavigationFlow], NavigationFlow>(),
|
|
38
|
+
|
|
39
|
+
/** A callback when the onStart node was present */
|
|
40
|
+
onStart: new SyncHook<[any]>(),
|
|
41
|
+
|
|
42
|
+
/** A callback when the onEnd node was present */
|
|
43
|
+
onEnd: new SyncHook<[any]>(),
|
|
44
|
+
|
|
45
|
+
/** A hook to intercept and block a transition */
|
|
46
|
+
skipTransition: new SyncBailHook<
|
|
47
|
+
[NamedState | undefined],
|
|
48
|
+
boolean | undefined
|
|
49
|
+
>(),
|
|
50
|
+
|
|
51
|
+
/** A chance to manipulate the flow-node used to calculate the given transition used */
|
|
52
|
+
beforeTransition: new SyncWaterfallHook<
|
|
53
|
+
[Exclude<NavigationFlowState, NavigationFlowEndState>, string]
|
|
54
|
+
>(),
|
|
55
|
+
|
|
56
|
+
/** A chance to manipulate the flow-node calculated after a transition */
|
|
57
|
+
resolveTransitionNode: new SyncWaterfallHook<[NavigationFlowState]>(),
|
|
58
|
+
|
|
59
|
+
/** A callback when a transition from 1 state to another was made */
|
|
60
|
+
transition: new SyncHook<[NamedState | undefined, NamedState]>(),
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
constructor(
|
|
64
|
+
id: string,
|
|
65
|
+
flow: NavigationFlow,
|
|
66
|
+
options?: {
|
|
67
|
+
/** Logger instance to use */
|
|
68
|
+
logger?: Logger;
|
|
69
|
+
}
|
|
70
|
+
) {
|
|
71
|
+
this.id = id;
|
|
72
|
+
this.flow = flow;
|
|
73
|
+
this.log = options?.logger;
|
|
74
|
+
this.history = [];
|
|
75
|
+
|
|
76
|
+
this.hooks.transition.tap(
|
|
77
|
+
'startPromise',
|
|
78
|
+
async (_oldState, nextState: NamedState) => {
|
|
79
|
+
const newState = nextState.value;
|
|
80
|
+
|
|
81
|
+
if (this.flowPromise && newState.state_type === 'END') {
|
|
82
|
+
this.flowPromise.resolve(newState);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/** Start the state machine */
|
|
89
|
+
public async start(): Promise<NavigationFlowEndState> {
|
|
90
|
+
if (this.flowPromise) {
|
|
91
|
+
this.log?.warn('Already called start for flow');
|
|
92
|
+
|
|
93
|
+
return this.flowPromise.promise;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
this.flow = this.hooks.beforeStart.call(this.flow) || this.flow;
|
|
97
|
+
|
|
98
|
+
if (this.flow.onStart) {
|
|
99
|
+
this.hooks.onStart.call(this.flow.onStart);
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const initialState = this.flow.startState;
|
|
103
|
+
|
|
104
|
+
if (!initialState) {
|
|
105
|
+
return Promise.reject(new Error("No 'startState' defined for flow"));
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
this.flowPromise = defer();
|
|
109
|
+
this.pushHistory(initialState);
|
|
110
|
+
|
|
111
|
+
return this.flowPromise.promise;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
public transition(transitionValue: string, options?: TransitionOptions) {
|
|
115
|
+
if (this.currentState?.value.state_type === 'END') {
|
|
116
|
+
this.log?.warn(
|
|
117
|
+
`Skipping transition using ${transitionValue}. Already at and END state`
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
if (this.currentState === undefined) {
|
|
124
|
+
throw new Error("Cannot transition when there's no current state");
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
if (options?.force) {
|
|
128
|
+
this.log?.debug(`Forced transition. Skipping validation checks`);
|
|
129
|
+
} else {
|
|
130
|
+
const skipTransition = this.hooks.skipTransition.call(this.currentState);
|
|
131
|
+
|
|
132
|
+
if (skipTransition) {
|
|
133
|
+
this.log?.debug(
|
|
134
|
+
`Skipping transition from ${this.currentState} b/c hook told us to`
|
|
135
|
+
);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
const state = this.hooks.beforeTransition.call(
|
|
141
|
+
this.currentState.value,
|
|
142
|
+
transitionValue
|
|
143
|
+
);
|
|
144
|
+
|
|
145
|
+
if (!('transitions' in state)) {
|
|
146
|
+
throw new Error(`No transitions defined for ${this.currentState.value}`);
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const { transitions } = state;
|
|
150
|
+
const nextState = transitions[transitionValue] || transitions['*'];
|
|
151
|
+
|
|
152
|
+
if (nextState === undefined) {
|
|
153
|
+
this.log?.warn(
|
|
154
|
+
`No transition from ${this.currentState.name} using ${transitionValue} or *`
|
|
155
|
+
);
|
|
156
|
+
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
this.log?.debug(
|
|
161
|
+
`Transitioning from ${this.currentState.name} to ${nextState} using ${transitionValue} `
|
|
162
|
+
);
|
|
163
|
+
|
|
164
|
+
return this.pushHistory(nextState, options);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private pushHistory(stateName: string, options?: TransitionOptions) {
|
|
168
|
+
if (!Object.prototype.hasOwnProperty.call(this.flow, stateName)) {
|
|
169
|
+
throw new Error(`No flow definition for: ${stateName} was found.`);
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
let nextState = this.flow[stateName];
|
|
173
|
+
|
|
174
|
+
if (
|
|
175
|
+
!this.flow[stateName] ||
|
|
176
|
+
typeof nextState !== 'object' ||
|
|
177
|
+
!('state_type' in nextState)
|
|
178
|
+
) {
|
|
179
|
+
this.log?.error(`Flow doesn't contain any states named: ${stateName}`);
|
|
180
|
+
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
const prevState = this.currentState;
|
|
185
|
+
|
|
186
|
+
nextState = this.hooks.resolveTransitionNode.call(nextState);
|
|
187
|
+
|
|
188
|
+
const newCurrentState = {
|
|
189
|
+
name: stateName,
|
|
190
|
+
value: nextState,
|
|
191
|
+
} as NamedState;
|
|
192
|
+
this.currentState = newCurrentState;
|
|
193
|
+
this.history.push(stateName);
|
|
194
|
+
|
|
195
|
+
// If the new state is an END state call the `onEnd` if it exists
|
|
196
|
+
|
|
197
|
+
if (newCurrentState.value.state_type === 'END' && this.flow.onEnd) {
|
|
198
|
+
this.hooks.onEnd.call(this.flow.onEnd);
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
this.hooks.transition.call(prevState, {
|
|
202
|
+
...newCurrentState,
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
}
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
import type {
|
|
1
|
+
import type { Validation } from '@player-ui/types';
|
|
2
|
+
import type { ViewPlugin, Resolver, Node, ViewInstance } from '../../view';
|
|
2
3
|
import type {
|
|
3
4
|
BindingInstance,
|
|
4
5
|
BindingLike,
|
|
5
6
|
BindingFactory,
|
|
6
|
-
} from '
|
|
7
|
-
import { isBinding } from '
|
|
8
|
-
import type { ValidationResponse } from '
|
|
9
|
-
import type { Validation } from '@player-ui/types';
|
|
7
|
+
} from '../../binding';
|
|
8
|
+
import { isBinding } from '../../binding';
|
|
9
|
+
import type { ValidationResponse } from '../../validator';
|
|
10
10
|
|
|
11
11
|
const CONTEXT = 'validation-binding-tracker';
|
|
12
12
|
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import type { BindingInstance, BindingFactory } from '@player-ui/binding';
|
|
2
|
-
import { isBinding } from '@player-ui/binding';
|
|
3
|
-
import type { DataModelWithParser, DataModelMiddleware } from '@player-ui/data';
|
|
4
|
-
import type { SchemaController } from '@player-ui/schema';
|
|
5
1
|
import type { Validation } from '@player-ui/types';
|
|
2
|
+
import { SyncHook, SyncWaterfallHook } from 'tapable-ts';
|
|
3
|
+
|
|
4
|
+
import type { BindingInstance, BindingFactory } from '../../binding';
|
|
5
|
+
import { isBinding } from '../../binding';
|
|
6
|
+
import type { DataModelWithParser, DataModelMiddleware } from '../../data';
|
|
7
|
+
import type { SchemaController } from '../../schema';
|
|
6
8
|
import type {
|
|
7
9
|
ErrorValidationResponse,
|
|
8
10
|
ValidationObject,
|
|
@@ -10,19 +12,18 @@ import type {
|
|
|
10
12
|
ValidationProvider,
|
|
11
13
|
ValidationResponse,
|
|
12
14
|
WarningValidationResponse,
|
|
13
|
-
} from '
|
|
14
|
-
import { ValidationMiddleware, ValidatorRegistry } from '
|
|
15
|
-
import type { Logger } from '
|
|
16
|
-
import { ProxyLogger } from '
|
|
17
|
-
import type { Resolve, ViewInstance } from '
|
|
18
|
-
import { caresAboutDataChanges } from '
|
|
19
|
-
import { replaceParams } from '
|
|
20
|
-
import { resolveDataRefs } from '
|
|
15
|
+
} from '../../validator';
|
|
16
|
+
import { ValidationMiddleware, ValidatorRegistry } from '../../validator';
|
|
17
|
+
import type { Logger } from '../../logger';
|
|
18
|
+
import { ProxyLogger } from '../../logger';
|
|
19
|
+
import type { Resolve, ViewInstance } from '../../view';
|
|
20
|
+
import { caresAboutDataChanges } from '../../view';
|
|
21
|
+
import { replaceParams } from '../../utils';
|
|
22
|
+
import { resolveDataRefs } from '../../string-resolver';
|
|
21
23
|
import type {
|
|
22
24
|
ExpressionEvaluatorOptions,
|
|
23
25
|
ExpressionType,
|
|
24
|
-
} from '
|
|
25
|
-
import { SyncHook, SyncWaterfallHook } from 'tapable-ts';
|
|
26
|
+
} from '../../expressions';
|
|
26
27
|
import type { BindingTracker } from './binding-tracker';
|
|
27
28
|
import { ValidationBindingTrackerViewPlugin } from './binding-tracker';
|
|
28
29
|
|
|
File without changes
|
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import type { Node } from '
|
|
2
|
-
import { NodeType } from '
|
|
1
|
+
import type { Node } from '../../view';
|
|
2
|
+
import { NodeType } from '../../view';
|
|
3
3
|
import { LocalStateStore } from './store';
|
|
4
4
|
import type { TransformRegistry } from './types';
|
|
5
5
|
import type { ViewController } from './controller';
|
|
6
|
-
import { PlayerPlugin } from '..';
|
|
7
6
|
|
|
8
7
|
/** Traverse up the nodes until the target is found */
|
|
9
8
|
function findUp(node: Node.Node, target: Node.Node): boolean {
|
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import { SyncHook, SyncWaterfallHook } from 'tapable-ts';
|
|
2
|
-
import type { Resolve } from '@player-ui/view';
|
|
3
|
-
import { ViewInstance } from '@player-ui/view';
|
|
4
|
-
import type { Logger } from '@player-ui/logger';
|
|
5
|
-
import type { FlowInstance, FlowController } from '@player-ui/flow';
|
|
6
|
-
import type { View, NavigationFlowViewState } from '@player-ui/types';
|
|
7
|
-
import { resolveDataRefsInString } from '@player-ui/string-resolver';
|
|
8
|
-
import { Registry } from '@player-ui/partial-match-registry';
|
|
9
2
|
import queueMicrotask from 'queue-microtask';
|
|
3
|
+
import { Registry } from '@player-ui/partial-match-registry';
|
|
4
|
+
import type { View, NavigationFlowViewState } from '@player-ui/types';
|
|
5
|
+
|
|
6
|
+
import { resolveDataRefsInString } from '../../string-resolver';
|
|
7
|
+
import type { Resolve } from '../../view';
|
|
8
|
+
import { ViewInstance } from '../../view';
|
|
9
|
+
import type { Logger } from '../../logger';
|
|
10
|
+
import type { FlowInstance, FlowController } from '../flow';
|
|
10
11
|
import type { DataController } from '../data';
|
|
11
12
|
import { AssetTransformCorePlugin } from './asset-transform';
|
|
12
13
|
import type { TransformRegistry } from './types';
|
|
13
|
-
import type { BindingInstance } from '
|
|
14
|
+
import type { BindingInstance } from '../../binding';
|
|
14
15
|
|
|
15
16
|
export interface ViewControllerOptions {
|
|
16
17
|
/** Where to get data from */
|
|
File without changes
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Asset } from '@player-ui/types';
|
|
2
|
-
import type { Resolve, Node } from '@player-ui/view';
|
|
3
2
|
import type { Registry } from '@player-ui/partial-match-registry';
|
|
3
|
+
|
|
4
|
+
import type { Resolve, Node } from '../../view';
|
|
4
5
|
import type { Store } from './store';
|
|
5
6
|
|
|
6
7
|
/** Transform function that is ran on the Asset before it's resolved */
|