@player-ui/async-node-plugin 0.8.0--canary.307.9645 → 0.8.0-next.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/index.ts CHANGED
@@ -1,107 +1,185 @@
1
- import { NodeType, getNodeID } from '@player-ui/player';
1
+ import { NodeType, getNodeID } from "@player-ui/player";
2
2
  import type {
3
3
  Player,
4
4
  PlayerPlugin,
5
5
  Node,
6
6
  ParseObjectOptions,
7
- } from '@player-ui/player';
8
- import { AsyncParallelBailHook } from 'tapable-ts';
9
- import queueMicrotask from 'queue-microtask';
10
- import { omit } from 'timm';
7
+ ViewInstance,
8
+ Parser,
9
+ ViewPlugin,
10
+ Resolver,
11
+ } from "@player-ui/player";
12
+ import { AsyncParallelBailHook } from "tapable-ts";
13
+ import queueMicrotask from "queue-microtask";
14
+ import { omit } from "timm";
11
15
 
12
- export * from './types';
16
+ export * from "./types";
17
+
18
+ export interface AsyncNodePluginOptions {
19
+ /** A set of plugins to load */
20
+ plugins?: AsyncNodeViewPlugin[];
21
+ }
22
+
23
+ export interface AsyncNodeViewPlugin extends ViewPlugin {
24
+ /** Use this to tap into the async node plugin hooks */
25
+ applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;
26
+
27
+ asyncNode: AsyncParallelBailHook<[Node.Async], any>;
28
+ }
13
29
 
14
30
  /**
15
31
  * Async node plugin used to resolve async nodes in the content
16
32
  * If an async node is present, allow users to provide a replacement node to be rendered when ready
17
33
  */
18
34
  export class AsyncNodePlugin implements PlayerPlugin {
35
+ private plugins: AsyncNodeViewPlugin[] | undefined;
36
+
37
+ constructor(options: AsyncNodePluginOptions) {
38
+ if (options?.plugins) {
39
+ this.plugins = options.plugins;
40
+ options.plugins.forEach((plugin) => {
41
+ plugin.applyPlugin(this);
42
+ });
43
+ }
44
+ }
45
+
19
46
  public readonly hooks = {
20
- onAsyncNode: new AsyncParallelBailHook<[Node.Node], Node.Node>(),
47
+ onAsyncNode: new AsyncParallelBailHook<[Node.Async], any>(),
21
48
  };
22
49
 
23
- name = 'AsyncNode';
50
+ name = "AsyncNode";
51
+
52
+ apply(player: Player) {
53
+ player.hooks.viewController.tap(this.name, (viewController) => {
54
+ viewController.hooks.view.tap(this.name, (view) => {
55
+ this.plugins?.forEach((plugin) => {
56
+ plugin.apply(view);
57
+ });
58
+ });
59
+ });
60
+ }
61
+ }
62
+
63
+ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
64
+ public asyncNode = new AsyncParallelBailHook<[Node.Async], any>();
65
+ private basePlugin: AsyncNodePlugin | undefined;
66
+
67
+ name = "AsyncNode";
68
+
69
+ private resolvedMapping = new Map<string, any>();
24
70
 
25
- private resolvedMapping = new Map<string, Node.Node>();
71
+ private currentView: ViewInstance | undefined;
26
72
 
27
73
  private isAsync(node: Node.Node | null): node is Node.Async {
28
74
  return node?.type === NodeType.Async;
29
75
  }
30
76
 
