@player-ui/async-node-plugin 0.7.5--canary.449.15808 → 0.7.5--canary.443.15842
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/AsyncNodePlugin.native.js +78 -67
- package/dist/AsyncNodePlugin.native.js.map +1 -1
- package/dist/cjs/index.cjs +51 -53
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +51 -53
- package/dist/index.mjs +51 -53
- package/dist/index.mjs.map +1 -1
- package/package.json +8 -8
- package/src/index.test.ts +9 -105
- package/src/index.ts +67 -74
- package/types/index.d.ts +4 -21
package/dist/cjs/index.cjs
CHANGED
|
@@ -67,56 +67,6 @@ var AsyncNodePluginPlugin = class {
|
|
|
67
67
|
this.name = "AsyncNode";
|
|
68
68
|
this.resolvedMapping = /* @__PURE__ */ new Map();
|
|
69
69
|
}
|
|
70
|
-
/**
|
|
71
|
-
* Updates the node asynchronously based on the result provided.
|
|
72
|
-
* This method is responsible for handling the update logic of asynchronous nodes.
|
|
73
|
-
* It checks if the node needs to be updated based on the new result and updates the mapping accordingly.
|
|
74
|
-
* If an update is necessary, it triggers an asynchronous update on the view.
|
|
75
|
-
* @param node The asynchronous node that might be updated.
|
|
76
|
-
* @param result The result obtained from resolving the async node. This could be any data structure or value.
|
|
77
|
-
* @param options Options provided for node resolution, including a potential parseNode function to process the result.
|
|
78
|
-
* @param view The view instance where the node resides. This can be undefined if the view is not currently active.
|
|
79
|
-
*/
|
|
80
|
-
handleAsyncUpdate(node, result, options, view) {
|
|
81
|
-
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
82
|
-
if (this.resolvedMapping.get(node.id) !== parsedNode) {
|
|
83
|
-
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
84
|
-
view?.updateAsync();
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
/**
|
|
88
|
-
* Handles the asynchronous API integration for resolving nodes.
|
|
89
|
-
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
|
90
|
-
* @param resolver The resolver instance to attach the hook to.
|
|
91
|
-
* @param view
|
|
92
|
-
*/
|
|
93
|
-
applyResolver(resolver) {
|
|
94
|
-
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
95
|
-
let resolvedNode;
|
|
96
|
-
if (this.isAsync(node)) {
|
|
97
|
-
const mappedValue = this.resolvedMapping.get(node.id);
|
|
98
|
-
if (mappedValue) {
|
|
99
|
-
resolvedNode = mappedValue;
|
|
100
|
-
}
|
|
101
|
-
} else {
|
|
102
|
-
resolvedNode = null;
|
|
103
|
-
}
|
|
104
|
-
const newNode = resolvedNode || node;
|
|
105
|
-
if (!resolvedNode && node?.type === import_player.NodeType.Async) {
|
|
106
|
-
(0, import_queue_microtask.default)(async () => {
|
|
107
|
-
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
108
|
-
node,
|
|
109
|
-
(result2) => {
|
|
110
|
-
this.handleAsyncUpdate(node, result2, options, this.currentView);
|
|
111
|
-
}
|
|
112
|
-
);
|
|
113
|
-
this.handleAsyncUpdate(node, result, options, this.currentView);
|
|
114
|
-
});
|
|
115
|
-
return node;
|
|
116
|
-
}
|
|
117
|
-
return newNode;
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
70
|
isAsync(node) {
|
|
121
71
|
return node?.type === import_player.NodeType.Async;
|
|
122
72
|
}
|
|
@@ -151,10 +101,58 @@ var AsyncNodePluginPlugin = class {
|
|
|
151
101
|
}
|
|
152
102
|
);
|
|
153
103
|
}
|
|
104
|
+
applyResolverHooks(resolver) {
|
|
105
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
106
|
+
let resolvedNode;
|
|
107
|
+
if (this.isAsync(node)) {
|
|
108
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
109
|
+
if (mappedValue) {
|
|
110
|
+
resolvedNode = mappedValue;
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
resolvedNode = null;
|
|
114
|
+
}
|
|
115
|
+
const newNode = resolvedNode || node;
|
|
116
|
+
if (!resolvedNode && node?.type === import_player.NodeType.Async) {
|
|
117
|
+
(0, import_queue_microtask.default)(async () => {
|
|
118
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
119
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
120
|
+
if (parsedNode) {
|
|
121
|
+
this.resolvedMapping.set(node.id, parsedNode);
|
|
122
|
+
this.currentView?.updateAsync();
|
|
123
|
+
}
|
|
124
|
+
});
|
|
125
|
+
return node;
|
|
126
|
+
}
|
|
127
|
+
return newNode;
|
|
128
|
+
});
|
|
129
|
+
}
|
|
154
130
|
apply(view) {
|
|
155
|
-
this.
|
|
156
|
-
view.hooks.
|
|
157
|
-
|
|
131
|
+
view.hooks.parser.tap("template", this.applyParser.bind(this));
|
|
132
|
+
view.hooks.resolver.tap("template", (resolver) => {
|
|
133
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
134
|
+
let resolvedNode;
|
|
135
|
+
if (this.isAsync(node)) {
|
|
136
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
137
|
+
if (mappedValue) {
|
|
138
|
+
resolvedNode = mappedValue;
|
|
139
|
+
}
|
|
140
|
+
} else {
|
|
141
|
+
resolvedNode = null;
|
|
142
|
+
}
|
|
143
|
+
const newNode = resolvedNode || node;
|
|
144
|
+
if (!resolvedNode && node?.type === import_player.NodeType.Async) {
|
|
145
|
+
(0, import_queue_microtask.default)(async () => {
|
|
146
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
147
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
148
|
+
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
149
|
+
view.updateAsync();
|
|
150
|
+
});
|
|
151
|
+
return node;
|
|
152
|
+
}
|
|
153
|
+
return newNode;
|
|
154
|
+
});
|
|
155
|
+
});
|
|
158
156
|
}
|
|
159
157
|
applyPlugin(asyncNodePlugin) {
|
|
160
158
|
this.basePlugin = asyncNodePlugin;
|
package/dist/cjs/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/index.ts"],"sourcesContent":["import { NodeType, getNodeID } from \"@player-ui/player\";\nimport type {\n Player,\n PlayerPlugin,\n Node,\n ParseObjectOptions,\n ViewInstance,\n Parser,\n ViewPlugin,\n Resolver,\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/index.ts"],"sourcesContent":["import { NodeType, getNodeID } from \"@player-ui/player\";\nimport type {\n Player,\n PlayerPlugin,\n Node,\n ParseObjectOptions,\n ViewInstance,\n Parser,\n ViewPlugin,\n Resolver,\n} from \"@player-ui/player\";\nimport { AsyncParallelBailHook } from \"tapable-ts\";\nimport queueMicrotask from \"queue-microtask\";\nimport { omit } from \"timm\";\n\nexport * from \"./types\";\n\nexport interface AsyncNodePluginOptions {\n /** A set of plugins to load */\n plugins?: AsyncNodeViewPlugin[];\n}\n\nexport interface AsyncNodeViewPlugin extends ViewPlugin {\n /** Use this to tap into the async node plugin hooks */\n applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;\n\n asyncNode: AsyncParallelBailHook<[Node.Async], any>;\n}\n\n/**\n * Async node plugin used to resolve async nodes in the content\n * If an async node is present, allow users to provide a replacement node to be rendered when ready\n */\nexport class AsyncNodePlugin implements PlayerPlugin {\n private plugins: AsyncNodeViewPlugin[] | undefined;\n\n constructor(options: AsyncNodePluginOptions) {\n if (options?.plugins) {\n this.plugins = options.plugins;\n options.plugins.forEach((plugin) => {\n plugin.applyPlugin(this);\n });\n }\n }\n\n public readonly hooks = {\n onAsyncNode: new AsyncParallelBailHook<[Node.Async], any>(),\n };\n\n name = \"AsyncNode\";\n\n apply(player: Player) {\n player.hooks.viewController.tap(this.name, (viewController) => {\n viewController.hooks.view.tap(this.name, (view) => {\n this.plugins?.forEach((plugin) => {\n plugin.apply(view);\n });\n });\n });\n }\n}\n\nexport class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {\n public asyncNode = new AsyncParallelBailHook<[Node.Async], any>();\n private basePlugin: AsyncNodePlugin | undefined;\n\n name = \"AsyncNode\";\n\n private resolvedMapping = new Map<string, any>();\n\n private currentView: ViewInstance | undefined;\n\n private isAsync(node: Node.Node | null): node is Node.Async {\n return node?.type === NodeType.Async;\n }\n\n applyParser(parser: Parser) {\n parser.hooks.determineNodeType.tap(this.name, (obj) => {\n if (Object.prototype.hasOwnProperty.call(obj, \"async\")) {\n return NodeType.Async;\n }\n });\n parser.hooks.parseNode.tap(\n this.name,\n (\n obj: any,\n nodeType: Node.ChildrenTypes,\n options: ParseObjectOptions,\n determinedNodeType: null | NodeType,\n ) => {\n if (determinedNodeType === NodeType.Async) {\n const parsedAsync = parser.parseObject(\n omit(obj, \"async\"),\n nodeType,\n options,\n );\n const parsedNodeId = getNodeID(parsedAsync);\n if (parsedAsync !== null && parsedNodeId) {\n return parser.createASTNode(\n {\n id: parsedNodeId,\n type: NodeType.Async,\n value: parsedAsync,\n },\n obj,\n );\n }\n\n return null;\n }\n },\n );\n }\n\n applyResolverHooks(resolver: Resolver) {\n resolver.hooks.beforeResolve.tap(this.name, (node, options) => {\n let resolvedNode;\n if (this.isAsync(node)) {\n const mappedValue = this.resolvedMapping.get(node.id);\n if (mappedValue) {\n resolvedNode = mappedValue;\n }\n } else {\n resolvedNode = null;\n }\n\n const newNode = resolvedNode || node;\n if (!resolvedNode && node?.type === NodeType.Async) {\n queueMicrotask(async () => {\n const result = await this.basePlugin?.hooks.onAsyncNode.call(node);\n const parsedNode =\n options.parseNode && result ? options.parseNode(result) : undefined;\n\n if (parsedNode) {\n this.resolvedMapping.set(node.id, parsedNode);\n this.currentView?.updateAsync();\n }\n });\n\n return node;\n }\n\n return newNode;\n });\n }\n\n apply(view: ViewInstance): void {\n view.hooks.parser.tap(\"template\", this.applyParser.bind(this));\n view.hooks.resolver.tap(\"template\", (resolver) => {\n resolver.hooks.beforeResolve.tap(this.name, (node, options) => {\n let resolvedNode;\n if (this.isAsync(node)) {\n const mappedValue = this.resolvedMapping.get(node.id);\n if (mappedValue) {\n resolvedNode = mappedValue;\n }\n } else {\n resolvedNode = null;\n }\n\n const newNode = resolvedNode || node;\n if (!resolvedNode && node?.type === NodeType.Async) {\n queueMicrotask(async () => {\n const result = await this.basePlugin?.hooks.onAsyncNode.call(node);\n const parsedNode =\n options.parseNode && result\n ? options.parseNode(result)\n : undefined;\n\n this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);\n view.updateAsync();\n });\n\n return node;\n }\n\n return newNode;\n });\n });\n }\n\n applyPlugin(asyncNodePlugin: AsyncNodePlugin): void {\n this.basePlugin = asyncNodePlugin;\n }\n}\n"],"mappings":"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","names":["queueMicrotask"]}
|
package/dist/index.legacy-esm.js
CHANGED
|
@@ -32,56 +32,6 @@ var AsyncNodePluginPlugin = class {
|
|
|
32
32
|
this.name = "AsyncNode";
|
|
33
33
|
this.resolvedMapping = /* @__PURE__ */ new Map();
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Updates the node asynchronously based on the result provided.
|
|
37
|
-
* This method is responsible for handling the update logic of asynchronous nodes.
|
|
38
|
-
* It checks if the node needs to be updated based on the new result and updates the mapping accordingly.
|
|
39
|
-
* If an update is necessary, it triggers an asynchronous update on the view.
|
|
40
|
-
* @param node The asynchronous node that might be updated.
|
|
41
|
-
* @param result The result obtained from resolving the async node. This could be any data structure or value.
|
|
42
|
-
* @param options Options provided for node resolution, including a potential parseNode function to process the result.
|
|
43
|
-
* @param view The view instance where the node resides. This can be undefined if the view is not currently active.
|
|
44
|
-
*/
|
|
45
|
-
handleAsyncUpdate(node, result, options, view) {
|
|
46
|
-
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
47
|
-
if (this.resolvedMapping.get(node.id) !== parsedNode) {
|
|
48
|
-
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
49
|
-
view?.updateAsync();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Handles the asynchronous API integration for resolving nodes.
|
|
54
|
-
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
|
55
|
-
* @param resolver The resolver instance to attach the hook to.
|
|
56
|
-
* @param view
|
|
57
|
-
*/
|
|
58
|
-
applyResolver(resolver) {
|
|
59
|
-
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
60
|
-
let resolvedNode;
|
|
61
|
-
if (this.isAsync(node)) {
|
|
62
|
-
const mappedValue = this.resolvedMapping.get(node.id);
|
|
63
|
-
if (mappedValue) {
|
|
64
|
-
resolvedNode = mappedValue;
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
resolvedNode = null;
|
|
68
|
-
}
|
|
69
|
-
const newNode = resolvedNode || node;
|
|
70
|
-
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
71
|
-
queueMicrotask(async () => {
|
|
72
|
-
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
73
|
-
node,
|
|
74
|
-
(result2) => {
|
|
75
|
-
this.handleAsyncUpdate(node, result2, options, this.currentView);
|
|
76
|
-
}
|
|
77
|
-
);
|
|
78
|
-
this.handleAsyncUpdate(node, result, options, this.currentView);
|
|
79
|
-
});
|
|
80
|
-
return node;
|
|
81
|
-
}
|
|
82
|
-
return newNode;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
35
|
isAsync(node) {
|
|
86
36
|
return node?.type === NodeType.Async;
|
|
87
37
|
}
|
|
@@ -116,10 +66,58 @@ var AsyncNodePluginPlugin = class {
|
|
|
116
66
|
}
|
|
117
67
|
);
|
|
118
68
|
}
|
|
69
|
+
applyResolverHooks(resolver) {
|
|
70
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
71
|
+
let resolvedNode;
|
|
72
|
+
if (this.isAsync(node)) {
|
|
73
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
74
|
+
if (mappedValue) {
|
|
75
|
+
resolvedNode = mappedValue;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
resolvedNode = null;
|
|
79
|
+
}
|
|
80
|
+
const newNode = resolvedNode || node;
|
|
81
|
+
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
82
|
+
queueMicrotask(async () => {
|
|
83
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
84
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
85
|
+
if (parsedNode) {
|
|
86
|
+
this.resolvedMapping.set(node.id, parsedNode);
|
|
87
|
+
this.currentView?.updateAsync();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return node;
|
|
91
|
+
}
|
|
92
|
+
return newNode;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
119
95
|
apply(view) {
|
|
120
|
-
this.
|
|
121
|
-
view.hooks.
|
|
122
|
-
|
|
96
|
+
view.hooks.parser.tap("template", this.applyParser.bind(this));
|
|
97
|
+
view.hooks.resolver.tap("template", (resolver) => {
|
|
98
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
99
|
+
let resolvedNode;
|
|
100
|
+
if (this.isAsync(node)) {
|
|
101
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
102
|
+
if (mappedValue) {
|
|
103
|
+
resolvedNode = mappedValue;
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
resolvedNode = null;
|
|
107
|
+
}
|
|
108
|
+
const newNode = resolvedNode || node;
|
|
109
|
+
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
110
|
+
queueMicrotask(async () => {
|
|
111
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
112
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
113
|
+
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
114
|
+
view.updateAsync();
|
|
115
|
+
});
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
return newNode;
|
|
119
|
+
});
|
|
120
|
+
});
|
|
123
121
|
}
|
|
124
122
|
applyPlugin(asyncNodePlugin) {
|
|
125
123
|
this.basePlugin = asyncNodePlugin;
|
package/dist/index.mjs
CHANGED
|
@@ -32,56 +32,6 @@ var AsyncNodePluginPlugin = class {
|
|
|
32
32
|
this.name = "AsyncNode";
|
|
33
33
|
this.resolvedMapping = /* @__PURE__ */ new Map();
|
|
34
34
|
}
|
|
35
|
-
/**
|
|
36
|
-
* Updates the node asynchronously based on the result provided.
|
|
37
|
-
* This method is responsible for handling the update logic of asynchronous nodes.
|
|
38
|
-
* It checks if the node needs to be updated based on the new result and updates the mapping accordingly.
|
|
39
|
-
* If an update is necessary, it triggers an asynchronous update on the view.
|
|
40
|
-
* @param node The asynchronous node that might be updated.
|
|
41
|
-
* @param result The result obtained from resolving the async node. This could be any data structure or value.
|
|
42
|
-
* @param options Options provided for node resolution, including a potential parseNode function to process the result.
|
|
43
|
-
* @param view The view instance where the node resides. This can be undefined if the view is not currently active.
|
|
44
|
-
*/
|
|
45
|
-
handleAsyncUpdate(node, result, options, view) {
|
|
46
|
-
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
47
|
-
if (this.resolvedMapping.get(node.id) !== parsedNode) {
|
|
48
|
-
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
49
|
-
view?.updateAsync();
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* Handles the asynchronous API integration for resolving nodes.
|
|
54
|
-
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
|
55
|
-
* @param resolver The resolver instance to attach the hook to.
|
|
56
|
-
* @param view
|
|
57
|
-
*/
|
|
58
|
-
applyResolver(resolver) {
|
|
59
|
-
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
60
|
-
let resolvedNode;
|
|
61
|
-
if (this.isAsync(node)) {
|
|
62
|
-
const mappedValue = this.resolvedMapping.get(node.id);
|
|
63
|
-
if (mappedValue) {
|
|
64
|
-
resolvedNode = mappedValue;
|
|
65
|
-
}
|
|
66
|
-
} else {
|
|
67
|
-
resolvedNode = null;
|
|
68
|
-
}
|
|
69
|
-
const newNode = resolvedNode || node;
|
|
70
|
-
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
71
|
-
queueMicrotask(async () => {
|
|
72
|
-
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
73
|
-
node,
|
|
74
|
-
(result2) => {
|
|
75
|
-
this.handleAsyncUpdate(node, result2, options, this.currentView);
|
|
76
|
-
}
|
|
77
|
-
);
|
|
78
|
-
this.handleAsyncUpdate(node, result, options, this.currentView);
|
|
79
|
-
});
|
|
80
|
-
return node;
|
|
81
|
-
}
|
|
82
|
-
return newNode;
|
|
83
|
-
});
|
|
84
|
-
}
|
|
85
35
|
isAsync(node) {
|
|
86
36
|
return node?.type === NodeType.Async;
|
|
87
37
|
}
|
|
@@ -116,10 +66,58 @@ var AsyncNodePluginPlugin = class {
|
|
|
116
66
|
}
|
|
117
67
|
);
|
|
118
68
|
}
|
|
69
|
+
applyResolverHooks(resolver) {
|
|
70
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
71
|
+
let resolvedNode;
|
|
72
|
+
if (this.isAsync(node)) {
|
|
73
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
74
|
+
if (mappedValue) {
|
|
75
|
+
resolvedNode = mappedValue;
|
|
76
|
+
}
|
|
77
|
+
} else {
|
|
78
|
+
resolvedNode = null;
|
|
79
|
+
}
|
|
80
|
+
const newNode = resolvedNode || node;
|
|
81
|
+
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
82
|
+
queueMicrotask(async () => {
|
|
83
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
84
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
85
|
+
if (parsedNode) {
|
|
86
|
+
this.resolvedMapping.set(node.id, parsedNode);
|
|
87
|
+
this.currentView?.updateAsync();
|
|
88
|
+
}
|
|
89
|
+
});
|
|
90
|
+
return node;
|
|
91
|
+
}
|
|
92
|
+
return newNode;
|
|
93
|
+
});
|
|
94
|
+
}
|
|
119
95
|
apply(view) {
|
|
120
|
-
this.
|
|
121
|
-
view.hooks.
|
|
122
|
-
|
|
96
|
+
view.hooks.parser.tap("template", this.applyParser.bind(this));
|
|
97
|
+
view.hooks.resolver.tap("template", (resolver) => {
|
|
98
|
+
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
99
|
+
let resolvedNode;
|
|
100
|
+
if (this.isAsync(node)) {
|
|
101
|
+
const mappedValue = this.resolvedMapping.get(node.id);
|
|
102
|
+
if (mappedValue) {
|
|
103
|
+
resolvedNode = mappedValue;
|
|
104
|
+
}
|
|
105
|
+
} else {
|
|
106
|
+
resolvedNode = null;
|
|
107
|
+
}
|
|
108
|
+
const newNode = resolvedNode || node;
|
|
109
|
+
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
110
|
+
queueMicrotask(async () => {
|
|
111
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(node);
|
|
112
|
+
const parsedNode = options.parseNode && result ? options.parseNode(result) : void 0;
|
|
113
|
+
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
114
|
+
view.updateAsync();
|
|
115
|
+
});
|
|
116
|
+
return node;
|
|
117
|
+
}
|
|
118
|
+
return newNode;
|
|
119
|
+
});
|
|
120
|
+
});
|
|
123
121
|
}
|
|
124
122
|
applyPlugin(asyncNodePlugin) {
|
|
125
123
|
this.basePlugin = asyncNodePlugin;
|
package/dist/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/index.ts"],"sourcesContent":["import { NodeType, getNodeID } from \"@player-ui/player\";\nimport type {\n Player,\n PlayerPlugin,\n Node,\n ParseObjectOptions,\n ViewInstance,\n Parser,\n ViewPlugin,\n Resolver,\n
|
|
1
|
+
{"version":3,"sources":["../../../../../../../../../../../../execroot/_main/bazel-out/k8-fastbuild/bin/plugins/async-node/core/src/index.ts"],"sourcesContent":["import { NodeType, getNodeID } from \"@player-ui/player\";\nimport type {\n Player,\n PlayerPlugin,\n Node,\n ParseObjectOptions,\n ViewInstance,\n Parser,\n ViewPlugin,\n Resolver,\n} from \"@player-ui/player\";\nimport { AsyncParallelBailHook } from \"tapable-ts\";\nimport queueMicrotask from \"queue-microtask\";\nimport { omit } from \"timm\";\n\nexport * from \"./types\";\n\nexport interface AsyncNodePluginOptions {\n /** A set of plugins to load */\n plugins?: AsyncNodeViewPlugin[];\n}\n\nexport interface AsyncNodeViewPlugin extends ViewPlugin {\n /** Use this to tap into the async node plugin hooks */\n applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;\n\n asyncNode: AsyncParallelBailHook<[Node.Async], any>;\n}\n\n/**\n * Async node plugin used to resolve async nodes in the content\n * If an async node is present, allow users to provide a replacement node to be rendered when ready\n */\nexport class AsyncNodePlugin implements PlayerPlugin {\n private plugins: AsyncNodeViewPlugin[] | undefined;\n\n constructor(options: AsyncNodePluginOptions) {\n if (options?.plugins) {\n this.plugins = options.plugins;\n options.plugins.forEach((plugin) => {\n plugin.applyPlugin(this);\n });\n }\n }\n\n public readonly hooks = {\n onAsyncNode: new AsyncParallelBailHook<[Node.Async], any>(),\n };\n\n name = \"AsyncNode\";\n\n apply(player: Player) {\n player.hooks.viewController.tap(this.name, (viewController) => {\n viewController.hooks.view.tap(this.name, (view) => {\n this.plugins?.forEach((plugin) => {\n plugin.apply(view);\n });\n });\n });\n }\n}\n\nexport class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {\n public asyncNode = new AsyncParallelBailHook<[Node.Async], any>();\n private basePlugin: AsyncNodePlugin | undefined;\n\n name = \"AsyncNode\";\n\n private resolvedMapping = new Map<string, any>();\n\n private currentView: ViewInstance | undefined;\n\n private isAsync(node: Node.Node | null): node is Node.Async {\n return node?.type === NodeType.Async;\n }\n\n applyParser(parser: Parser) {\n parser.hooks.determineNodeType.tap(this.name, (obj) => {\n if (Object.prototype.hasOwnProperty.call(obj, \"async\")) {\n return NodeType.Async;\n }\n });\n parser.hooks.parseNode.tap(\n this.name,\n (\n obj: any,\n nodeType: Node.ChildrenTypes,\n options: ParseObjectOptions,\n determinedNodeType: null | NodeType,\n ) => {\n if (determinedNodeType === NodeType.Async) {\n const parsedAsync = parser.parseObject(\n omit(obj, \"async\"),\n nodeType,\n options,\n );\n const parsedNodeId = getNodeID(parsedAsync);\n if (parsedAsync !== null && parsedNodeId) {\n return parser.createASTNode(\n {\n id: parsedNodeId,\n type: NodeType.Async,\n value: parsedAsync,\n },\n obj,\n );\n }\n\n return null;\n }\n },\n );\n }\n\n applyResolverHooks(resolver: Resolver) {\n resolver.hooks.beforeResolve.tap(this.name, (node, options) => {\n let resolvedNode;\n if (this.isAsync(node)) {\n const mappedValue = this.resolvedMapping.get(node.id);\n if (mappedValue) {\n resolvedNode = mappedValue;\n }\n } else {\n resolvedNode = null;\n }\n\n const newNode = resolvedNode || node;\n if (!resolvedNode && node?.type === NodeType.Async) {\n queueMicrotask(async () => {\n const result = await this.basePlugin?.hooks.onAsyncNode.call(node);\n const parsedNode =\n options.parseNode && result ? options.parseNode(result) : undefined;\n\n if (parsedNode) {\n this.resolvedMapping.set(node.id, parsedNode);\n this.currentView?.updateAsync();\n }\n });\n\n return node;\n }\n\n return newNode;\n });\n }\n\n apply(view: ViewInstance): void {\n view.hooks.parser.tap(\"template\", this.applyParser.bind(this));\n view.hooks.resolver.tap(\"template\", (resolver) => {\n resolver.hooks.beforeResolve.tap(this.name, (node, options) => {\n let resolvedNode;\n if (this.isAsync(node)) {\n const mappedValue = this.resolvedMapping.get(node.id);\n if (mappedValue) {\n resolvedNode = mappedValue;\n }\n } else {\n resolvedNode = null;\n }\n\n const newNode = resolvedNode || node;\n if (!resolvedNode && node?.type === NodeType.Async) {\n queueMicrotask(async () => {\n const result = await this.basePlugin?.hooks.onAsyncNode.call(node);\n const parsedNode =\n options.parseNode && result\n ? options.parseNode(result)\n : undefined;\n\n this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);\n view.updateAsync();\n });\n\n return node;\n }\n\n return newNode;\n });\n });\n }\n\n applyPlugin(asyncNodePlugin: AsyncNodePlugin): void {\n this.basePlugin = asyncNodePlugin;\n }\n}\n"],"mappings":"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","names":[]}
|
package/package.json
CHANGED
|
@@ -1,19 +1,14 @@
|
|
|
1
1
|
{
|
|
2
|
-
"sideEffects": false,
|
|
3
|
-
"files": [
|
|
4
|
-
"dist",
|
|
5
|
-
"src",
|
|
6
|
-
"types"
|
|
7
|
-
],
|
|
8
2
|
"name": "@player-ui/async-node-plugin",
|
|
9
|
-
"version": "0.7.5--canary.
|
|
3
|
+
"version": "0.7.5--canary.443.15842",
|
|
10
4
|
"main": "dist/cjs/index.cjs",
|
|
11
5
|
"peerDependencies": {
|
|
12
|
-
"@player-ui/player": "0.7.5--canary.
|
|
6
|
+
"@player-ui/player": "0.7.5--canary.443.15842"
|
|
13
7
|
},
|
|
14
8
|
"module": "dist/index.legacy-esm.js",
|
|
15
9
|
"types": "types/index.d.ts",
|
|
16
10
|
"bundle": "dist/AsyncNodePlugin.native.js",
|
|
11
|
+
"sideEffects": false,
|
|
17
12
|
"exports": {
|
|
18
13
|
"./package.json": "./package.json",
|
|
19
14
|
"./dist/index.css": "./dist/index.css",
|
|
@@ -23,6 +18,11 @@
|
|
|
23
18
|
"default": "./dist/cjs/index.cjs"
|
|
24
19
|
}
|
|
25
20
|
},
|
|
21
|
+
"files": [
|
|
22
|
+
"dist",
|
|
23
|
+
"src",
|
|
24
|
+
"types"
|
|
25
|
+
],
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"queue-microtask": "^1.2.3",
|
|
28
28
|
"tapable-ts": "^0.2.3",
|
package/src/index.test.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, test
|
|
1
|
+
import { expect, test } from "vitest";
|
|
2
2
|
import { Node, InProgressState, ViewInstance } from "@player-ui/player";
|
|
3
3
|
import { Player } from "@player-ui/player";
|
|
4
4
|
import { waitFor } from "@testing-library/react";
|
|
@@ -44,20 +44,11 @@ const asyncNodeTest = async (resolvedValue: any) => {
|
|
|
44
44
|
|
|
45
45
|
let deferredResolve: ((value: any) => void) | undefined;
|
|
46
46
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const result = new Promise((resolve) => {
|
|
53
|
-
deferredResolve = resolve; // Promise would be resolved only once
|
|
54
|
-
});
|
|
55
|
-
|
|
56
|
-
updateContent = update;
|
|
57
|
-
// Return the result to follow the same mechanism as before
|
|
58
|
-
return result;
|
|
59
|
-
},
|
|
60
|
-
);
|
|
47
|
+
plugin.hooks.onAsyncNode.tap("test", async (node: Node.Async) => {
|
|
48
|
+
return new Promise((resolve) => {
|
|
49
|
+
deferredResolve = resolve; // Promise would be resolved only once
|
|
50
|
+
});
|
|
51
|
+
});
|
|
61
52
|
|
|
62
53
|
let updateNumber = 0;
|
|
63
54
|
|
|
@@ -93,7 +84,7 @@ const asyncNodeTest = async (resolvedValue: any) => {
|
|
|
93
84
|
}
|
|
94
85
|
|
|
95
86
|
await waitFor(() => {
|
|
96
|
-
expect(updateNumber).toBe(
|
|
87
|
+
expect(updateNumber).toBe(2);
|
|
97
88
|
});
|
|
98
89
|
|
|
99
90
|
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
@@ -102,14 +93,10 @@ const asyncNodeTest = async (resolvedValue: any) => {
|
|
|
102
93
|
expect(view?.actions[0].asset.type).toBe("action");
|
|
103
94
|
expect(view?.actions.length).toBe(1);
|
|
104
95
|
|
|
105
|
-
|
|
106
|
-
if (deferredResolve) {
|
|
107
|
-
updateContent(resolvedValue);
|
|
108
|
-
}
|
|
96
|
+
viewInstance?.update();
|
|
109
97
|
|
|
110
|
-
//Even after an update, the view should not change as we are deleting the resolved node if there is no view update
|
|
111
98
|
await waitFor(() => {
|
|
112
|
-
expect(updateNumber).toBe(
|
|
99
|
+
expect(updateNumber).toBe(3);
|
|
113
100
|
});
|
|
114
101
|
|
|
115
102
|
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
@@ -127,89 +114,6 @@ test("should return current node view when the resolved node is undefined", asyn
|
|
|
127
114
|
await asyncNodeTest(undefined);
|
|
128
115
|
});
|
|
129
116
|
|
|
130
|
-
test("can handle multiple updates through callback mechanism", async () => {
|
|
131
|
-
const plugin = new AsyncNodePlugin({
|
|
132
|
-
plugins: [new AsyncNodePluginPlugin()],
|
|
133
|
-
});
|
|
134
|
-
|
|
135
|
-
let deferredResolve: ((value: any) => void) | undefined;
|
|
136
|
-
|
|
137
|
-
let updateContent: any;
|
|
138
|
-
|
|
139
|
-
plugin.hooks.onAsyncNode.tap(
|
|
140
|
-
"test",
|
|
141
|
-
async (node: Node.Async, update: (content: any) => void) => {
|
|
142
|
-
const result = new Promise((resolve) => {
|
|
143
|
-
deferredResolve = resolve; // Promise would be resolved only once
|
|
144
|
-
});
|
|
145
|
-
|
|
146
|
-
updateContent = update;
|
|
147
|
-
// Return the result to follow the same mechanism as before
|
|
148
|
-
return result;
|
|
149
|
-
},
|
|
150
|
-
);
|
|
151
|
-
|
|
152
|
-
let updateNumber = 0;
|
|
153
|
-
|
|
154
|
-
const player = new Player({ plugins: [plugin] });
|
|
155
|
-
|
|
156
|
-
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
157
|
-
vc.hooks.view.tap("async-node-test", (view) => {
|
|
158
|
-
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
159
|
-
updateNumber++;
|
|
160
|
-
});
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
|
|
164
|
-
player.start(basicFRFWithActions as any);
|
|
165
|
-
|
|
166
|
-
let view = (player.getState() as InProgressState).controllers.view.currentView
|
|
167
|
-
?.lastUpdate;
|
|
168
|
-
|
|
169
|
-
expect(view).toBeDefined();
|
|
170
|
-
expect(view?.actions[1]).toBeUndefined();
|
|
171
|
-
|
|
172
|
-
await waitFor(() => {
|
|
173
|
-
expect(updateNumber).toBe(1);
|
|
174
|
-
expect(deferredResolve).toBeDefined();
|
|
175
|
-
});
|
|
176
|
-
|
|
177
|
-
if (deferredResolve) {
|
|
178
|
-
deferredResolve({
|
|
179
|
-
asset: {
|
|
180
|
-
id: "next-label-action",
|
|
181
|
-
type: "action",
|
|
182
|
-
value: "dummy value",
|
|
183
|
-
},
|
|
184
|
-
});
|
|
185
|
-
}
|
|
186
|
-
|
|
187
|
-
await waitFor(() => {
|
|
188
|
-
expect(updateNumber).toBe(2);
|
|
189
|
-
});
|
|
190
|
-
|
|
191
|
-
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
192
|
-
?.lastUpdate;
|
|
193
|
-
|
|
194
|
-
expect(view?.actions[0].asset.type).toBe("action");
|
|
195
|
-
expect(view?.actions[1].asset.type).toBe("action");
|
|
196
|
-
expect(updateNumber).toBe(2);
|
|
197
|
-
|
|
198
|
-
if (deferredResolve) {
|
|
199
|
-
updateContent(null);
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
await waitFor(() => {
|
|
203
|
-
expect(updateNumber).toBe(3);
|
|
204
|
-
});
|
|
205
|
-
|
|
206
|
-
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
207
|
-
?.lastUpdate;
|
|
208
|
-
|
|
209
|
-
expect(view?.actions[0].asset.type).toBe("action");
|
|
210
|
-
expect(view?.actions[1]).toBeUndefined();
|
|
211
|
-
});
|
|
212
|
-
|
|
213
117
|
test("replaces async nodes with provided node", async () => {
|
|
214
118
|
const plugin = new AsyncNodePlugin({
|
|
215
119
|
plugins: [new AsyncNodePluginPlugin()],
|