@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
@@ -1,8 +1,8 @@
1
- import type { Node } from '../../view';
2
- import { NodeType } from '../../view';
3
- import { LocalStateStore } from './store';
4
- import type { TransformRegistry } from './types';
5
- import type { ViewController } from './controller';
1
+ import type { Node } from "../../view";
2
+ import { NodeType } from "../../view";
3
+ import { LocalStateStore } from "./store";
4
+ import type { TransformRegistry } from "./types";
5
+ import type { ViewController } from "./controller";
6
6
 
7
7
  /** Traverse up the nodes until the target is found */
8
8
  function findUp(node: Node.Node, target: Node.Node): boolean {
@@ -32,18 +32,18 @@ export class AssetTransformCorePlugin {
32
32
  constructor(registry: TransformRegistry) {
33
33
  this.registry = registry;
34
34
  this.stateStore = new Map();
35
- this.beforeResolveSymbol = Symbol('before resolve');
36
- this.resolveSymbol = Symbol('resolve');
37
- this.beforeResolveCountSymbol = Symbol('before resolve count');
38
- this.resolveCountSymbol = Symbol('resolve count');
35
+ this.beforeResolveSymbol = Symbol("before resolve");
36
+ this.resolveSymbol = Symbol("resolve");
37
+ this.beforeResolveCountSymbol = Symbol("before resolve count");
38
+ this.resolveCountSymbol = Symbol("resolve count");
39
39
  }
40
40
 
41
41
  apply(viewController: ViewController) {
42
- viewController.hooks.view.tap('asset-transform', (view) => {
42
+ viewController.hooks.view.tap("asset-transform", (view) => {
43
43
  // Clear out everything when we create a new view
44
44
  this.stateStore.clear();
45
45
 
46
- view.hooks.resolver.tap('asset-transform', (resolver) => {
46
+ view.hooks.resolver.tap("asset-transform", (resolver) => {
47
47
  let lastUpdatedNode: Node.Node | undefined;
48
48
 
49
49
  /** A function to update the state and trigger a view re-compute */
@@ -74,27 +74,27 @@ export class AssetTransformCorePlugin {
74
74
 
75
75
  return {
76
76
  useSharedState: (
77
- key: string | symbol
77
+ key: string | symbol,
78
78
  ): (<T>(initialState: T) => readonly [T, (value: T) => void]) => {
79
79
  return store.useSharedState(key);
80
80
  },
81
81
  useLocalState: <T>(initialState: T) => {
82
82
  return store.getLocalStateFunction<T>(
83
83
  stepKey,
84
- countKey
84
+ countKey,
85
85
  )(initialState);
86
86
  },
87
87
  };
88
88
  };
89
89
 
90
- resolver.hooks.beforeResolve.tap('asset-transform', (node, options) => {
91
- if (node && (node.type === 'asset' || node.type === 'view')) {
90
+ resolver.hooks.beforeResolve.tap("asset-transform", (node, options) => {
91
+ if (node && (node.type === "asset" || node.type === "view")) {
92
92
  const transform = this.registry.get(node.value);
93
93
 
94
94
  if (transform?.beforeResolve) {
95
95
  const store = getStore(
96
96
  options.node ?? node,
97
- this.beforeResolveSymbol
97
+ this.beforeResolveSymbol,
98
98
  );
99
99
 
100
100
  return transform.beforeResolve(node, options, store);
@@ -104,11 +104,11 @@ export class AssetTransformCorePlugin {
104
104
  return node;
105
105
  });
106
106
 
107
- resolver.hooks.afterUpdate.tap('asset-transform', () => {
107
+ resolver.hooks.afterUpdate.tap("asset-transform", () => {
108
108
  lastUpdatedNode = undefined;
109
109
  });
110
110
 
111
- resolver.hooks.skipResolve.tap('asset-transform', (skip, node) => {
111
+ resolver.hooks.skipResolve.tap("asset-transform", (skip, node) => {
112
112
  if (!skip || !lastUpdatedNode) {
113
113
  return skip;
114
114
  }
@@ -120,7 +120,7 @@ export class AssetTransformCorePlugin {
120
120
  });
121
121
 
122
122
  resolver.hooks.afterResolve.tap(
123
- 'asset-transform',
123
+ "asset-transform",
124
124
  (value, node, options) => {
125
125
  if (node.type !== NodeType.Asset && node.type !== NodeType.View) {
126
126
  return value;
@@ -141,7 +141,7 @@ export class AssetTransformCorePlugin {
141
141
  }
142
142
 
143
143
  return value;
144
- }
144
+ },
145
145
  );
146
146
  });
147
147
  });
@@ -1,17 +1,17 @@
1
- import { SyncHook, SyncWaterfallHook } from 'tapable-ts';
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';
11
- import type { DataController } from '../data/controller';
12
- import { AssetTransformCorePlugin } from './asset-transform';
13
- import type { TransformRegistry } from './types';
14
- import type { BindingInstance } from '../../binding';
1
+ import { SyncHook, SyncWaterfallHook } from "tapable-ts";
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";
11
+ import type { DataController } from "../data/controller";
12
+ import { AssetTransformCorePlugin } from "./asset-transform";
13
+ import type { TransformRegistry } from "./types";
14
+ import type { BindingInstance } from "../../binding";
15
15
 
16
16
  export interface ViewControllerOptions {
17
17
  /** Where to get data from */
@@ -51,7 +51,7 @@ export class ViewController {
51
51
 
52
52
  constructor(
53
53
  initialViews: View[],
54
- options: Resolve.ResolverOptions & ViewControllerOptions
54
+ options: Resolve.ResolverOptions & ViewControllerOptions,
55
55
  ) {
56
56
  this.viewOptions = options;
57
57
  this.viewMap = initialViews.reduce<Record<string, View>>(
@@ -60,22 +60,22 @@ export class ViewController {
60
60
  viewMap[view.id] = view;
61
61
  return viewMap;
62
62
  },
63
- {}
63
+ {},
64
64
  );
65
65
 
66
66
  new AssetTransformCorePlugin(this.transformRegistry).apply(this);
67
67
 
68
68
  options.flowController.hooks.flow.tap(
69
- 'viewController',
69
+ "viewController",
70
70
  (flow: FlowInstance) => {
71
- flow.hooks.transition.tap('viewController', (_oldState, newState) => {
72
- if (newState.value.state_type === 'VIEW') {
71
+ flow.hooks.transition.tap("viewController", (_oldState, newState) => {
72
+ if (newState.value.state_type === "VIEW") {
73
73
  this.onView(newState.value);
74
74
  } else {
75
75
  this.currentView = undefined;
76
76
  }
77
77
  });
78
- }
78
+ },
79
79
  );
80
80
 
81
81
  /** Trigger a view update */
@@ -90,21 +90,21 @@ export class ViewController {
90
90
  };
91
91
 
92
92
  options.model.hooks.onUpdate.tap(
93
- 'viewController',
93
+ "viewController",
94
94
  (updates, updateOptions) => {
95
95
  update(
96
96
  new Set(updates.map((t) => t.binding)),
97
- updateOptions?.silent ?? false
97
+ updateOptions?.silent ?? false,
98
98
  );
99
- }
99
+ },
100
100
  );
101
101
 
102
- options.model.hooks.onDelete.tap('viewController', (binding) => {
102
+ options.model.hooks.onDelete.tap("viewController", (binding) => {
103
103
  const parentBinding = binding.parent();
104
104
  const property = binding.key();
105
105
 
106
106
  // Deleting an array item will trigger an update for the entire array
107
- if (typeof property === 'number' && parentBinding) {
107
+ if (typeof property === "number" && parentBinding) {
108
108
  update(new Set([parentBinding]));
109
109
  } else {
110
110
  update(new Set([binding]));
@@ -148,7 +148,7 @@ export class ViewController {
148
148
  resolveDataRefsInString(possibleViewIdMatch, {
149
149
  model: this.viewOptions.model,
150
150
  evaluate: this.viewOptions.evaluator.evaluate,
151
- })
151
+ }),
152
152
  );
153
153
 
154
154
  if (matchingViewId && this.viewMap[matchingViewId]) {
@@ -162,7 +162,7 @@ export class ViewController {
162
162
  const source = this.hooks.resolveView.call(
163
163
  this.getViewForRef(viewId),
164
164
  viewId,
165
- state
165
+ state,
166
166
  );
167
167
 
168
168
  if (!source) {
@@ -1,4 +1,4 @@
1
- export * from './asset-transform';
2
- export * from './controller';
3
- export * from './store';
4
- export * from './types';
1
+ export * from "./asset-transform";
2
+ export * from "./controller";
3
+ export * from "./store";
4
+ export * from "./types";
@@ -1,17 +1,17 @@
1
1
  export interface Store {
2
2
  useLocalState<T>(initialState: T): readonly [T, (value: T) => void];
3
3
  useSharedState<T>(
4
- key: string | symbol
4
+ key: string | symbol,
5
5
  ): (initialState: T) => readonly [T, (value: T) => void];
6
6
  }
7
7
 
8
8
  interface SharedStore {
9
9
  getLocalStateFunction<T>(
10
10
  key: string | symbol,
11
- countKey: symbol
11
+ countKey: symbol,
12
12
  ): (initialState: T) => readonly [T, (value: T) => void];
13
13
  useSharedState<T>(
14
- key: string | symbol
14
+ key: string | symbol,
15
15
  ): (initialState: T) => readonly [T, (value: T) => void];
16
16
  }
17
17
 
@@ -1,24 +1,24 @@
1
- import type { Asset } from '@player-ui/types';
2
- import type { Registry } from '@player-ui/partial-match-registry';
1
+ import type { Asset } from "@player-ui/types";
2
+ import type { Registry } from "@player-ui/partial-match-registry";
3
3
 
4
- import type { Resolve, Node } from '../../view';
5
- import type { Store } from './store';
4
+ import type { Resolve, Node } from "../../view";
5
+ import type { Store } from "./store";
6
6
 
7
7
  /** Transform function that is ran on the Asset before it's resolved */
8
8
  export type BeforeTransformFunction<AuthoredAsset extends Asset = Asset> = (
9
9
  asset: Node.Asset<AuthoredAsset> | Node.View<AuthoredAsset>,
10
10
  options: Resolve.NodeResolveOptions,
11
- store: Store
11
+ store: Store,
12
12
  ) => Node.Node;
13
13
 
14
14
  /** Transform function that is ran on the Asset after it's resolved */
15
15
  export type TransformFunction<
16
16
  AuthoredAsset extends Asset = Asset,
17
- TransformedAsset extends Asset = AuthoredAsset
17
+ TransformedAsset extends Asset = AuthoredAsset,
18
18
  > = (
19
19
  asset: AuthoredAsset,
20
20
  options: Resolve.NodeResolveOptions,
21
- store: Store
21
+ store: Store,
22
22
  ) => TransformedAsset;
23
23
 
24
24
  export interface TransformFunctions {
@@ -0,0 +1,64 @@
1
+ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2
+
3
+ exports[`dependency model > tracks dependency sets correctly 1`] = `
4
+ Set {
5
+ BindingInstance {
6
+ "factory": [Function],
7
+ "joined": "foo.bar",
8
+ "split": [
9
+ "foo",
10
+ "bar",
11
+ ],
12
+ },
13
+ }
14
+ `;
15
+
16
+ exports[`dependency model > tracks dependency sets correctly 2`] = `
17
+ Set {
18
+ BindingInstance {
19
+ "factory": [Function],
20
+ "joined": "foo.baz",
21
+ "split": [
22
+ "foo",
23
+ "baz",
24
+ ],
25
+ },
26
+ BindingInstance {
27
+ "factory": [Function],
28
+ "joined": "foo.bad",
29
+ "split": [
30
+ "foo",
31
+ "bad",
32
+ ],
33
+ },
34
+ }
35
+ `;
36
+
37
+ exports[`dependency model > tracks dependency sets correctly 3`] = `
38
+ Set {
39
+ BindingInstance {
40
+ "factory": [Function],
41
+ "joined": "foo.bar",
42
+ "split": [
43
+ "foo",
44
+ "bar",
45
+ ],
46
+ },
47
+ BindingInstance {
48
+ "factory": [Function],
49
+ "joined": "foo.baz",
50
+ "split": [
51
+ "foo",
52
+ "baz",
53
+ ],
54
+ },
55
+ BindingInstance {
56
+ "factory": [Function],
57
+ "joined": "foo.bad",
58
+ "split": [
59
+ "foo",
60
+ "bad",
61
+ ],
62
+ },
63
+ }
64
+ `;
@@ -0,0 +1,146 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import { BindingParser } from "../../binding";
3
+ import { LocalModel, DependencyModel, DependencyMiddleware } from "..";
4
+
5
+ const parser = new BindingParser({
6
+ get: () => undefined,
7
+ set: () => undefined,
8
+ evaluate: () => undefined,
9
+ });
10
+ const binding = parser.parse("foo.bar");
11
+
12
+ describe("dependency model", () => {
13
+ it("tracks reads", () => {
14
+ const trackedModel = new DependencyModel(
15
+ new LocalModel({ foo: { bar: "baz" } }),
16
+ );
17
+
18
+ trackedModel.get(binding);
19
+ expect(trackedModel.readsBinding(binding)).toBe(true);
20
+ expect(trackedModel.readsBinding(parser.parse("foo.baz"))).toBe(false);
21
+ expect(trackedModel.getDependencies().size).toBe(1);
22
+ });
23
+
24
+ it("tracks writes", () => {
25
+ const trackedModel = new DependencyModel(
26
+ new LocalModel({ foo: { bar: "baz" } }),
27
+ );
28
+
29
+ trackedModel.set([[binding, "not baz"]]);
30
+ expect(trackedModel.writesBinding(binding)).toBe(true);
31
+ expect(trackedModel.writesBinding(parser.parse("foo.baz"))).toBe(false);
32
+ expect(trackedModel.getModified().size).toBe(1);
33
+ });
34
+
35
+ it(`uses the existing set instead of recreating a new one`, () => {
36
+ const trackedModel = new DependencyModel(
37
+ new LocalModel({ foo: { bar: "baz" } }),
38
+ );
39
+ const binding2 = parser.parse("foo.baz");
40
+
41
+ trackedModel.trackSubset("core");
42
+ trackedModel.get(binding);
43
+ trackedModel.trackSubset("core");
44
+ trackedModel.get(binding2);
45
+
46
+ expect(trackedModel.getDependencies("core").size).toBe(2);
47
+ });
48
+
49
+ it("tracks dependency sets correctly", () => {
50
+ const trackedModel = new DependencyModel(
51
+ new LocalModel({ foo: { bar: "baz" } }),
52
+ );
53
+ const binding2 = parser.parse("foo.baz");
54
+ const binding3 = parser.parse("foo.bad");
55
+
56
+ trackedModel.trackSubset("children");
57
+ trackedModel.get(binding);
58
+ trackedModel.trackSubset("core");
59
+ trackedModel.get(binding2);
60
+ trackedModel.trackDefault();
61
+ trackedModel.get(binding3);
62
+
63
+ expect(trackedModel.getDependencies("children")).toMatchSnapshot();
64
+ expect(trackedModel.getDependencies("core")).toMatchSnapshot();
65
+ expect(trackedModel.getDependencies()).toMatchSnapshot();
66
+
67
+ trackedModel.reset();
68
+ expect(trackedModel.getDependencies("children").size).toBe(0);
69
+ expect(trackedModel.getDependencies("core").size).toBe(0);
70
+ expect(trackedModel.getDependencies().size).toBe(0);
71
+ });
72
+
73
+ it("adds a tracked dependency to children set", () => {
74
+ const trackedModel = new DependencyModel(
75
+ new LocalModel({ foo: { bar: "baz" } }),
76
+ );
77
+
78
+ trackedModel.addChildReadDep(binding);
79
+ expect(trackedModel.getDependencies("children").size).toBe(1);
80
+ expect(trackedModel.getDependencies("core").size).toBe(0);
81
+ expect(trackedModel.getDependencies().size).toBe(1);
82
+ });
83
+ });
84
+
85
+ describe("dependency model middleware", () => {
86
+ it("tracks reads", () => {
87
+ const base = new LocalModel({ foo: { bar: "baz" } });
88
+ const trackedModel = new DependencyMiddleware();
89
+
90
+ trackedModel.get(binding, undefined, base);
91
+ expect(trackedModel.readsBinding(binding)).toBe(true);
92
+ expect(trackedModel.readsBinding(parser.parse("foo.baz"))).toBe(false);
93
+ expect(trackedModel.getDependencies().size).toBe(1);
94
+ });
95
+
96
+ it("tracks a subset of read dependencies", () => {
97
+ const base = new LocalModel({ foo: { bar: "baz" } });
98
+ const binding2 = parser.parse("foo.baz");
99
+ const trackedModel = new DependencyMiddleware();
100
+
101
+ trackedModel.trackSubset("children");
102
+ trackedModel.get(binding, undefined, base);
103
+ trackedModel.trackDefault();
104
+ trackedModel.get(binding2, undefined, base);
105
+
106
+ expect(trackedModel.getDependencies("children").size).toBe(1);
107
+ expect(trackedModel.getDependencies("core").size).toBe(1);
108
+ expect(trackedModel.getDependencies().size).toBe(2);
109
+
110
+ trackedModel.reset();
111
+ expect(trackedModel.getDependencies("children").size).toBe(0);
112
+ expect(trackedModel.getDependencies("core").size).toBe(0);
113
+ expect(trackedModel.getDependencies().size).toBe(0);
114
+ });
115
+
116
+ it("tracks writes", () => {
117
+ const base = new LocalModel({ foo: { bar: "baz" } });
118
+ const trackedModel = new DependencyMiddleware();
119
+ trackedModel.set([[binding, "not baz"]], undefined, base);
120
+ expect(trackedModel.writesBinding(binding)).toBe(true);
121
+ expect(trackedModel.writesBinding(parser.parse("foo.baz"))).toBe(false);
122
+ expect(trackedModel.getModified().size).toBe(1);
123
+ trackedModel.reset();
124
+ expect(trackedModel.getModified().size).toBe(0);
125
+ });
126
+
127
+ it("tracks a subset of write dependencies", () => {
128
+ const base = new LocalModel({ foo: { bar: "baz" } });
129
+ const binding2 = parser.parse("foo.baz");
130
+ const trackedModel = new DependencyMiddleware();
131
+
132
+ trackedModel.trackSubset("children");
133
+ trackedModel.set([[binding, "not baz"]], undefined, base);
134
+ trackedModel.trackDefault();
135
+ trackedModel.set([[binding2, "not bar"]], undefined, base);
136
+
137
+ expect(trackedModel.getModified("children").size).toBe(1);
138
+ expect(trackedModel.getModified("core").size).toBe(1);
139
+ expect(trackedModel.getModified().size).toBe(2);
140
+
141
+ trackedModel.reset();
142
+ expect(trackedModel.getModified("children").size).toBe(0);
143
+ expect(trackedModel.getModified("core").size).toBe(0);
144
+ expect(trackedModel.getModified().size).toBe(0);
145
+ });
146
+ });
@@ -0,0 +1,46 @@
1
+ import { it, expect } from "vitest";
2
+ import { BindingParser } from "../../binding";
3
+ import { LocalModel } from "..";
4
+
5
+ const parser = new BindingParser({
6
+ get: () => undefined,
7
+ set: () => undefined,
8
+ evaluate: () => undefined,
9
+ });
10
+ const binding = parser.parse("foo.bar");
11
+ it("sets data", () => {
12
+ const model = new LocalModel();
13
+ model.set([[binding, "baz"]]);
14
+ expect(model.get(binding)).toBe("baz");
15
+ });
16
+
17
+ it("overrides data", () => {
18
+ const model = new LocalModel({ foo: { bar: "baz" } });
19
+ expect(model.get(binding)).toBe("baz");
20
+ model.set([[binding, "not baz"]]);
21
+ expect(model.get(binding)).toBe("not baz");
22
+ });
23
+
24
+ it("gets data", () => {
25
+ const model = new LocalModel({ foo: { bar: "baz" } });
26
+ expect(model.get(binding)).toBe("baz");
27
+ });
28
+
29
+ it("resets data", () => {
30
+ const model = new LocalModel({ foo: { bar: "baz" } });
31
+ expect(model.get(binding)).toBe("baz");
32
+ model.reset();
33
+ expect(model.get(binding)).toBe(undefined);
34
+ });
35
+
36
+ it("resets data starting with new model", () => {
37
+ const model = new LocalModel({ foo: { bar: "baz" } });
38
+ expect(model.get(binding)).toBe("baz");
39
+ model.reset({ foo: { bar: "not baz" } });
40
+ expect(model.get(binding)).toBe("not baz");
41
+ });
42
+
43
+ it("retuns the whole model when no binding is passed", () => {
44
+ const model = new LocalModel({ foo: { bar: "baz" } });
45
+ expect(model.get()).toStrictEqual({ foo: { bar: "baz" } });
46
+ });
@@ -0,0 +1,78 @@
1
+ import { describe, it, expect, beforeEach, vitest } from "vitest";
2
+ import { BindingInstance, BindingParser } from "../../binding";
3
+ import type { DataModelMiddleware } from "..";
4
+ import { LocalModel, PipelinedDataModel } from "..";
5
+ import { withParser } from "../model";
6
+ import type { BatchSetTransaction } from "../model";
7
+
8
+ const { parse } = new BindingParser({
9
+ get: () => undefined,
10
+ set: () => undefined,
11
+ evaluate: () => undefined,
12
+ });
13
+
14
+ describe("model", () => {
15
+ let localModel: LocalModel;
16
+ let model: PipelinedDataModel;
17
+
18
+ beforeEach(() => {
19
+ localModel = new LocalModel();
20
+
21
+ const middleware: DataModelMiddleware = {
22
+ get(binding, options, next) {
23
+ return next?.get(binding, options);
24
+ },
25
+ set(transaction, options, next) {
26
+ const newTransaction: BatchSetTransaction = [];
27
+ transaction.forEach(([binding, val]) => {
28
+ if (val !== "bad") {
29
+ newTransaction.push([binding, val]);
30
+ }
31
+ });
32
+
33
+ return next?.set(newTransaction, options) ?? [];
34
+ },
35
+ };
36
+
37
+ model = new PipelinedDataModel();
38
+ model.addMiddleware(localModel);
39
+ model.addMiddleware(middleware);
40
+ });
41
+
42
+ it("works with basic middleware", () => {
43
+ model.set([
44
+ [parse("foo.bar"), "bad"],
45
+ [parse("foo.baz"), "good"],
46
+ ]);
47
+
48
+ expect(localModel.get(parse("foo.bar"))).toBe(undefined);
49
+ expect(localModel.get(parse("foo.baz"))).toBe("good");
50
+ });
51
+
52
+ it("works with withParser", () => {
53
+ const mockParse = vitest.fn(() => new BindingInstance(["some", "binding"]));
54
+
55
+ const modelWithParser = withParser(model, mockParse);
56
+
57
+ modelWithParser.get("some.binding");
58
+
59
+ expect(mockParse).toHaveBeenCalledWith(
60
+ "some.binding",
61
+ expect.objectContaining({ readOnly: true }),
62
+ );
63
+
64
+ modelWithParser.set([["some.binding", "test"]]);
65
+
66
+ expect(mockParse).toHaveBeenCalledWith(
67
+ "some.binding",
68
+ expect.objectContaining({ readOnly: false }),
69
+ );
70
+
71
+ modelWithParser.delete(["some.binding"]);
72
+
73
+ expect(mockParse).toHaveBeenCalledWith(
74
+ "some.binding",
75
+ expect.objectContaining({ readOnly: false }),
76
+ );
77
+ });
78
+ });