@player-ui/async-node-plugin 0.8.0-next.3 → 0.8.0-next.5
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 +294 -324
- package/dist/AsyncNodePlugin.native.js.map +1 -1
- package/dist/cjs/index.cjs +73 -64
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +73 -64
- package/dist/index.mjs +73 -64
- package/dist/index.mjs.map +1 -1
- package/package.json +2 -2
- package/src/index.test.ts +443 -327
- package/src/index.ts +101 -80
- package/types/index.d.ts +22 -4
package/src/index.ts
CHANGED
|
@@ -4,10 +4,12 @@ import type {
|
|
|
4
4
|
PlayerPlugin,
|
|
5
5
|
Node,
|
|
6
6
|
ParseObjectOptions,
|
|
7
|
+
ParseObjectChildOptions,
|
|
7
8
|
ViewInstance,
|
|
8
9
|
Parser,
|
|
9
10
|
ViewPlugin,
|
|
10
11
|
Resolver,
|
|
12
|
+
Resolve,
|
|
11
13
|
} from "@player-ui/player";
|
|
12
14
|
import { AsyncParallelBailHook } from "tapable-ts";
|
|
13
15
|
import queueMicrotask from "queue-microtask";
|
|
@@ -24,7 +26,7 @@ export interface AsyncNodeViewPlugin extends ViewPlugin {
|
|
|
24
26
|
/** Use this to tap into the async node plugin hooks */
|
|
25
27
|
applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;
|
|
26
28
|
|
|
27
|
-
asyncNode: AsyncParallelBailHook<[Node.Async], any>;
|
|
29
|
+
asyncNode: AsyncParallelBailHook<[Node.Async, (result: any) => void], any>;
|
|
28
30
|
}
|
|
29
31
|
|
|
30
32
|
/**
|
|
@@ -44,7 +46,10 @@ export class AsyncNodePlugin implements PlayerPlugin {
|
|
|
44
46
|
}
|
|
45
47
|
|
|
46
48
|
public readonly hooks = {
|
|
47
|
-
onAsyncNode: new AsyncParallelBailHook<
|
|
49
|
+
onAsyncNode: new AsyncParallelBailHook<
|
|
50
|
+
[Node.Async, (result: any) => void],
|
|
51
|
+
any
|
|
52
|
+
>(),
|
|
48
53
|
};
|
|
49
54
|
|
|
50
55
|
name = "AsyncNode";
|
|
@@ -61,7 +66,10 @@ export class AsyncNodePlugin implements PlayerPlugin {
|
|
|
61
66
|
}
|
|
62
67
|
|
|
63
68
|
export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
64
|
-
public asyncNode = new AsyncParallelBailHook<
|
|
69
|
+
public asyncNode = new AsyncParallelBailHook<
|
|
70
|
+
[Node.Async, (result: any) => void],
|
|
71
|
+
any
|
|
72
|
+
>();
|
|
65
73
|
private basePlugin: AsyncNodePlugin | undefined;
|
|
66
74
|
|
|
67
75
|
name = "AsyncNode";
|
|
@@ -70,49 +78,38 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
70
78
|
|
|
71
79
|
private currentView: ViewInstance | undefined;
|
|
72
80
|
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
)
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
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
|
-
);
|
|
81
|
+
/**
|
|
82
|
+
* Updates the node asynchronously based on the result provided.
|
|
83
|
+
* This method is responsible for handling the update logic of asynchronous nodes.
|
|
84
|
+
* It checks if the node needs to be updated based on the new result and updates the mapping accordingly.
|
|
85
|
+
* If an update is necessary, it triggers an asynchronous update on the view.
|
|
86
|
+
* @param node The asynchronous node that might be updated.
|
|
87
|
+
* @param result The result obtained from resolving the async node. This could be any data structure or value.
|
|
88
|
+
* @param options Options provided for node resolution, including a potential parseNode function to process the result.
|
|
89
|
+
* @param view The view instance where the node resides. This can be undefined if the view is not currently active.
|
|
90
|
+
*/
|
|
91
|
+
private handleAsyncUpdate(
|
|
92
|
+
node: Node.Async,
|
|
93
|
+
result: any,
|
|
94
|
+
options: Resolve.NodeResolveOptions,
|
|
95
|
+
view: ViewInstance | undefined,
|
|
96
|
+
) {
|
|
97
|
+
const parsedNode =
|
|
98
|
+
options.parseNode && result ? options.parseNode(result) : undefined;
|
|
99
|
+
|
|
100
|
+
if (this.resolvedMapping.get(node.id) !== parsedNode) {
|
|
101
|
+
this.resolvedMapping.set(node.id, parsedNode ? parsedNode : node);
|
|
102
|
+
view?.updateAsync();
|
|
103
|
+
}
|
|
113
104
|
}
|
|
114
105
|
|
|
115
|
-
|
|
106
|
+
/**
|
|
107
|
+
* Handles the asynchronous API integration for resolving nodes.
|
|
108
|
+
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
|
109
|
+
* @param resolver The resolver instance to attach the hook to.
|
|
110
|
+
* @param view
|
|
111
|
+
*/
|
|
112
|
+
applyResolver(resolver: Resolver) {
|
|
116
113
|
resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
|
|
117
114
|
let resolvedNode;
|
|
118
115
|
if (this.isAsync(node)) {
|
|
@@ -127,56 +124,80 @@ export class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
|
127
124
|
const newNode = resolvedNode || node;
|
|
128
125
|
if (!resolvedNode && node?.type === NodeType.Async) {
|
|
129
126
|
queueMicrotask(async () => {
|
|
130
|
-
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
}
|
|
127
|
+
const result = await this.basePlugin?.hooks.onAsyncNode.call(
|
|
128
|
+
node,
|
|
129
|
+
(result) => {
|
|
130
|
+
this.handleAsyncUpdate(node, result, options, this.currentView);
|
|
131
|
+
},
|
|
132
|
+
);
|
|
133
|
+
this.handleAsyncUpdate(node, result, options, this.currentView);
|
|
138
134
|
});
|
|
139
135
|
|
|
140
136
|
return node;
|
|
141
137
|
}
|
|
142
|
-
|
|
143
138
|
return newNode;
|
|
144
139
|
});
|
|
145
140
|
}
|
|
146
141
|
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
142
|
+
private isAsync(node: Node.Node | null): node is Node.Async {
|
|
143
|
+
return node?.type === NodeType.Async;
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
private isDeterminedAsync(obj: any) {
|
|
147
|
+
return obj && Object.prototype.hasOwnProperty.call(obj, "async");
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
applyParser(parser: Parser) {
|
|
151
|
+
parser.hooks.parseNode.tap(
|
|
152
|
+
this.name,
|
|
153
|
+
(
|
|
154
|
+
obj: any,
|
|
155
|
+
nodeType: Node.ChildrenTypes,
|
|
156
|
+
options: ParseObjectOptions,
|
|
157
|
+
childOptions?: ParseObjectChildOptions,
|
|
158
|
+
) => {
|
|
159
|
+
if (this.isDeterminedAsync(obj)) {
|
|
160
|
+
const parsedAsync = parser.parseObject(
|
|
161
|
+
omit(obj, "async"),
|
|
162
|
+
nodeType,
|
|
163
|
+
options,
|
|
164
|
+
);
|
|
165
|
+
const parsedNodeId = getNodeID(parsedAsync);
|
|
166
|
+
|
|
167
|
+
if (parsedAsync === null || !parsedNodeId) {
|
|
168
|
+
return childOptions ? [] : null;
|
|
156
169
|
}
|
|
157
|
-
} else {
|
|
158
|
-
resolvedNode = null;
|
|
159
|
-
}
|
|
160
170
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
171
|
+
const asyncAST = parser.createASTNode(
|
|
172
|
+
{
|
|
173
|
+
id: parsedNodeId,
|
|
174
|
+
type: NodeType.Async,
|
|
175
|
+
value: parsedAsync,
|
|
176
|
+
},
|
|
177
|
+
obj,
|
|
178
|
+
);
|
|
169
179
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
180
|
+
if (childOptions) {
|
|
181
|
+
return asyncAST
|
|
182
|
+
? [
|
|
183
|
+
{
|
|
184
|
+
path: [...childOptions.path, childOptions.key],
|
|
185
|
+
value: asyncAST,
|
|
186
|
+
},
|
|
187
|
+
]
|
|
188
|
+
: [];
|
|
189
|
+
}
|
|
173
190
|
|
|
174
|
-
return
|
|
191
|
+
return asyncAST;
|
|
175
192
|
}
|
|
193
|
+
},
|
|
194
|
+
);
|
|
195
|
+
}
|
|
176
196
|
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
197
|
+
apply(view: ViewInstance): void {
|
|
198
|
+
this.currentView = view;
|
|
199
|
+
view.hooks.parser.tap("async", this.applyParser.bind(this));
|
|
200
|
+
view.hooks.resolver.tap("async", this.applyResolver.bind(this));
|
|
180
201
|
}
|
|
181
202
|
|
|
182
203
|
applyPlugin(asyncNodePlugin: AsyncNodePlugin): void {
|
package/types/index.d.ts
CHANGED
|
@@ -8,7 +8,7 @@ export interface AsyncNodePluginOptions {
|
|
|
8
8
|
export interface AsyncNodeViewPlugin extends ViewPlugin {
|
|
9
9
|
/** Use this to tap into the async node plugin hooks */
|
|
10
10
|
applyPlugin: (asyncNodePlugin: AsyncNodePlugin) => void;
|
|
11
|
-
asyncNode: AsyncParallelBailHook<[Node.Async], any>;
|
|
11
|
+
asyncNode: AsyncParallelBailHook<[Node.Async, (result: any) => void], any>;
|
|
12
12
|
}
|
|
13
13
|
/**
|
|
14
14
|
* Async node plugin used to resolve async nodes in the content
|
|
@@ -18,20 +18,38 @@ export declare class AsyncNodePlugin implements PlayerPlugin {
|
|
|
18
18
|
private plugins;
|
|
19
19
|
constructor(options: AsyncNodePluginOptions);
|
|
20
20
|
readonly hooks: {
|
|
21
|
-
onAsyncNode: AsyncParallelBailHook<[Node.Async], any, Record<string, any>>;
|
|
21
|
+
onAsyncNode: AsyncParallelBailHook<[Node.Async, (result: any) => void], any, Record<string, any>>;
|
|
22
22
|
};
|
|
23
23
|
name: string;
|
|
24
24
|
apply(player: Player): void;
|
|
25
25
|
}
|
|
26
26
|
export declare class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
|
|
27
|
-
asyncNode: AsyncParallelBailHook<[Node.Async], any, Record<string, any>>;
|
|
27
|
+
asyncNode: AsyncParallelBailHook<[Node.Async, (result: any) => void], any, Record<string, any>>;
|
|
28
28
|
private basePlugin;
|
|
29
29
|
name: string;
|
|
30
30
|
private resolvedMapping;
|
|
31
31
|
private currentView;
|
|
32
|
+
/**
|
|
33
|
+
* Updates the node asynchronously based on the result provided.
|
|
34
|
+
* This method is responsible for handling the update logic of asynchronous nodes.
|
|
35
|
+
* It checks if the node needs to be updated based on the new result and updates the mapping accordingly.
|
|
36
|
+
* If an update is necessary, it triggers an asynchronous update on the view.
|
|
37
|
+
* @param node The asynchronous node that might be updated.
|
|
38
|
+
* @param result The result obtained from resolving the async node. This could be any data structure or value.
|
|
39
|
+
* @param options Options provided for node resolution, including a potential parseNode function to process the result.
|
|
40
|
+
* @param view The view instance where the node resides. This can be undefined if the view is not currently active.
|
|
41
|
+
*/
|
|
42
|
+
private handleAsyncUpdate;
|
|
43
|
+
/**
|
|
44
|
+
* Handles the asynchronous API integration for resolving nodes.
|
|
45
|
+
* This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
|
|
46
|
+
* @param resolver The resolver instance to attach the hook to.
|
|
47
|
+
* @param view
|
|
48
|
+
*/
|
|
49
|
+
applyResolver(resolver: Resolver): void;
|
|
32
50
|
private isAsync;
|
|
51
|
+
private isDeterminedAsync;
|
|
33
52
|
applyParser(parser: Parser): void;
|
|
34
|
-
applyResolverHooks(resolver: Resolver): void;
|
|
35
53
|
apply(view: ViewInstance): void;
|
|
36
54
|
applyPlugin(asyncNodePlugin: AsyncNodePlugin): void;
|
|
37
55
|
}
|