@player-ui/async-node-plugin 0.15.4--canary.881.37421 → 0.15.4--canary.884.37483

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/types/index.d.ts CHANGED
@@ -1,9 +1,25 @@
1
- import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver } from "@player-ui/player";
1
+ import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver, ViewController } from "@player-ui/player";
2
2
  import { AsyncSeriesBailHook, SyncBailHook } from "tapable-ts";
3
- import { AsyncPluginContext } from "./internal-types";
4
3
  export * from "./types";
5
4
  export * from "./transform";
6
5
  export * from "./createAsyncTransform";
6
+ /** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
7
+ * This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
8
+ */
9
+ type AsyncPluginContext = {
10
+ /** Map of async node id to resolved content */
11
+ nodeResolveCache: Map<string, Node.Node>;
12
+ /** The view instance this context is attached to. */
13
+ view: ViewInstance;
14
+ /** The view controller this context is attached to. */
15
+ viewController: ViewController;
16
+ /** Map of async node id to promises being used to resolve them */
17
+ inProgressNodes: Set<string>;
18
+ /** Map of async node ids to the original node they represent.
19
+ * In some cases, async nodes are transformed into from other node types so the original reference is needed in order to trigger an update on the view when the async node changes.
20
+ */
21
+ originalNodeCache: Map<string, Set<Node.Node>>;
22
+ };
7
23
  export interface AsyncNodePluginOptions {
8
24
  /** A set of plugins to load */
9
25
  plugins?: AsyncNodeViewPlugin[];
@@ -64,7 +80,6 @@ export declare class AsyncNodePluginPlugin implements AsyncNodeViewPlugin {
64
80
  */
65
81
  private handleAsyncUpdate;
66
82
  private hasValidMapping;
67
- private getOrCreateAsyncNodeCacheEntry;
68
83
  /**
69
84
  * Handles the asynchronous API integration for resolving nodes.
70
85
  * This method sets up a hook on the resolver's `beforeResolve` event to process async nodes.
@@ -2,6 +2,4 @@ export * from "./extractNodeFromPath";
2
2
  export * from "./traverseAndReplace";
3
3
  export * from "./unwrapAsset";
4
4
  export * from "./requiresAssetWrapper";
5
- export * from "./isAsyncPlayerError";
6
- export * from "./getNodeFromError";
7
5
  //# sourceMappingURL=index.d.ts.map
@@ -1,30 +0,0 @@
1
- import {
2
- ErrorSeverity,
3
- type Node,
4
- type PlayerErrorMetadata,
5
- } from "@player-ui/player";
6
-
7
- export const ASYNC_ERROR_TYPE = "ASYNC-PLUGIN";
8
- export type AsyncErrorMetadata = {
9
- node: Node.Async;
10
- };
11
- export class AsyncNodeError
12
- extends Error
13
- implements PlayerErrorMetadata<AsyncErrorMetadata>
14
- {
15
- readonly type: string = ASYNC_ERROR_TYPE;
16
- readonly severity: ErrorSeverity = ErrorSeverity.ERROR;
17
- readonly metadata: AsyncErrorMetadata;
18
-
19
- constructor(
20
- node: Node.Async,
21
- message?: string,
22
- public readonly cause?: Error | undefined,
23
- ) {
24
- super(message);
25
-
26
- this.metadata = {
27
- node,
28
- };
29
- }
30
- }
@@ -1,30 +0,0 @@
1
- import type { Node, ViewController, ViewInstance } from "@player-ui/player";
2
-
3
- export type AsyncNodeInfo = {
4
- /** The async node */
5
- asyncNode: Node.Async;
6
- /** All nodes that need to be updated when the async content changes. This could be the async node itself, or a node that created it (i.e. an asset node that transformed into an async node). */
7
- updateNodes: Set<Node.Node>;
8
- /** The resolved content for this async node */
9
- resolvedContent?: Node.Node;
10
- };
11
-
12
- /** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
13
- * This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
14
- */
15
- export type AsyncPluginContext = {
16
- /** The view instance this context is attached to. */
17
- view: ViewInstance;
18
- /** The view controller this context is attached to. */
19
- viewController: ViewController;
20
- /** Set of async node ids that are currently being managed by an incomplete promise. */
21
- inProgressNodes: Set<string>;
22
- /** Map of async node ids to related info for that node. */
23
- asyncNodeCache: Map<string, AsyncNodeInfo>;
24
- /** Maps asset ids to its original node. Used to then search for what if could be generated by. */
25
- assetIdCache: Map<string, Node.Node>;
26
- /** Maps nodes to the async id that generated them. */
27
- generatedByMap: Map<Node.Node, string>;
28
- /** Map to track the original parent of nodes that were flattened into another. This is needed to track which async nodes actually generated these nodes. */
29
- originalParentMap: Map<Node.Node, Node.Node>;
30
- };
@@ -1,219 +0,0 @@
1
- import { describe, expect, it, vi, beforeEach } from "vitest";
2
- import { getNodeFromError } from "../getNodeFromError";
3
- import { isAsyncPlayerError } from "../isAsyncPlayerError";
4
- import {
5
- ErrorMetadata,
6
- ErrorSeverity,
7
- ErrorTypes,
8
- NodeType,
9
- PlayerError,
10
- PlayerErrorMetadata,
11
- } from "@player-ui/player";
12
- import { AsyncNodeInfo, AsyncPluginContext } from "../../internal-types";
13
- import { ASYNC_ERROR_TYPE, AsyncNodeError } from "../../AsyncNodeError";
14
-
15
- vi.mock("../isAsyncPlayerError");
16
-
17
- /** Test class to create an error with any additional properties */
18
- class ErrorWithProps extends Error implements PlayerErrorMetadata {
19
- constructor(
20
- message: string,
21
- public type: string,
22
- public severity?: ErrorSeverity,
23
- public metadata?: ErrorMetadata,
24
- ) {
25
- super(message);
26
- }
27
- }
28
-
29
- const createPlayerError = (
30
- errorType: string,
31
- metadata?: ErrorMetadata,
32
- ): PlayerError =>
33
- new ErrorWithProps("Error", errorType, ErrorSeverity.ERROR, metadata);
34
-
35
- const createContext = (
36
- baseContext?: Partial<AsyncPluginContext>,
37
- ): AsyncPluginContext => ({
38
- assetIdCache: new Map(),
39
- asyncNodeCache: new Map(),
40
- generatedByMap: new Map(),
41
- inProgressNodes: new Set(),
42
- originalParentMap: new Map(),
43
- view: {} as any,
44
- viewController: {} as any,
45
- ...baseContext,
46
- });
47
-
48
- describe("getNodeFromError", () => {
49
- beforeEach(() => {
50
- vi.mocked(isAsyncPlayerError).mockReturnValue(false);
51
- });
52
- describe("render errors", () => {
53
- it("should be undefined when no string assetId is in the error metadata", () => {
54
- const result = getNodeFromError(
55
- createPlayerError(ErrorTypes.RENDER, {}),
56
- createContext(),
57
- );
58
-
59
- expect(result).toBeUndefined();
60
- });
61
-
62
- it("should be undefined the assetId is not in the context cache", () => {
63
- const result = getNodeFromError(
64
- createPlayerError(ErrorTypes.RENDER, { assetId: "test-id" }),
65
- createContext(),
66
- );
67
-
68
- expect(result).toBeUndefined();
69
- });
70
-
71
- it("should be the node from the assetIdCache if the assetId is available", () => {
72
- const context = createContext();
73
- context.assetIdCache.set("test-id", {
74
- type: NodeType.Value,
75
- value: {
76
- prop: "value",
77
- },
78
- });
79
- const result = getNodeFromError(
80
- createPlayerError(ErrorTypes.RENDER, { assetId: "test-id" }),
81
- context,
82
- );
83
-
84
- expect(result).toStrictEqual({
85
- type: NodeType.Value,
86
- value: {
87
- prop: "value",
88
- },
89
- });
90
- });
91
- });
92
-
93
- describe("view errors", () => {
94
- const notRealNodes = [undefined, null, [], "node"];
95
- it.each(notRealNodes)(
96
- "should return undefined for any view error without a node",
97
- (node) => {
98
- const result = getNodeFromError(
99
- createPlayerError(ErrorTypes.VIEW, { node }),
100
- createContext(),
101
- );
102
-
103
- expect(result).toBeUndefined();
104
- },
105
- );
106
-
107
- it("should return the node property if it is a node", () => {
108
- const result = getNodeFromError(
109
- createPlayerError(ErrorTypes.VIEW, {
110
- node: {
111
- type: NodeType.Value,
112
- value: {
113
- prop: "value",
114
- },
115
- },
116
- }),
117
- createContext(),
118
- );
119
-
120
- expect(result).toStrictEqual({
121
- type: NodeType.Value,
122
- value: {
123
- prop: "value",
124
- },
125
- });
126
- });
127
- });
128
-
129
- describe("async errors", () => {
130
- it("should return undefined if the error is not recognized as an async error", () => {
131
- const result = getNodeFromError(
132
- {
133
- error: new ErrorWithProps(
134
- "Error",
135
- ASYNC_ERROR_TYPE,
136
- ErrorSeverity.ERROR,
137
- {
138
- node: {
139
- type: NodeType.Value,
140
- value: {
141
- prop: "value",
142
- },
143
- },
144
- },
145
- ),
146
- errorType: ASYNC_ERROR_TYPE,
147
- skipped: false,
148
- },
149
- createContext(),
150
- );
151
-
152
- expect(result).toBeUndefined();
153
- });
154
-
155
- it("should return undefined if the node from the error is undefined", () => {
156
- vi.mocked(isAsyncPlayerError).mockReturnValue(true);
157
- const result = getNodeFromError(
158
- createPlayerError(ASYNC_ERROR_TYPE, undefined),
159
- createContext(),
160
- );
161
-
162
- expect(result).toBeUndefined();
163
- });
164
-
165
- it("should return the node the asyncNodeCache if an id matches", () => {
166
- vi.mocked(isAsyncPlayerError).mockReturnValue(true);
167
- const cacheEntry: AsyncNodeInfo = {
168
- asyncNode: {
169
- type: NodeType.Async,
170
- id: "test-id",
171
- value: {
172
- type: NodeType.Value,
173
- value: {
174
- prop: "value cached",
175
- },
176
- },
177
- },
178
- updateNodes: new Set(),
179
- };
180
- const result = getNodeFromError(
181
- new AsyncNodeError({
182
- type: NodeType.Async,
183
- id: "test-id",
184
- value: {
185
- type: NodeType.Value,
186
- value: {
187
- prop: "value",
188
- },
189
- },
190
- }),
191
- createContext({
192
- asyncNodeCache: new Map([["test-id", cacheEntry]]),
193
- }),
194
- );
195
-
196
- expect(result).toStrictEqual({
197
- type: NodeType.Async,
198
- id: "test-id",
199
- value: {
200
- type: NodeType.Value,
201
- value: {
202
- prop: "value cached",
203
- },
204
- },
205
- });
206
- });
207
- });
208
-
209
- describe("other errors", () => {
210
- it("should return undefined for all other errors", () => {
211
- const result = getNodeFromError(
212
- createPlayerError("UNKNOWN", {}),
213
- createContext(),
214
- );
215
-
216
- expect(result).toBeUndefined();
217
- });
218
- });
219
- });
@@ -1,33 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { isAsyncPlayerError } from "../isAsyncPlayerError";
3
- import {
4
- ErrorMetadata,
5
- ErrorSeverity,
6
- PlayerErrorMetadata,
7
- } from "@player-ui/player";
8
-
9
- /** Test class to create an error with any additional properties */
10
- class ErrorWithProps extends Error implements PlayerErrorMetadata {
11
- constructor(
12
- message: string,
13
- public type: string,
14
- public severity?: ErrorSeverity,
15
- public metadata?: ErrorMetadata,
16
- ) {
17
- super(message);
18
- }
19
- }
20
-
21
- describe("isAsyncPlayerError", () => {
22
- it("should return true for errors with the type 'ASYNC-PLUGIN'", () => {
23
- expect(isAsyncPlayerError(new ErrorWithProps("test", "ASYNC-PLUGIN"))).toBe(
24
- true,
25
- );
26
- });
27
-
28
- it("should return false for errors without the type 'ASYNC-PLUGIN'", () => {
29
- expect(isAsyncPlayerError(new ErrorWithProps("test", "UNKNOWN"))).toBe(
30
- false,
31
- );
32
- });
33
- });
@@ -1,34 +0,0 @@
1
- import { PlayerError, Node, ErrorTypes } from "@player-ui/player";
2
- import { AsyncPluginContext } from "../internal-types";
3
- import { isAsyncPlayerError } from "./isAsyncPlayerError";
4
-
5
- /** Get the AST Node related to a specific error if available. */
6
- export const getNodeFromError = (
7
- playerError: PlayerError,
8
- context: AsyncPluginContext,
9
- ): Node.Node | undefined => {
10
- if (playerError.type === ErrorTypes.RENDER) {
11
- const { assetId } = playerError.metadata ?? {};
12
-
13
- if (typeof assetId !== "string") {
14
- return undefined;
15
- }
16
-
17
- return context.assetIdCache.get(assetId);
18
- }
19
-
20
- if (playerError.type === ErrorTypes.VIEW) {
21
- const { node } = playerError.metadata ?? {};
22
- // TODO: Remove some of this from here. Maybe export type assertion functions from where the errors are generated?
23
- if (typeof node === "object" && node !== null && !Array.isArray(node)) {
24
- return node as Node.Node;
25
- }
26
- }
27
-
28
- if (isAsyncPlayerError(playerError) && playerError.metadata !== undefined) {
29
- // Use the node from the cache to ensure it is the latest version of the async node from the resolver
30
- return context.asyncNodeCache.get(playerError.metadata.node.id)?.asyncNode;
31
- }
32
-
33
- return undefined;
34
- };
@@ -1,8 +0,0 @@
1
- import { PlayerError } from "@player-ui/player";
2
- import { ASYNC_ERROR_TYPE, AsyncErrorMetadata } from "../AsyncNodeError";
3
-
4
- export const isAsyncPlayerError = (
5
- error: PlayerError,
6
- ): error is PlayerError<AsyncErrorMetadata> => {
7
- return error.type === ASYNC_ERROR_TYPE;
8
- };
@@ -1,13 +0,0 @@
1
- import { ErrorSeverity, type Node, type PlayerErrorMetadata } from "@player-ui/player";
2
- export declare const ASYNC_ERROR_TYPE = "ASYNC-PLUGIN";
3
- export type AsyncErrorMetadata = {
4
- node: Node.Async;
5
- };
6
- export declare class AsyncNodeError extends Error implements PlayerErrorMetadata<AsyncErrorMetadata> {
7
- readonly cause?: Error | undefined;
8
- readonly type: string;
9
- readonly severity: ErrorSeverity;
10
- readonly metadata: AsyncErrorMetadata;
11
- constructor(node: Node.Async, message?: string, cause?: Error | undefined);
12
- }
13
- //# sourceMappingURL=AsyncNodeError.d.ts.map
@@ -1,29 +0,0 @@
1
- import type { Node, ViewController, ViewInstance } from "@player-ui/player";
2
- export type AsyncNodeInfo = {
3
- /** The async node */
4
- asyncNode: Node.Async;
5
- /** All nodes that need to be updated when the async content changes. This could be the async node itself, or a node that created it (i.e. an asset node that transformed into an async node). */
6
- updateNodes: Set<Node.Node>;
7
- /** The resolved content for this async node */
8
- resolvedContent?: Node.Node;
9
- };
10
- /** Object type for storing data related to a single `apply` of the `AsyncNodePluginPlugin`
11
- * This object should be setup once per ViewInstance to keep any cached info just for that view to avoid conflicts of shared async node ids across different view states.
12
- */
13
- export type AsyncPluginContext = {
14
- /** The view instance this context is attached to. */
15
- view: ViewInstance;
16
- /** The view controller this context is attached to. */
17
- viewController: ViewController;
18
- /** Set of async node ids that are currently being managed by an incomplete promise. */
19
- inProgressNodes: Set<string>;
20
- /** Map of async node ids to related info for that node. */
21
- asyncNodeCache: Map<string, AsyncNodeInfo>;
22
- /** Maps asset ids to its original node. Used to then search for what if could be generated by. */
23
- assetIdCache: Map<string, Node.Node>;
24
- /** Maps nodes to the async id that generated them. */
25
- generatedByMap: Map<Node.Node, string>;
26
- /** Map to track the original parent of nodes that were flattened into another. This is needed to track which async nodes actually generated these nodes. */
27
- originalParentMap: Map<Node.Node, Node.Node>;
28
- };
29
- //# sourceMappingURL=internal-types.d.ts.map
@@ -1,5 +0,0 @@
1
- import { PlayerError, Node } from "@player-ui/player";
2
- import { AsyncPluginContext } from "../internal-types";
3
- /** Get the AST Node related to a specific error if available. */
4
- export declare const getNodeFromError: (playerError: PlayerError, context: AsyncPluginContext) => Node.Node | undefined;
5
- //# sourceMappingURL=getNodeFromError.d.ts.map
@@ -1,4 +0,0 @@
1
- import { PlayerError } from "@player-ui/player";
2
- import { AsyncErrorMetadata } from "../AsyncNodeError";
3
- export declare const isAsyncPlayerError: (error: PlayerError) => error is PlayerError<AsyncErrorMetadata>;
4
- //# sourceMappingURL=isAsyncPlayerError.d.ts.map