@player-ui/player 0.13.0 → 0.14.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.
@@ -52,59 +52,66 @@ const withContext = (model: DataModelWithParser): DataModelWithParser => {
52
52
  };
53
53
  };
54
54
 
55
+ export type ResolverHooks = {
56
+ /** A hook to allow skipping of the resolution tree for a specific node */
57
+ skipResolve: SyncWaterfallHook<
58
+ [boolean, Node.Node, Resolve.NodeResolveOptions]
59
+ >;
60
+
61
+ /** An event emitted before calculating the next update */
62
+ beforeUpdate: SyncHook<[Set<BindingInstance> | undefined]>;
63
+
64
+ /** An event emitted after calculating the next update */
65
+ afterUpdate: SyncHook<[any]>;
66
+
67
+ /** The options passed to a node to resolve it to an object */
68
+ resolveOptions: SyncWaterfallHook<[Resolve.NodeResolveOptions, Node.Node]>;
69
+
70
+ /** A hook to transform the AST node into a new AST node before resolving it */
71
+ beforeResolve: SyncWaterfallHook<
72
+ [Node.Node | null, Resolve.NodeResolveOptions]
73
+ >;
74
+
75
+ /**
76
+ * A hook to transform an AST node into it's resolved value.
77
+ * This runs _before_ any children are resolved
78
+ */
79
+ resolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions]>;
80
+
81
+ /**
82
+ * A hook to transform the resolved value of an AST node.
83
+ * This runs _after_ all children nodes are resolved
84
+ */
85
+ afterResolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions]>;
86
+
87
+ /** Called at the very end of a node's tree being updated */
88
+ afterNodeUpdate: SyncHook<[Node.Node, Node.Node | undefined, NodeUpdate]>;
89
+ };
90
+
55
91
  /**
56
92
  * The Resolver is the way to take a parsed AST graph of a view and resolve it to a concrete representation of the current user state
57
93
  * It combines the ability to mutate ast nodes before resolving, as well as the mutating the resolved objects while parsing
58
94
  */
