@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.
Files changed (214) hide show
  1. package/dist/Player.native.js +11630 -0
  2. package/dist/Player.native.js.map +1 -0
  3. package/dist/cjs/index.cjs +5626 -0
  4. package/dist/cjs/index.cjs.map +1 -0
  5. package/dist/{index.esm.js → index.legacy-esm.js} +2044 -1667
  6. package/dist/{index.cjs.js → index.mjs} +2052 -1761
  7. package/dist/index.mjs.map +1 -0
  8. package/package.json +29 -63
  9. package/src/__tests__/data.test.ts +498 -0
  10. package/src/__tests__/flow.test.ts +312 -0
  11. package/src/__tests__/helpers/action-exp.plugin.ts +22 -0
  12. package/src/__tests__/helpers/actions.flow.ts +67 -0
  13. package/src/__tests__/helpers/binding.plugin.ts +125 -0
  14. package/src/__tests__/helpers/expression.plugin.ts +88 -0
  15. package/src/__tests__/helpers/transform-plugin.ts +19 -0
  16. package/src/__tests__/helpers/validation.flow.ts +56 -0
  17. package/src/__tests__/player.test.ts +597 -0
  18. package/src/__tests__/string-resolver.test.ts +186 -0
  19. package/src/__tests__/validation.test.ts +3555 -0
  20. package/src/__tests__/view.test.ts +715 -0
  21. package/src/binding/__tests__/binding.test.ts +113 -0
  22. package/src/binding/__tests__/index.test.ts +208 -0
  23. package/src/binding/__tests__/resolver.test.ts +83 -0
  24. package/src/binding/binding.ts +6 -6
  25. package/src/binding/index.ts +34 -34
  26. package/src/binding/resolver.ts +19 -19
  27. package/src/binding/utils.ts +7 -7
  28. package/src/binding-grammar/__tests__/parser.test.ts +64 -0
  29. package/src/binding-grammar/__tests__/test-utils/ast-cases.ts +198 -0
  30. package/src/binding-grammar/__tests__/test-utils/perf-test.ts +66 -0
  31. package/src/binding-grammar/ast.ts +11 -11
  32. package/src/binding-grammar/custom/index.ts +19 -22
  33. package/src/binding-grammar/ebnf/index.ts +20 -21
  34. package/src/binding-grammar/ebnf/types.ts +13 -13
  35. package/src/binding-grammar/index.ts +4 -4
  36. package/src/binding-grammar/parsimmon/index.ts +14 -14
  37. package/src/controllers/constants/__tests__/index.test.ts +106 -0
  38. package/src/controllers/constants/index.ts +3 -3
  39. package/src/controllers/constants/utils.ts +4 -4
  40. package/src/controllers/data/controller.ts +22 -22
  41. package/src/controllers/data/index.ts +1 -1
  42. package/src/controllers/data/utils.ts +7 -7
  43. package/src/controllers/flow/__tests__/controller.test.ts +195 -0
  44. package/src/controllers/flow/__tests__/flow.test.ts +381 -0
  45. package/src/controllers/flow/controller.ts +13 -13
  46. package/src/controllers/flow/flow.ts +23 -23
  47. package/src/controllers/flow/index.ts +2 -2
  48. package/src/controllers/index.ts +5 -5
  49. package/src/controllers/validation/binding-tracker.ts +71 -59
  50. package/src/controllers/validation/controller.ts +104 -104
  51. package/src/controllers/validation/index.ts +2 -2
  52. package/src/controllers/view/asset-transform.ts +20 -20
  53. package/src/controllers/view/controller.ts +27 -27
  54. package/src/controllers/view/index.ts +4 -4
  55. package/src/controllers/view/store.ts +3 -3
  56. package/src/controllers/view/types.ts +7 -7
  57. package/src/data/__tests__/__snapshots__/dependency-tracker.test.ts.snap +64 -0
  58. package/src/data/__tests__/dependency-tracker.test.ts +146 -0
  59. package/src/data/__tests__/local-model.test.ts +46 -0
  60. package/src/data/__tests__/model.test.ts +78 -0
  61. package/src/data/dependency-tracker.ts +16 -16
  62. package/src/data/index.ts +4 -4
  63. package/src/data/local-model.ts +6 -6
  64. package/src/data/model.ts +17 -17
  65. package/src/data/noop-model.ts +1 -1
  66. package/src/expressions/__tests__/__snapshots__/parser.test.ts.snap +854 -0
  67. package/src/expressions/__tests__/evaluator-functions.test.ts +47 -0
  68. package/src/expressions/__tests__/evaluator.test.ts +410 -0
  69. package/src/expressions/__tests__/parser.test.ts +115 -0
  70. package/src/expressions/__tests__/utils.test.ts +44 -0
  71. package/src/expressions/evaluator-functions.ts +6 -6
  72. package/src/expressions/evaluator.ts +71 -67
  73. package/src/expressions/index.ts +4 -4
  74. package/src/expressions/parser.ts +102 -105
  75. package/src/expressions/types.ts +29 -21
  76. package/src/expressions/utils.ts +32 -21
  77. package/src/index.ts +13 -13
  78. package/src/logger/__tests__/consoleLogger.test.ts +46 -0
  79. package/src/logger/__tests__/noopLogger.test.ts +13 -0
  80. package/src/logger/__tests__/proxyLogger.test.ts +31 -0
  81. package/src/logger/__tests__/tapableLogger.test.ts +41 -0
  82. package/src/logger/consoleLogger.ts +9 -9
  83. package/src/logger/index.ts +5 -5
  84. package/src/logger/noopLogger.ts +1 -1
  85. package/src/logger/proxyLogger.ts +6 -6
  86. package/src/logger/tapableLogger.ts +7 -7
  87. package/src/logger/types.ts +2 -2
  88. package/src/player.ts +60 -58
  89. package/src/plugins/default-exp-plugin.ts +10 -10
  90. package/src/plugins/default-view-plugin.ts +29 -0
  91. package/src/plugins/flow-exp-plugin.ts +6 -6
  92. package/src/schema/__tests__/schema.test.ts +243 -0
  93. package/src/schema/index.ts +2 -2
  94. package/src/schema/schema.ts +24 -24
  95. package/src/schema/types.ts +4 -4
  96. package/src/string-resolver/__tests__/index.test.ts +361 -0
  97. package/src/string-resolver/index.ts +17 -17
  98. package/src/types.ts +17 -17
  99. package/src/utils/__tests__/replaceParams.test.ts +33 -0
  100. package/src/utils/index.ts +1 -1
  101. package/src/utils/replaceParams.ts +1 -1
  102. package/src/validator/__tests__/binding-map-splice.test.ts +53 -0
  103. package/src/validator/__tests__/validation-middleware.test.ts +127 -0
  104. package/src/validator/binding-map-splice.ts +5 -5
  105. package/src/validator/index.ts +4 -4
  106. package/src/validator/registry.ts +1 -1
  107. package/src/validator/types.ts +13 -13
  108. package/src/validator/validation-middleware.ts +15 -15
  109. package/src/view/__tests__/view.immutable.test.ts +269 -0
  110. package/src/view/__tests__/view.test.ts +959 -0
  111. package/src/view/builder/index.test.ts +69 -0
  112. package/src/view/builder/index.ts +3 -3
  113. package/src/view/index.ts +5 -5
  114. package/src/view/parser/__tests__/__snapshots__/parser.test.ts.snap +394 -0
  115. package/src/view/parser/__tests__/parser.test.ts +264 -0
  116. package/src/view/parser/index.ts +43 -33
  117. package/src/view/parser/types.ts +11 -11
  118. package/src/view/parser/utils.ts +5 -5
  119. package/src/view/plugins/__tests__/__snapshots__/template.test.ts.snap +278 -0
  120. package/src/view/plugins/__tests__/applicability.test.ts +265 -0
  121. package/src/view/plugins/__tests__/string.test.ts +122 -0
  122. package/src/view/plugins/__tests__/template.test.ts +724 -0
  123. package/src/view/plugins/applicability.ts +19 -19
  124. package/src/view/plugins/index.ts +4 -5
  125. package/src/view/plugins/options.ts +1 -1
  126. package/src/view/plugins/string-resolver.ts +22 -22
  127. package/src/view/plugins/switch.ts +22 -23
  128. package/src/view/plugins/template-plugin.ts +26 -27
  129. package/src/view/resolver/__tests__/dependencies.test.ts +321 -0
  130. package/src/view/resolver/__tests__/edgecases.test.ts +626 -0
  131. package/src/view/resolver/index.ts +42 -42
  132. package/src/view/resolver/types.ts +21 -20
  133. package/src/view/resolver/utils.ts +9 -9
  134. package/src/view/view.ts +32 -22
  135. package/types/binding/binding.d.ts +50 -0
  136. package/types/binding/index.d.ts +29 -0
  137. package/types/binding/resolver.d.ts +26 -0
  138. package/types/binding/utils.d.ts +12 -0
  139. package/types/binding-grammar/ast.d.ts +67 -0
  140. package/types/binding-grammar/custom/index.d.ts +4 -0
  141. package/types/binding-grammar/ebnf/index.d.ts +4 -0
  142. package/types/binding-grammar/ebnf/types.d.ts +75 -0
  143. package/types/binding-grammar/index.d.ts +5 -0
  144. package/types/binding-grammar/parsimmon/index.d.ts +4 -0
  145. package/types/controllers/constants/index.d.ts +45 -0
  146. package/types/controllers/constants/utils.d.ts +6 -0
  147. package/types/controllers/data/controller.d.ts +45 -0
  148. package/types/controllers/data/index.d.ts +2 -0
  149. package/types/controllers/data/utils.d.ts +14 -0
  150. package/types/controllers/flow/controller.d.ts +25 -0
  151. package/types/controllers/flow/flow.d.ts +50 -0
  152. package/types/controllers/flow/index.d.ts +3 -0
  153. package/types/controllers/index.d.ts +6 -0
  154. package/types/controllers/validation/binding-tracker.d.ts +32 -0
  155. package/types/controllers/validation/controller.d.ts +151 -0
  156. package/types/controllers/validation/index.d.ts +3 -0
  157. package/types/controllers/view/asset-transform.d.ts +19 -0
  158. package/types/controllers/view/controller.d.ts +37 -0
  159. package/types/controllers/view/index.d.ts +5 -0
  160. package/types/controllers/view/store.d.ts +20 -0
  161. package/types/controllers/view/types.d.ts +16 -0
  162. package/types/data/dependency-tracker.d.ts +49 -0
  163. package/types/data/index.d.ts +5 -0
  164. package/types/data/local-model.d.ts +16 -0
  165. package/types/data/model.d.ts +86 -0
  166. package/types/data/noop-model.d.ts +13 -0
  167. package/types/expressions/evaluator-functions.d.ts +15 -0
  168. package/types/expressions/evaluator.d.ts +52 -0
  169. package/types/expressions/index.d.ts +5 -0
  170. package/types/expressions/parser.d.ts +10 -0
  171. package/types/expressions/types.d.ts +144 -0
  172. package/types/expressions/utils.d.ts +12 -0
  173. package/types/index.d.ts +14 -0
  174. package/types/logger/consoleLogger.d.ts +17 -0
  175. package/types/logger/index.d.ts +6 -0
  176. package/types/logger/noopLogger.d.ts +10 -0
  177. package/types/logger/proxyLogger.d.ts +15 -0
  178. package/types/logger/tapableLogger.d.ts +23 -0
  179. package/types/logger/types.d.ts +6 -0
  180. package/types/player.d.ts +101 -0
  181. package/types/plugins/default-exp-plugin.d.ts +9 -0
  182. package/types/plugins/default-view-plugin.d.ts +9 -0
  183. package/types/plugins/flow-exp-plugin.d.ts +11 -0
  184. package/types/schema/index.d.ts +3 -0
  185. package/types/schema/schema.d.ts +36 -0
  186. package/types/schema/types.d.ts +38 -0
  187. package/types/string-resolver/index.d.ts +30 -0
  188. package/types/types.d.ts +73 -0
  189. package/types/utils/index.d.ts +2 -0
  190. package/types/utils/replaceParams.d.ts +9 -0
  191. package/types/validator/binding-map-splice.d.ts +10 -0
  192. package/types/validator/index.d.ts +5 -0
  193. package/types/validator/registry.d.ts +11 -0
  194. package/types/validator/types.d.ts +53 -0
  195. package/types/validator/validation-middleware.d.ts +36 -0
  196. package/types/view/builder/index.d.ts +35 -0
  197. package/types/view/index.d.ts +6 -0
  198. package/types/view/parser/index.d.ts +52 -0
  199. package/types/view/parser/types.d.ts +109 -0
  200. package/types/view/parser/utils.d.ts +6 -0
  201. package/types/view/plugins/applicability.d.ts +10 -0
  202. package/types/view/plugins/index.d.ts +5 -0
  203. package/types/view/plugins/options.d.ts +4 -0
  204. package/types/view/plugins/string-resolver.d.ts +13 -0
  205. package/types/view/plugins/switch.d.ts +14 -0
  206. package/types/view/plugins/template-plugin.d.ts +33 -0
  207. package/types/view/resolver/index.d.ts +73 -0
  208. package/types/view/resolver/types.d.ts +129 -0
  209. package/types/view/resolver/utils.d.ts +11 -0
  210. package/types/view/view.d.ts +37 -0
  211. package/dist/index.d.ts +0 -1814
  212. package/dist/player.dev.js +0 -11472
  213. package/dist/player.prod.js +0 -2
  214. package/src/view/plugins/plugin.ts +0 -21