31
- apply(player: Player) {
32
- player.hooks.viewController.tap(this.name, (viewController) => {
33
- viewController.hooks.view.tap(this.name, (view) => {
34
- view.hooks.parser.tap(this.name, (parser) => {
35
- parser.hooks.determineNodeType.tap(this.name, (obj) => {
36
- if (Object.prototype.hasOwnProperty.call(obj, 'async')) {
37
- return NodeType.Async;
38
- }
39
- });
40
- parser.hooks.parseNode.tap(
41
- this.name,
42
- (
43
- obj: any,
44
- nodeType: Node.ChildrenTypes,
45
- options: ParseObjectOptions,
46
- determinedNodeType: null | NodeType
47
- ) => {
48
- if (determinedNodeType === NodeType.Async) {
49
- const parsedAsync = parser.parseObject(
50
- omit(obj, 'async'),
51
- nodeType,
52
- options
53
- );
54
- const parsedNodeId = getNodeID(parsedAsync);
55
- if (parsedAsync !== null && parsedNodeId) {
56
- return parser.createASTNode(
57
- {
58
- id: parsedNodeId,
59
- type: NodeType.Async,
60
- value: parsedAsync,
61
- },
62
- obj
63
- );
64
- }
65
-
66
- return null;
67
- }
68
- }
77
+ applyParser(parser: Parser) {
78
+ parser.hooks.determineNodeType.tap(this.name, (obj) => {
79
+ if (Object.prototype.hasOwnProperty.call(obj, "async")) {
80
+ return NodeType.Async;
81
+ }
82
+ });
83
+ parser.hooks.parseNode.tap(
84
+ this.name,
85
+ (
86
+ obj: any,
87
+ nodeType: Node.ChildrenTypes,
88
+ options: ParseObjectOptions,
89
+ determinedNodeType: null | NodeType,
90
+ ) => {
91
+ if (determinedNodeType === NodeType.Async) {
92
+ const parsedAsync = parser.parseObject(
93
+ omit(obj, "async"),
94
+ nodeType,
95
+ options,
69
96
  );
97
+ const parsedNodeId = getNodeID(parsedAsync);
98
+ if (parsedAsync !== null && parsedNodeId) {
99
+ return parser.createASTNode(
100
+ {
101
+ id: parsedNodeId,
102
+ type: NodeType.Async,
103
+ value: parsedAsync,
104
+ },
105
+ obj,
106
+ );
107
+ }
108
+
109
+ return null;
110
+ }
111
+ },
112
+ );
113
+ }
114
+
115
+ applyResolverHooks(resolver: Resolver) {
116
+ resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
117
+ let resolvedNode;
118
+ if (this.isAsync(node)) {
119
+ const mappedValue = this.resolvedMapping.get(node.id);
120
+ if (mappedValue) {
121
+ resolvedNode = mappedValue;
122
+ }
123
+ } else {
124
+ resolvedNode = null;
125
+ }
126
+
127
+ const newNode = resolvedNode || node;
128
+ if (!resolvedNode && node?.type === NodeType.Async) {
129
+ queueMicrotask(async () => {
130
+ const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
131
+ const parsedNode =
132
+ options.parseNode && result ? options.parseNode(result) : undefined;
133
+
134
+ if (parsedNode) {
135
+ this.resolvedMapping.set(node.id, parsedNode);
136
+ this.currentView?.updateAsync();
137
+ }
70
138
  });
71
139
 
72
- view.hooks.resolver.tap(this.name, (resolver) => {
73
- resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
74
- let resolvedNode;
75
- if (this.isAsync(node)) {
76
- const mappedValue = this.resolvedMapping.get(node.id);
77
- if (mappedValue) {
78
- resolvedNode = mappedValue;
79
- }
80
- } else {
81
- resolvedNode = null;
82
- }
83
-
84
- const newNode = resolvedNode || node;
85
- if (!resolvedNode && node?.type === NodeType.Async) {
86
- queueMicrotask(async () => {
87
- const result = await this.hooks.onAsyncNode.call(node);
88
- const parsedNode = options.parseNode
89
- ? options.parseNode(result)
90
- : undefined;
91
-
92
- if (parsedNode) {
93
- this.resolvedMapping.set(node.id, parsedNode);
94
- viewController.currentView?.updateAsync();
95
- }
96
- });
97
-
98
- return node;
99
- }
100
-
101
- return newNode;
140
+ return node;
141
+ }
142
+
143
+ return newNode;
144
+ });
145
+ }
146
+
147
+ apply(view: ViewInstance): void {
148
+ view.hooks.parser.tap("template", this.applyParser.bind(this));
149
+ view.hooks.resolver.tap("template", (resolver) => {
150
+ resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
151
+ let resolvedNode;
152
+ if (this.isAsync(node)) {
153
+ const mappedValue = this.resolvedMapping.get(node.id);
154
+ if (mappedValue) {
155
+ resolvedNode = mappedValue;
156
+ }
157
+ } else {
158
+ resolvedNode = null;
159
+ }
160
+
161
+ const newNode = resolvedNode || node;
162
+ if (!resolvedNode && node?.type === NodeType.Async) {
163
+ queueMicrotask(async () => {
164
+ const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
165
+ const parsedNode =
166
+ options.parseNode && result
167
+ ? options.parseNode(result)
168
+ : undefined;
169
+
170
+ this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
171
+ view.updateAsync();
102
172
  });
103
- });
173
+
174
+ return node;
175
+ }
176
+
177
+ return newNode;
104
178
  });
105
179
  });
106
180
  }
181
+
182
+ applyPlugin(asyncNodePlugin: AsyncNodePlugin): void {
183
+ this.basePlugin = asyncNodePlugin;
184
+ }
107
185
  }
package/src/types.ts CHANGED
@@ -1,6 +1,6 @@
1
- import type { Node } from '@player-ui/player';
1
+ import type { Node } from "@player-ui/player";
2
2
 
3
3
  export type AsyncNodeHandler = (
4
4
  node: Node.Node,
5
- update: (object: any) => void
5
+ update: (object: any) => void,
6
6
  ) => void;
@@ -0,0 +1,38 @@
1
+ import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver } from "@player-ui/player";
2
+ import { AsyncParallelBailHook } from "tapable-ts";
3
+ export * from "./types";
4
+ export interface AsyncNodePluginOptions {
5
+ /** A set of plugins to load */
6
+ plugins?: AsyncNodeViewPlugin[];
7
+ }
8
+ export interface AsyncNodeViewPlugin extends ViewPlugin {
9
+ /** Use this to tap into the async node plugin hooks */
10
+ applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;
11
+ asyncNode: AsyncParallelBailHook<[Node.Async], any>;
12
+ }
13
+ /**
14
+ * Async node plugin used to resolve async nodes in the content
15
+ * If an async node is present, allow users to provide a replacement node to be rendered when ready
16
+ */
17
+ export declare class AsyncNodePlugin implements PlayerPlugin {
18
+ private plugins;
19
+ constructor(options: AsyncNodePluginOptions);
20
+ readonly hooks: {
21
+ onAsyncNode: AsyncParallelBailHook<[Node.Async], any, Record<string, any>>;
22
+ };
23
+ name: string;
24
+ apply(player: Player): void;
25
+ }
26
+ export declare class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
27
+ asyncNode: AsyncParallelBailHook<[Node.Async], any, Record<string, any>>;
28
+ private basePlugin;
29
+ name: string;
30
+ private resolvedMapping;
31
+ private currentView;
32
+ private isAsync;
33
+ applyParser(parser: Parser): void;
34
+ applyResolverHooks(resolver: Resolver): void;
35
+ apply(view: ViewInstance): void;
36
+ applyPlugin(asyncNodePlugin: AsyncNodePlugin): void;
37
+ }
38
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,3 @@
1
+ import type { Node } from "@player-ui/player";
2
+ export type AsyncNodeHandler = (node: Node.Node, update: (object: any) => void) => void;
3
+ //# sourceMappingURL=types.d.ts.map