59
95
  export class Resolver {
60
- public readonly hooks = {
61
- /** A hook to allow skipping of the resolution tree for a specific node */
62
- skipResolve: new SyncWaterfallHook<
63
- [boolean, Node.Node, Resolve.NodeResolveOptions]
64
- >(),
65
-
66
- /** An event emitted before calculating the next update */
67
- beforeUpdate: new SyncHook<[Set<BindingInstance> | undefined]>(),
68
-
69
- /** An event emitted after calculating the next update */
70
- afterUpdate: new SyncHook<[any]>(),
71
-
72
- /** The options passed to a node to resolve it to an object */
73
- resolveOptions: new SyncWaterfallHook<
74
- [Resolve.NodeResolveOptions, Node.Node]
75
- >(),
76
-
77
- /** A hook to transform the AST node into a new AST node before resolving it */
78
- beforeResolve: new SyncWaterfallHook<
79
- [Node.Node | null, Resolve.NodeResolveOptions]
80
- >(),
81
-
82
- /**
83
- * A hook to transform an AST node into it's resolved value.
84
- * This runs _before_ any children are resolved
85
- */
86
- resolve: new SyncWaterfallHook<
87
- [any, Node.Node, Resolve.NodeResolveOptions]
88
- >(),
89
-
90
- /**
91
- * A hook to transform the resolved value of an AST node.
92
- * This runs _after_ all children nodes are resolved
93
- */
94
- afterResolve: new SyncWaterfallHook<
95
- [any, Node.Node, Resolve.NodeResolveOptions]
96
- >(),
97
-
98
- /** Called at the very end of a node's tree being updated */
99
- afterNodeUpdate: new SyncHook<
100
- [Node.Node, Node.Node | undefined, NodeUpdate]
101
- >(),
96
+ public readonly hooks: ResolverHooks = {
97
+ skipResolve: new SyncWaterfallHook(),
98
+ beforeUpdate: new SyncHook(),
99
+ afterUpdate: new SyncHook(),
100
+ resolveOptions: new SyncWaterfallHook(),
101
+ beforeResolve: new SyncWaterfallHook(),
102
+ resolve: new SyncWaterfallHook(),
103
+ afterResolve: new SyncWaterfallHook(),
104
+ afterNodeUpdate: new SyncHook(),
102
105
  };
103
106
 
104
107
  /**
105
108
  * The AST tree after beforeResolve is ran mapped to the AST before beforeResolve is ran
106
109
  */
107
110
  private readonly ASTMap: Map<Node.Node, Node.Node>;
111
+ /**
112
+ * The AST tree after beforeResolve is ran mapped to the AST before beforeResolve is ran
113
+ */
114
+ private AsyncIdMap: Map<string, Node.Node>;
108
115
  /**
109
116
  * The root node in the AST tree we want to resolve
110
117
  */
@@ -138,19 +145,36 @@ export class Resolver {
138
145
  this.ASTMap = new Map();
139
146
  this.logger = options.logger;
140
147
  this.idCache = new Set();
148
+ this.AsyncIdMap = new Map();
141
149
  }
142
150
 
143
- public getSourceNode(convertedAST: Node.Node) {
151
+ public getSourceNode(convertedAST: Node.Node): Node.Node | undefined {
144
152
  return this.ASTMap.get(convertedAST);
145
153
  }
146
154
 
147
- public update(changes?: Set<BindingInstance>): any {
155
+ public update(
156
+ changes?: Set<BindingInstance>,
157
+ asyncChanges?: Set<string>,
158
+ ): any {
148
159
  this.hooks.beforeUpdate.call(changes);
149
160
  const resolveCache = new Map<Node.Node, Resolve.ResolvedNode>();
150
161
  this.idCache.clear();
151
162
  const prevASTMap = new Map(this.ASTMap);
152
163
  this.ASTMap.clear();
153
164
 
165
+ const prevAsyncIdMap = new Map(this.AsyncIdMap);
166
+ const nextAsyncIdMap = new Map<string, Node.Node>();
167
+ asyncChanges?.forEach((id) => {
168
+ let current: Node.Node | undefined = prevAsyncIdMap.get(id);
169
+ while (current && prevASTMap.has(current)) {
170
+ const next = prevASTMap.get(current);
171
+ if (next && this.resolveCache.has(next)) {
172
+ this.resolveCache.delete(next);
173
+ }
174
+ current = current.parent;
175
+ }
176
+ });
177
+
154
178
  const updated = this.computeTree(
155
179
  this.root,
156
180
  undefined,
@@ -159,13 +183,15 @@ export class Resolver {
159
183
  toNodeResolveOptions(this.options),
160
184
  undefined,
161
185
  prevASTMap,
186
+ nextAsyncIdMap,
162
187
  );
188
+ this.AsyncIdMap = nextAsyncIdMap;
163
189
  this.resolveCache = resolveCache;
164
190
  this.hooks.afterUpdate.call(updated.value);
165
191
  return updated.value;
166
192
  }
167
193
 
168
- public getResolveCache() {
194
+ public getResolveCache(): Map<Node.Node, Resolve.ResolvedNode> {
169
195
  return new Map(this.resolveCache);
170
196
  }
171
197
 
@@ -226,6 +252,7 @@ export class Resolver {
226
252
  options: Resolve.NodeResolveOptions,
227
253
  partiallyResolvedParent: Node.Node | undefined,
228
254
  prevASTMap: Map<Node.Node, Node.Node>,
255
+ nextAsyncIdMap: Map<string, Node.Node>,
229
256
  ): NodeUpdate {
230
257
  const dependencyModel = new DependencyModel(options.data.model);
231
258
 
@@ -258,31 +285,6 @@ export class Resolver {
258
285
  resolveOptions,
259
286
  );
260
287
 
261
- // Shallow clone the node so that changes to it during the resolve steps don't impact the original.
262
- // We are trusting that this becomes a deep clone once the whole node tree has been traversed.
263
- const clonedNode = {
264
- ...this.cloneNode(node),
265
- parent: partiallyResolvedParent,
266
- };
267
- const resolvedAST = this.hooks.beforeResolve.call(
268
- clonedNode,
269
- resolveOptions,
270
- ) ?? {
271
- type: NodeType.Empty,
272
- };
273
-
274
- const isNestedMultiNodeWithAsync =
275
- resolvedAST.type === NodeType.MultiNode &&
276
- partiallyResolvedParent?.parent?.parent?.type === NodeType.MultiNode &&
277
- partiallyResolvedParent.parent.type === NodeType.Value &&
278
- resolvedAST.parent?.type === NodeType.Asset &&
279
- resolvedAST.parent.value.id.includes("async");
280
-
281
- const isNestedMultiNode =
282
- resolvedAST.type === NodeType.MultiNode &&
283
- partiallyResolvedParent?.parent?.type === NodeType.MultiNode &&
284
- partiallyResolvedParent.type === NodeType.Value;
285
-
286
288
  if (previousResult && shouldUseLastValue) {
287
289
  const update = {
288
290
  ...previousResult,
@@ -302,6 +304,12 @@ export class Resolver {
302
304
  updated: false,
303
305
  };
304
306
  cacheUpdate.set(AST, resolvedUpdate);
307
+ if (resolvedUpdate.node.type === NodeType.Async) {
308
+ nextAsyncIdMap.set(resolvedUpdate.node.id, resolvedUpdate.node);
309
+ }
310
+ for (const key of resolvedUpdate.node.asyncNodesResolved ?? []) {
311
+ nextAsyncIdMap.set(key, resolvedUpdate.node);
312
+ }
305
313
 
306
314
  /** Helper function for recursing over child node */
307
315
  const handleChildNode = (childNode: Node.Node) => {
@@ -336,10 +344,26 @@ export class Resolver {
336
344
  return update;
337
345
  }
338
346
 
339
- if (isNestedMultiNodeWithAsync) {
340
- resolvedAST.parent = partiallyResolvedParent.parent;
341
- } else {
342
- resolvedAST.parent = partiallyResolvedParent;
347
+ // Shallow clone the node so that changes to it during the resolve steps don't impact the original.
348
+ // We are trusting that this becomes a deep clone once the whole node tree has been traversed.
349
+ const clonedNode: Node.Node = {
350
+ ...this.cloneNode(node),
351
+ parent: partiallyResolvedParent,
352
+ };
353
+ const resolvedAST = this.hooks.beforeResolve.call(
354
+ clonedNode,
355
+ resolveOptions,
356
+ ) ?? {
357
+ type: NodeType.Empty,
358
+ };
359
+
360
+ resolvedAST.parent = partiallyResolvedParent;
361
+
362
+ if (resolvedAST.type === NodeType.Async) {
363
+ nextAsyncIdMap.set(resolvedAST.id, resolvedAST);
364
+ }
365
+ for (const id of resolvedAST.asyncNodesResolved ?? []) {
366
+ nextAsyncIdMap.set(id, resolvedAST);
343
367
  }
344
368
 
345
369
  resolveOptions.node = resolvedAST;
@@ -371,6 +395,7 @@ export class Resolver {
371
395
  resolveOptions,
372
396
  resolvedAST,
373
397
  prevASTMap,
398
+ nextAsyncIdMap,
374
399
  );
375
400
  const {
376
401
  dependencies: childTreeDeps,
@@ -401,15 +426,9 @@ export class Resolver {
401
426
  resolvedAST.children = newChildren;
402
427
  } else if (resolvedAST.type === NodeType.MultiNode) {
403
428
  const childValue: any = [];
404
- const rawParentToPassIn = isNestedMultiNode
405
- ? partiallyResolvedParent?.parent
406
- : node;
429
+ const rawParentToPassIn = node;
407
430
 
408
- const hasAsync = resolvedAST.values
409
- .map((value, index) => (value.type === NodeType.Async ? index : -1))
410
- .filter((index) => index !== -1);
411
-
412
- const newValues = resolvedAST.values.map((mValue) => {
431
+ resolvedAST.values = resolvedAST.values.map((mValue) => {
413
432
  const mTree = this.computeTree(
414
433
  mValue,
415
434
  rawParentToPassIn,
@@ -418,47 +437,21 @@ export class Resolver {
418
437
  resolveOptions,
419
438
  resolvedAST,
420
439
  prevASTMap,
440
+ nextAsyncIdMap,
421
441
  );
422
442
 
423
443
  if (mTree.value !== undefined && mTree.value !== null) {
424
- /**
425
- * async nodes' parent is a multi-node
426
- * When the node to resolve is an async node and the flatten flag is true
427
- * Add the content streamed in to the childValue of parent multi-node
428
- * Array.isArray(mTree.value.asset.values) is the case when the content is an async asset
429
- */
430
- if (
431
- mValue.type === NodeType.Async &&
432
- mValue.flatten &&
433
- mTree.value.asset &&
434
- Array.isArray(mTree.value.asset.values)
435
- ) {
436
- // This flatten function only changed the values not node structure
437
- unpackAndPush(mTree.value, childValue);
438
- } else {
439
- childValue.push(mTree.value);
440
- }
441
- }
442
-
443
- mTree.dependencies.forEach((bindingDep) =>
444
- childDependencies.add(bindingDep),
445
- );
444
+ mTree.dependencies.forEach((bindingDep) =>
445
+ childDependencies.add(bindingDep),
446
+ );
446
447
 
447
- updated = updated || mTree.updated;
448
+ updated = updated || mTree.updated;
449
+ childValue.push(mTree.value);
450
+ }
448
451
 
449
452
  return mTree.node;
450
453
  });
451
454
 
452
- if (hasAsync.length > 0) {
453
- // this likely turned into a nested multinode, attempt to flatten in node structure
454
- const copy = newValues;
455
- hasAsync.forEach((index) => {
456
- if (copy[index]) copy.splice(index, 1, ...unpackNode(copy[index]));
457
- });
458
- resolvedAST.values = copy;
459
- } else {
460
- resolvedAST.values = newValues;
461
- }
462
455
  resolved = childValue;
463
456
  }
464
457
 
@@ -487,50 +480,9 @@ export class Resolver {
487
480
  ]),
488
481
  };
489
482
 
490
- this.hooks.afterNodeUpdate.call(
491
- node,
492
- isNestedMultiNode ? partiallyResolvedParent?.parent : rawParent,
493
- update,
494
- );
483
+ this.hooks.afterNodeUpdate.call(node, rawParent, update);
495
484
  cacheUpdate.set(node, update);
496
485
 
497
486
  return update;
498
487
  }
499
488
  }
500
-
501
- /**
502
- * helper function to flatten a potential nested array and combine with initial array
503
- */
504
- function unpackAndPush(item: any | any[], initial: any[]): void {
505
- if (item.asset.values && Array.isArray(item.asset.values)) {
506
- item.asset.values.forEach((i: any) => {
507
- unpackAndPush(i, initial);
508
- });
509
- } else {
510
- initial.push(item);
511
- }
512
- }
513
-
514
- function unpackNode(item: Node.Node) {
515
- const unpacked: Node.Node[] = [];
516
- if (
517
- "children" in item &&
518
- item.children?.[0]?.value.type === NodeType.Asset &&
519
- (item.children?.[0]?.value as Node.Asset).children
520
- ) {
521
- if (
522
- (item.children?.[0]?.value as Node.Asset).children?.[0]?.value.type ===
523
- NodeType.MultiNode
524
- ) {
525
- (
526
- (item.children?.[0]?.value as Node.Asset).children?.[0]
527
- ?.value as Node.MultiNode
528
- ).values.forEach((value) => {
529
- unpacked.push(value);
530
- });
531
- }
532
- } else {
533
- unpacked.push(item);
534
- }
535
- return unpacked;
536
- }
package/src/view/view.ts CHANGED
@@ -109,8 +109,8 @@ export class ViewInstance implements ValidationProvider {
109
109
  this.resolverOptions = resolverOptions;
110
110
  }
111
111
 
112
- public updateAsync(): void {
113
- const update = this.resolver?.update();
112
+ public updateAsync(asyncNode: string): void {
113
+ const update = this.resolver?.update(new Set(), new Set([asyncNode]));
114
114
  this.lastUpdate = update;
115
115
  this.hooks.onUpdate.call(update);
116
116
  }
@@ -23,7 +23,7 @@ export interface QueryNode extends Node<"Query"> {
23
23
  /** A simple segment */
24
24
  export interface ValueNode extends Node<"Value"> {
25
25
  /** The segment value */
26
- value: string | number;
26
+ value: string | number | boolean;
27
27
  }
28
28
  /** A nested expression */
29
29
  export interface ExpressionNode extends Node<"Expression"> {
@@ -31,7 +31,7 @@ export interface ExpressionNode extends Node<"Expression"> {
31
31
  value: string;
32
32
  }
33
33
  /** Helper to create a value node */
34
- export declare const toValue: (value: string | number) => ValueNode;
34
+ export declare const toValue: (value: string | number | boolean) => ValueNode;
35
35
  /** Helper to create an expression node */
36
36
  export declare const toExpression: (value: string) => ExpressionNode;
37
37
  /** Helper to create a nested path node */
@@ -29,7 +29,7 @@ export declare class Builder {
29
29
  *
30
30
  * @param id - the id of async node. It should be identical for each async node
31
31
  */
32
- static asyncNode(id: string, flatten?: boolean): Node.Async;
32
+ static asyncNode(id: string, flatten?: boolean, onValueReceived?: (node: Node.Node) => Node.Node): Node.Async;
33
33
  /**
34
34
  * Adds a child node to a node
35
35
  *
@@ -13,33 +13,49 @@ export interface ParseObjectChildOptions {
13
13
  path: Node.PathSegment[];
14
14
  parentObj: object;
15
15
  }
16
+ export type ParserHooks = {
17
+ /**
18
+ * A hook to interact with an object _before_ parsing it into an AST
19
+ *
20
+ * @param value - The object we're are about to parse
21
+ * @returns - A new value to parse.
22
+ * If undefined, the original value is used.
23
+ * If null, we stop parsing this node.
24
+ */
25
+ onParseObject: SyncWaterfallHook<[object, NodeType]>;
26
+ /**
27
+ * A callback to interact with an AST _after_ we parse it into the AST
28
+ *
29
+ * @param value - The object we parsed
30
+ * @param node - The AST node we generated
31
+ * @returns - A new AST node to use
32
+ * If undefined, the original value is used.
33
+ * If null, we ignore this node all together
34
+ */
35
+ onCreateASTNode: SyncWaterfallHook<[Node.Node | undefined | null, object]>;
36
+ /** A hook to call when parsing an object into an AST node
37
+ *
38
+ * @param obj - The object we're are about to parse
39
+ * @param nodeType - The type of node we're parsing
40
+ * @param parseOptions - Additional options when parsing
41
+ * @param childOptions - Additional options that are populated when the node being parsed is a child of another node
42
+ * @returns - A new AST node to use
43
+ * If undefined, the original value is used.
44
+ * If null, we ignore this node all together
45
+ */
46
+ parseNode: SyncBailHook<[
47
+ obj: object,
48
+ nodeType: Node.ChildrenTypes,
49
+ parseOptions: ParseObjectOptions,
50
+ childOptions?: ParseObjectChildOptions
51
+ ], Node.Node | Node.Child[]>;
52
+ };
16
53
  /**
17
54
  * The Parser is the way to take an incoming view from the user and parse it into an AST.
18
55
  * It provides a few ways to interact with the parsing, including mutating an object before and after creation of an AST node
19
56
  */
20
57
  export declare class Parser {
21
- readonly hooks: {
22
- /**
23
- * A hook to interact with an object _before_ parsing it into an AST
24
- *
25
- * @param value - The object we're are about to parse
26
- * @returns - A new value to parse.
27
- * If undefined, the original value is used.
28
- * If null, we stop parsing this node.
29
- */
30
- onParseObject: SyncWaterfallHook<[object, NodeType], Record<string, any>>;
31
- /**
32
- * A callback to interact with an AST _after_ we parse it into the AST
33
- *
34
- * @param value - The object we parsed
35
- * @param node - The AST node we generated
36
- * @returns - A new AST node to use
37
- * If undefined, the original value is used.
38
- * If null, we ignore this node all together
39
- */
40
- onCreateASTNode: SyncWaterfallHook<[Node.Node | null | undefined, object], Record<string, any>>;
41
- parseNode: SyncBailHook<[obj: object, nodeType: Node.ChildrenTypes, parseOptions: ParseObjectOptions, childOptions?: ParseObjectChildOptions | undefined], Node.Node | Node.Child[], Record<string, any>>;
42
- };
58
+ readonly hooks: ParserHooks;
43
59
  parseView(value: AnyAssetType): Node.View;
44
60
  createASTNode(node: Node.Node | null, value: any): Node.Node | null;
45
61
  parseObject(obj: object, type?: Node.ChildrenTypes, options?: ParseObjectOptions): Node.Node | null;
@@ -19,6 +19,8 @@ export declare namespace Node {
19
19
  type: T;
20
20
  /** Every node (outside of the root) contains a reference to it's parent */
21
21
  parent?: Node;
22
+ /** The ids of async nodes resolved within this node */
23
+ asyncNodesResolved?: string[];
22
24
  }
23
25
  type PathSegment = string | number;
24
26
  interface Child {
@@ -93,6 +95,8 @@ export declare namespace Node {
93
95
  * Should the content streamed in be flattened during resolving
94
96
  */
95
97
  flatten?: boolean;
98
+ /** Function to run against parsed content from the node to manipulate the content before resolving it. */
99
+ onValueReceived?: (node: Node.Node) => Node.Node;
96
100
  }
97
101
  interface PluginOptions {
98
102
  /** A list of plugins */
@@ -8,39 +8,51 @@ interface NodeUpdate extends Resolve.ResolvedNode {
8
8
  /** A flag to track if a node has changed since the last resolution */
9
9
  updated: boolean;
10
10
  }
11
+ export type ResolverHooks = {
12
+ /** A hook to allow skipping of the resolution tree for a specific node */
13
+ skipResolve: SyncWaterfallHook<[
14
+ boolean,
15
+ Node.Node,
16
+ Resolve.NodeResolveOptions
17
+ ]>;
18
+ /** An event emitted before calculating the next update */
19
+ beforeUpdate: SyncHook<[Set<BindingInstance> | undefined]>;
20
+ /** An event emitted after calculating the next update */
21
+ afterUpdate: SyncHook<[any]>;
22
+ /** The options passed to a node to resolve it to an object */
23
+ resolveOptions: SyncWaterfallHook<[Resolve.NodeResolveOptions, Node.Node]>;
24
+ /** A hook to transform the AST node into a new AST node before resolving it */
25
+ beforeResolve: SyncWaterfallHook<[
26
+ Node.Node | null,
27
+ Resolve.NodeResolveOptions
28
+ ]>;
29
+ /**
30
+ * A hook to transform an AST node into it's resolved value.
31
+ * This runs _before_ any children are resolved
32
+ */
33
+ resolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions]>;
34
+ /**
35
+ * A hook to transform the resolved value of an AST node.
36
+ * This runs _after_ all children nodes are resolved
37
+ */
38
+ afterResolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions]>;
39
+ /** Called at the very end of a node's tree being updated */
40
+ afterNodeUpdate: SyncHook<[Node.Node, Node.Node | undefined, NodeUpdate]>;
41
+ };
11
42
  /**
12
43
  * The Resolver is the way to take a parsed AST graph of a view and resolve it to a concrete representation of the current user state
13
44
  * It combines the ability to mutate ast nodes before resolving, as well as the mutating the resolved objects while parsing
14
45
  */
15
46
  export declare class Resolver {
16
- readonly hooks: {
17
- /** A hook to allow skipping of the resolution tree for a specific node */
18
- skipResolve: SyncWaterfallHook<[boolean, Node.Node, Resolve.NodeResolveOptions], Record<string, any>>;
19
- /** An event emitted before calculating the next update */
20
- beforeUpdate: SyncHook<[Set<BindingInstance> | undefined], Record<string, any>>;
21
- /** An event emitted after calculating the next update */
22
- afterUpdate: SyncHook<[any], Record<string, any>>;
23
- /** The options passed to a node to resolve it to an object */
24
- resolveOptions: SyncWaterfallHook<[Resolve.NodeResolveOptions, Node.Node], Record<string, any>>;
25
- /** A hook to transform the AST node into a new AST node before resolving it */
26
- beforeResolve: SyncWaterfallHook<[Node.Node | null, Resolve.NodeResolveOptions], Record<string, any>>;
27
- /**
28
- * A hook to transform an AST node into it's resolved value.
29
- * This runs _before_ any children are resolved
30
- */
31
- resolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions], Record<string, any>>;
32
- /**
33
- * A hook to transform the resolved value of an AST node.
34
- * This runs _after_ all children nodes are resolved
35
- */
36
- afterResolve: SyncWaterfallHook<[any, Node.Node, Resolve.NodeResolveOptions], Record<string, any>>;
37
- /** Called at the very end of a node's tree being updated */
38
- afterNodeUpdate: SyncHook<[Node.Node, Node.Node | undefined, NodeUpdate], Record<string, any>>;
39
- };
47
+ readonly hooks: ResolverHooks;
40
48
  /**
41
49
  * The AST tree after beforeResolve is ran mapped to the AST before beforeResolve is ran
42
50
  */
43
51
  private readonly ASTMap;
52
+ /**
53
+ * The AST tree after beforeResolve is ran mapped to the AST before beforeResolve is ran
54
+ */
55
+ private AsyncIdMap;
44
56
  /**
45
57
  * The root node in the AST tree we want to resolve
46
58
  */
@@ -64,7 +76,7 @@ export declare class Resolver {
64
76
  private logger?;
65
77
  constructor(root: Node.Node, options: Resolve.ResolverOptions);
66
78
  getSourceNode(convertedAST: Node.Node): Node.Node | undefined;
67
- update(changes?: Set<BindingInstance>): any;
79
+ update(changes?: Set<BindingInstance>, asyncChanges?: Set<string>): any;
68
80
  getResolveCache(): Map<Node.Node, Resolve.ResolvedNode>;
69
81
  private getPreviousResult;
70
82
  private cloneNode;
@@ -27,7 +27,7 @@ export declare class ViewInstance implements ValidationProvider {
27
27
  private templatePlugin;
28
28
  lastUpdate: Record<string, any> | undefined;
29
29
  constructor(initialView: ViewType, resolverOptions: Resolve.ResolverOptions);
30
- updateAsync(): void;
30
+ updateAsync(asyncNode: string): void;
31
31
  update(changes?: Set<BindingInstance>): any;
32
32
  getValidationsForBinding(binding: BindingInstance): Array<ValidationObject> | undefined;
33
33
  setTemplatePlugin(plugin: TemplatePlugin): void;