package/src/player.ts CHANGED
@@ -1,37 +1,38 @@
1
- import { setIn } from 'timm';
2
- import deferred from 'p-defer';
3
- import type { Flow as FlowType, FlowResult } from '@player-ui/types';
4
-
5
- import { SyncHook, SyncWaterfallHook } from 'tapable-ts';
6
- import type { Logger } from './logger';
7
- import { TapableLogger } from './logger';
8
- import type { ExpressionType } from './expressions';
9
- import { ExpressionEvaluator } from './expressions';
10
- import { SchemaController } from './schema';
11
- import { BindingParser } from './binding';
12
- import type { ViewInstance } from './view';
13
- import { resolveDataRefs } from './string-resolver';
14
- import type { FlowInstance } from './controllers';
1
+ import { setIn } from "timm";
2
+ import deferred from "p-defer";
3
+ import type { Flow as FlowType, FlowResult } from "@player-ui/types";
4
+
5
+ import { SyncHook, SyncWaterfallHook } from "tapable-ts";
6
+ import type { Logger } from "./logger";
7
+ import { TapableLogger } from "./logger";
8
+ import type { ExpressionType } from "./expressions";
9
+ import { ExpressionEvaluator } from "./expressions";
10
+ import { SchemaController } from "./schema";
11
+ import { BindingParser } from "./binding";
12
+ import type { ViewInstance } from "./view";
13
+ import { resolveDataRefs } from "./string-resolver";
14
+ import type { FlowInstance } from "./controllers";
15
15
  import {
16
16
  ConstantsController,
17
17
  ViewController,
18
18
  DataController,
19
19
  ValidationController,
20
20
  FlowController,
21
- } from './controllers';
22
- import { FlowExpPlugin } from './plugins/flow-exp-plugin';
23
- import { DefaultExpPlugin } from './plugins/default-exp-plugin';
21
+ } from "./controllers";
22
+ import { FlowExpPlugin } from "./plugins/flow-exp-plugin";
23
+ import { DefaultExpPlugin } from "./plugins/default-exp-plugin";
24
24
  import type {
25
25
  PlayerFlowState,
26
26
  InProgressState,
27
27
  CompletedState,
28
28
  ErrorState,
29
- } from './types';
30
- import { NOT_STARTED_STATE } from './types';
29
+ } from "./types";
30
+ import { NOT_STARTED_STATE } from "./types";
31
+ import { DefaultViewPlugin } from "./plugins/default-view-plugin";
31
32
 
32
33
  // Variables injected at build time
33
- const PLAYER_VERSION = '0.8.0--canary.307.9621';
34
- const COMMIT = '2f21b7b894c885ccfed826751ba96a0638e3d8d8';
34
+ const PLAYER_VERSION = "__VERSION__";
35
+ const COMMIT = "__GIT_COMMIT__";
35
36
 
36
37
  export interface PlayerPlugin {
37
38
  /**
@@ -58,7 +59,7 @@ export interface ExtendedPlayerPlugin<
58
59
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
59
60
  Expressions = void,
60
61
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
61
- DataTypes = void
62
+ DataTypes = void,
62
63
  > {}
63
64
 
64
65
  export interface PlayerConfigOptions {
@@ -136,6 +137,7 @@ export class Player {
136
137
  this.config = config || {};
137
138
  this.config.plugins = [
138
139
  new DefaultExpPlugin(),
140
+ new DefaultViewPlugin(),
139
141
  ...(this.config.plugins || []),
140
142
  new FlowExpPlugin(),
141
143
  ];
@@ -151,7 +153,7 @@ export class Player {
151
153
 
152
154
  /** Find instance of [Plugin] that has been registered to Player */
153
155
  public findPlugin<Plugin extends PlayerPlugin>(
154
- symbol: symbol
156
+ symbol: symbol,
155
157
  ): Plugin | undefined {
156
158
  return this.config.plugins?.find((el) => el.symbol === symbol) as Plugin;
157
159
  }
@@ -159,7 +161,7 @@ export class Player {
159
161
  /** Retrieve an instance of [Plugin] and conditionally invoke [apply] if it exists */
160
162
  public applyTo<Plugin extends PlayerPlugin>(
161
163
  symbol: symbol,
162
- apply: (plugin: Plugin) => void
164
+ apply: (plugin: Plugin) => void,
163
165
  ): void {
164
166
  const plugin = this.findPlugin<Plugin>(symbol);
165
167
 
@@ -208,7 +210,7 @@ export class Player {
208
210
  start: () => void;
209
211
 
210
212
  /** the state object to kick if off */
211
- state: Omit<InProgressState, 'ref'>;
213
+ state: Omit<InProgressState, "ref">;
212
214
  } {
213
215
  const userFlow = this.hooks.resolveFlowContent.call(userContent);
214
216
 
@@ -254,21 +256,21 @@ export class Player {
254
256
  logger: this.logger,
255
257
  });
256
258
 
257
- dataController.hooks.format.tap('player', (value, binding) => {
259
+ dataController.hooks.format.tap("player", (value, binding) => {
258
260
  const formatter = schema.getFormatter(binding);
259
261
 
260
262
  return formatter ? formatter.format(value) : value;
261
263
  });
262
264
 
263
- dataController.hooks.deformat.tap('player', (value, binding) => {
265
+ dataController.hooks.deformat.tap("player", (value, binding) => {
264
266
  const formatter = schema.getFormatter(binding);
265
267
 
266
268
  return formatter ? formatter.deformat(value) : value;
267
269
  });
268
270
 
269
271
  dataController.hooks.resolveDefaultValue.tap(
270
- 'player',
271
- (binding) => schema.getApparentType(binding)?.default
272
+ "player",
273
+ (binding) => schema.getApparentType(binding)?.default,
272
274
  );
273
275
 
274
276
  // eslint-disable-next-line prefer-const
@@ -281,7 +283,7 @@ export class Player {
281
283
 
282
284
  this.hooks.expressionEvaluator.call(expressionEvaluator);
283
285
 
284
- expressionEvaluator.hooks.onError.tap('player', (e) => {
286
+ expressionEvaluator.hooks.onError.tap("player", (e) => {
285
287
  flowResultDeferred.reject(e);
286
288
 
287
289
  return true;
@@ -296,14 +298,14 @@ export class Player {
296
298
  });
297
299
  }
298
300
 
299
- flowController.hooks.flow.tap('player', (flow: FlowInstance) => {
300
- flow.hooks.beforeTransition.tap('player', (state, transitionVal) => {
301
+ flowController.hooks.flow.tap("player", (flow: FlowInstance) => {
302
+ flow.hooks.beforeTransition.tap("player", (state, transitionVal) => {
301
303
  /** Checks to see if there are any transitions for a specific transition state (i.e. next, back). If not, it will default to * */
302
304
  const computedTransitionVal = state.transitions[transitionVal]
303
305
  ? transitionVal
304
- : '*';
306
+ : "*";
305
307
  if (state.onEnd && state.transitions[computedTransitionVal]) {
306
- if (typeof state.onEnd === 'object' && 'exp' in state.onEnd) {
308
+ if (typeof state.onEnd === "object" && "exp" in state.onEnd) {
307
309
  expressionEvaluator?.evaluate(state.onEnd.exp);
308
310
  } else {
309
311
  expressionEvaluator?.evaluate(state.onEnd as ExpressionType);
@@ -312,7 +314,7 @@ export class Player {
312
314
 
313
315
  /** If the transition does not exist, then do not resolve any expressions */
314
316
  if (
315
- !('transitions' in state) ||
317
+ !("transitions" in state) ||
316
318
  !state.transitions[computedTransitionVal]
317
319
  ) {
318
320
  return state;
@@ -321,15 +323,15 @@ export class Player {
321
323
  /** resolves and sets the transition to the computed exp */
322
324
  return setIn(
323
325
  state,
324
- ['transitions', computedTransitionVal],
325
- resolveStrings(state.transitions[computedTransitionVal])
326
+ ["transitions", computedTransitionVal],
327
+ resolveStrings(state.transitions[computedTransitionVal]),
326
328
  ) as any;
327
329
  });
328
330
 
329
- flow.hooks.skipTransition.tap('validation', (currentState) => {
330
- if (currentState?.value.state_type === 'VIEW') {
331
+ flow.hooks.skipTransition.tap("validation", (currentState) => {
332
+ if (currentState?.value.state_type === "VIEW") {
331
333
  const { canTransition, validations } =
332
- validationController.validateView('navigation');
334
+ validationController.validateView("navigation");
333
335
 
334
336
  if (!canTransition && validations) {
335
337
  const bindings = new Set(validations.keys());
@@ -342,36 +344,36 @@ export class Player {
342
344
  return undefined;
343
345
  });
344
346
 
345
- flow.hooks.resolveTransitionNode.tap('player', (state) => {
347
+ flow.hooks.resolveTransitionNode.tap("player", (state) => {
346
348
  let newState = state;
347
349
 
348
- if ('ref' in state) {
349
- newState = setIn(state, ['ref'], resolveStrings(state.ref)) as any;
350
+ if ("ref" in state) {
351
+ newState = setIn(state, ["ref"], resolveStrings(state.ref)) as any;
350
352
  }
351
353
 
352
- if ('param' in state) {
354
+ if ("param" in state) {
353
355
  newState = setIn(
354
356
  state,
355
- ['param'],
356
- resolveStrings(state.param, false)
357
+ ["param"],
358
+ resolveStrings(state.param, false),
357
359
  ) as any;
358
360
  }
359
361
 
360
362
  return newState;
361
363
  });
362
364
 
363
- flow.hooks.transition.tap('player', (_oldState, newState) => {
364
- if (newState.value.state_type !== 'VIEW') {
365
+ flow.hooks.transition.tap("player", (_oldState, newState) => {
366
+ if (newState.value.state_type !== "VIEW") {
365
367
  validationController.reset();
366
368
  }
367
369
  });
368
370
 
369
- flow.hooks.afterTransition.tap('player', (flowInstance) => {
371
+ flow.hooks.afterTransition.tap("player", (flowInstance) => {
370
372
  const value = flowInstance.currentState?.value;
371
- if (value && value.state_type === 'ACTION') {
373
+ if (value && value.state_type === "ACTION") {
372
374
  const { exp } = value;
373
375
  flowController?.transition(
374
- String(expressionEvaluator?.evaluate(exp))
376
+ String(expressionEvaluator?.evaluate(exp)),
375
377
  );
376
378
  }
377
379
 
@@ -418,7 +420,7 @@ export class Player {
418
420
  },
419
421
  constants: this.constantsController,
420
422
  });
421
- viewController.hooks.view.tap('player', (view) => {
423
+ viewController.hooks.view.tap("player", (view) => {
422
424
  validationController.onView(view);
423
425
  this.hooks.view.call(view);
424
426
  });
@@ -445,7 +447,7 @@ export class Player {
445
447
  .finally(() => this.hooks.onEnd.call());
446
448
  },
447
449
  state: {
448
- status: 'in-progress',
450
+ status: "in-progress",
449
451
  flowResult: flowResultDeferred.promise,
450
452
  controllers: {
451
453
  data: dataController,
@@ -464,13 +466,13 @@ export class Player {
464
466
  }
465
467
 
466
468
  public async start(payload: FlowType): Promise<CompletedState> {
467
- const ref = Symbol(payload?.id ?? 'payload');
469
+ const ref = Symbol(payload?.id ?? "payload");
468
470
 
469
471
  /** A check to avoid updating the state for a flow that's not the current one */
470
472
  const maybeUpdateState = <T extends PlayerFlowState>(newState: T) => {
471
473
  if (this.state.ref !== ref) {
472
474
  this.logger.warn(
473
- `Received update for a flow that's not the current one`
475
+ `Received update for a flow that's not the current one`,
474
476
  );
475
477
 
476
478
  return newState;
@@ -482,7 +484,7 @@ export class Player {
482
484
  };
483
485
 
484
486
  this.setState({
485
- status: 'not-started',
487
+ status: "not-started",
486
488
  ref,
487
489
  });
488
490
 
@@ -499,7 +501,7 @@ export class Player {
499
501
  // make sure to use the same ref as the starting one
500
502
  const endProps = {
501
503
  ref,
502
- status: 'completed',
504
+ status: "completed",
503
505
  flow: state.flow,
504
506
  controllers: {
505
507
  data: state.controllers.data.makeReadOnly(),
@@ -512,7 +514,7 @@ export class Player {
512
514
  });
513
515
  } catch (error: any) {
514
516
  const errorState: ErrorState = {
515
- status: 'error',
517
+ status: "error",
516
518
  ref,
517
519
  flow: payload,
518
520
  error,
@@ -1,6 +1,6 @@
1
- import type { ExpressionHandler, ExpressionType } from '../expressions';
2
- import type { SchemaController } from '../schema';
3
- import type { Player, PlayerPlugin } from '../player';
1
+ import type { ExpressionHandler, ExpressionType } from "../expressions";
2
+ import type { SchemaController } from "../schema";
3
+ import type { Player, PlayerPlugin } from "../player";
4
4
 
5
5
  /** Gets formatter for given formatName and formats value if found, returns value otherwise */
6
6
  const createFormatFunction = (schema: SchemaController) => {
@@ -10,7 +10,7 @@ const createFormatFunction = (schema: SchemaController) => {
10
10
  const handler: ExpressionHandler<[unknown, string], any> = (
11
11
  ctx,
12
12
  value,
13
- formatName
13
+ formatName,
14
14
  ) => {
15
15
  return (
16
16
  schema.getFormatterForType({ type: formatName })?.format(value) ?? value
@@ -24,7 +24,7 @@ const createFormatFunction = (schema: SchemaController) => {
24
24
  * A plugin that provides the out-of-the-box expressions for player
25
25
  */
26
26
  export class DefaultExpPlugin implements PlayerPlugin {
27
- name = 'flow-exp-plugin';
27
+ name = "flow-exp-plugin";
28
28
 
29
29
  apply(player: Player) {
30
30
  let formatFunction: ExpressionHandler<[unknown, string]> | undefined;
@@ -35,22 +35,22 @@ export class DefaultExpPlugin implements PlayerPlugin {
35
35
 
36
36
  player.hooks.expressionEvaluator.tap(this.name, (expEvaluator) => {
37
37
  if (formatFunction) {
38
- expEvaluator.addExpressionFunction('format', formatFunction);
38
+ expEvaluator.addExpressionFunction("format", formatFunction);
39
39
  }
40
40
 
41
- expEvaluator.addExpressionFunction('log', (ctx, ...args) => {
41
+ expEvaluator.addExpressionFunction("log", (ctx, ...args) => {
42
42
  player.logger.info(...args);
43
43
  });
44
44
 
45
- expEvaluator.addExpressionFunction('debug', (ctx, ...args) => {
45
+ expEvaluator.addExpressionFunction("debug", (ctx, ...args) => {
46
46
  player.logger.debug(...args);
47
47
  });
48
48
 
49
49
  expEvaluator.addExpressionFunction(
50
- 'eval',
50
+ "eval",
51
51
  (ctx, ...args: [ExpressionType]) => {
52
52
  return ctx.evaluate(...args);
53
- }
53
+ },
54
54
  );
55
55
  });
56
56
  }
@@ -0,0 +1,29 @@
1
+ import type { Player, PlayerPlugin } from "../player";
2
+ import {
3
+ ApplicabilityPlugin,
4
+ StringResolverPlugin,
5
+ SwitchPlugin,
6
+ TemplatePlugin,
7
+ toNodeResolveOptions,
8
+ } from "../view";
9
+
10
+ /**
11
+ * A plugin that provides the out-of-the-box expressions for player
12
+ */
13
+ export class DefaultViewPlugin implements PlayerPlugin {
14
+ name = "default-view-plugin";
15
+
16
+ apply(player: Player) {
17
+ player.hooks.viewController.tap(this.name, (viewController) => {
18
+ viewController.hooks.view.tap(this.name, (view) => {
19
+ const pluginOptions = toNodeResolveOptions(view.resolverOptions);
20
+ new SwitchPlugin(pluginOptions).apply(view);
21
+ new ApplicabilityPlugin().apply(view);
22
+ new StringResolverPlugin().apply(view);
23
+ const templatePlugin = new TemplatePlugin(pluginOptions);
24
+ templatePlugin.apply(view);
25
+ view.hooks.onTemplatePluginCreated.call(templatePlugin);
26
+ });
27
+ });
28
+ }
29
+ }
@@ -2,10 +2,10 @@ import type {
2
2
  Expression,
3
3
  ExpressionObject,
4
4
  NavigationFlowState,
5
- } from '@player-ui/types';
6
- import type { ExpressionEvaluator, ExpressionType } from '../expressions';
7
- import type { FlowInstance } from '../controllers';
8
- import type { Player, PlayerPlugin } from '../player';
5
+ } from "@player-ui/types";
6
+ import type { ExpressionEvaluator, ExpressionType } from "../expressions";
7
+ import type { FlowInstance } from "../controllers";
8
+ import type { Player, PlayerPlugin } from "../player";
9
9
 
10
10
  /**
11
11
  * A plugin that taps into the flow controller to evaluate available expressions
@@ -13,7 +13,7 @@ import type { Player, PlayerPlugin } from '../player';
13
13
  * e.g: onStart, onEnd
14
14
  */
15
15
  export class FlowExpPlugin implements PlayerPlugin {
16
- name = 'flow-exp-plugin';
16
+ name = "flow-exp-plugin";
17
17
 
18
18
  apply(player: Player) {
19
19
  let expressionEvaluator: ExpressionEvaluator | undefined;
@@ -25,7 +25,7 @@ export class FlowExpPlugin implements PlayerPlugin {
25
25
  */
26
26
  const handleEval = (exp: Expression | ExpressionObject) => {
27
27
  if (exp) {
28
- if (typeof exp === 'object' && 'exp' in exp) {
28
+ if (typeof exp === "object" && "exp" in exp) {
29
29
  expressionEvaluator?.evaluate(exp.exp);
30
30
  } else {
31
31
  expressionEvaluator?.evaluate(exp as ExpressionType);
@@ -0,0 +1,243 @@
1
+ import { describe, test, expect } from "vitest";
2
+ import { BindingParser } from "../../binding";
3
+ import { SchemaController } from "..";
4
+
5
+ const { parse } = new BindingParser({
6
+ get: () => undefined,
7
+ set: () => undefined,
8
+ evaluate: () => undefined,
9
+ });
10
+
11
+ describe("schema", () => {
12
+ const schema = new SchemaController({
13
+ ROOT: {
14
+ pets: {
15
+ type: "PetType",
16
+ isArray: true,
17
+ },
18
+ owner: {
19
+ type: "OwnerType",
20
+ },
21
+ animals: {
22
+ type: "AnimalType",
23
+ isRecord: true,
24
+ },
25
+ automobile: {
26
+ type: "carType",
27
+ isArray: true,
28
+ },
29
+ },
30
+ PetType: {
31
+ breed: {
32
+ type: "StringType",
33
+ },
34
+ name: {
35
+ type: "StringType",
36
+ validation: [
37
+ {
38
+ type: "required",
39
+ },
40
+ ],
41
+ },
42
+ age: {
43
+ type: "IntegerType",
44
+ validation: [
45
+ {
46
+ type: "required",
47
+ },
48
+ ],
49
+ },
50
+ },
51
+ OwnerType: {
52
+ name: {
53
+ type: "FirstNameType",
54
+ validation: [
55
+ {
56
+ type: "enum",
57
+ options: ["adam"],
58
+ },
59
+ ],
60
+ },
61
+ },
62
+ AnimalType: {
63
+ age: {
64
+ type: "IntegerType",
65
+ validation: [
66
+ {
67
+ type: "required",
68
+ },
69
+ ],
70
+ },
71
+ type: {
72
+ type: "StringType",
73
+ },
74
+ name: {
75
+ type: "StringType",
76
+ validation: [
77
+ {
78
+ type: "length",
79
+ min: 1,
80
+ max: 10,
81
+ },
82
+ ],
83
+ },
84
+ colors: {
85
+ type: "colorType",
86
+ isArray: true,
87
+ },
88
+ },
89
+ carType: {
90
+ year: {
91
+ type: "IntegerType",
92
+ },
93
+ car: {
94
+ type: "makeType",
95
+ isRecord: true,
96
+ },
97
+ },
98
+ colorType: {
99
+ color: {
100
+ type: "StringType",
101
+ },
102
+ },
103
+ makeType: {
104
+ makeInteger: {
105
+ type: "IntegerType",
106
+ validation: [
107
+ {
108
+ type: "required",
109
+ },
110
+ ],
111
+ },
112
+ model: {
113
+ type: "modelType",
114
+ isArray: true,
115
+ },
116
+ },
117
+ modelType: {
118
+ color: {
119
+ type: "StringType",
120
+ },
121
+ body: {
122
+ type: "StringType",
123
+ validation: [
124
+ {
125
+ type: "required",
126
+ },
127
+ ],
128
+ },
129
+ },
130
+ });
131
+
132
+ test("gets basic type info", () => {
133
+ expect(schema.getType(parse("owner.name"))?.type).toBe("FirstNameType");
134
+ expect(schema.getValidationsForBinding(parse("owner.name"))).toStrictEqual([
135
+ {
136
+ type: "enum",
137
+ options: ["adam"],
138
+ trigger: "change",
139
+ severity: "error",
140
+ },
141
+ ]);
142
+ });
143
+
144
+ test("gets the type for objects in an array", () => {
145
+ expect(schema.getType(parse("pets.4.name"))?.type).toBe("StringType");
146
+ expect(
147
+ schema.getValidationsForBinding(parse("pets.999.name")),
148
+ ).toStrictEqual([
149
+ {
150
+ type: "required",
151
+ trigger: "change",
152
+ severity: "error",
153
+ },
154
+ ]);
155
+ });
156
+
157
+ test("gets the type for an array parent", () => {
158
+ expect(schema.getType(parse("pets"))).toStrictEqual({
159
+ type: "PetType",
160
+ isArray: true,
161
+ });
162
+ });
163
+
164
+ test("gets the type for an record parent", () => {
165
+ expect(schema.getType(parse("animals"))).toStrictEqual({
166
+ type: "AnimalType",
167
+ isRecord: true,
168
+ });
169
+ });
170
+
171
+ test("gets the type for objects in a record", () => {
172
+ expect(schema.getType(parse("animals.cat.age"))?.type).toBe("IntegerType");
173
+ expect(
174
+ schema.getValidationsForBinding(parse("animals.cat.age")),
175
+ ).toStrictEqual([
176
+ {
177
+ type: "required",
178
+ trigger: "change",
179
+ severity: "error",
180
+ },
181
+ ]);
182
+ });
183
+
184
+ test("gets the type for objects in a record in an array", () => {
185
+ expect(schema.getType(parse("animals.cat.colors.0.color"))?.type).toBe(
186
+ "StringType",
187
+ );
188
+ });
189
+
190
+ test("gets the type for objects in a record with validation", () => {
191
+ expect(schema.getType(parse("animals.ginger.name"))?.type).toBe(
192
+ "StringType",
193
+ );
194
+ expect(
195
+ schema.getValidationsForBinding(parse("animals.ginger.name")),
196
+ ).toStrictEqual([
197
+ {
198
+ type: "length",
199
+ min: 1,
200
+ max: 10,
201
+ trigger: "change",
202
+ severity: "error",
203
+ },
204
+ ]);
205
+ });
206
+
207
+ test("gets the schema type for an array of objects in an object. and an array in an object of arrays", () => {
208
+ expect(schema.getType(parse("automobile.0.year"))?.type).toBe(
209
+ "IntegerType",
210
+ );
211
+ expect(
212
+ schema.getType(parse("automobile.0.car.honda.makeInteger"))?.type,
213
+ ).toBe("IntegerType");
214
+ expect(
215
+ schema.getValidationsForBinding(
216
+ parse("automobile.0.car.honda.makeInteger"),
217
+ ),
218
+ ).toStrictEqual([
219
+ {
220
+ type: "required",
221
+ trigger: "change",
222
+ severity: "error",
223
+ },
224
+ ]);
225
+ expect(
226
+ schema.getType(parse("automobile.0.car.honda.model.0.color"))?.type,
227
+ ).toBe("StringType");
228
+ expect(
229
+ schema.getType(parse("automobile.0.car.honda.model.0.body"))?.type,
230
+ ).toBe("StringType");
231
+ expect(
232
+ schema.getValidationsForBinding(
233
+ parse("automobile.0.car.honda.model.0.body"),
234
+ ),
235
+ ).toStrictEqual([
236
+ {
237
+ type: "required",
238
+ trigger: "change",
239
+ severity: "error",
240
+ },
241
+ ]);
242
+ });
243
+ });
@@ -1,2 +1,2 @@
1
- export * from './types';
2
- export * from './schema';
1
+ export * from "./types";
2
+ export * from "./schema";