@player-ui/async-node-plugin 0.10.4-next.2 → 0.10.4
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 +159 -13
- package/dist/AsyncNodePlugin.native.js.map +1 -1
- package/dist/cjs/index.cjs +32 -7
- package/dist/cjs/index.cjs.map +1 -1
- package/dist/index.legacy-esm.js +29 -5
- package/dist/index.mjs +29 -5
- package/dist/index.mjs.map +1 -1
- package/package.json +5 -2
- package/src/__tests__/__snapshots__/transform.test.ts.snap +58 -0
- package/src/__tests__/index.test.ts +329 -0
- package/src/__tests__/transform.test.ts +25 -0
- package/src/index.ts +1 -0
- package/src/transform.ts +40 -0
- package/src/types.ts +7 -0
- package/types/index.d.ts +1 -0
- package/types/transform.d.ts +11 -0
- package/types/types.d.ts +1 -0
|
@@ -3,6 +3,7 @@ import { Node, InProgressState, ViewInstance } from "@player-ui/player";
|
|
|
3
3
|
import { Player, Parser } from "@player-ui/player";
|
|
4
4
|
import { waitFor } from "@testing-library/react";
|
|
5
5
|
import { AsyncNodePlugin, AsyncNodePluginPlugin } from "../index";
|
|
6
|
+
import { ReferenceAssetsPlugin } from "@player-ui/reference-assets-plugin";
|
|
6
7
|
|
|
7
8
|
describe("view", () => {
|
|
8
9
|
const basicFRFWithActions = {
|
|
@@ -38,6 +39,40 @@ describe("view", () => {
|
|
|
38
39
|
},
|
|
39
40
|
};
|
|
40
41
|
|
|
42
|
+
const chatMessageContent = {
|
|
43
|
+
id: "chat",
|
|
44
|
+
views: [
|
|
45
|
+
{
|
|
46
|
+
id: "1",
|
|
47
|
+
type: "chat-message",
|
|
48
|
+
value: {
|
|
49
|
+
asset: {
|
|
50
|
+
id: "2",
|
|
51
|
+
type: "text",
|
|
52
|
+
value: "chat message",
|
|
53
|
+
},
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
],
|
|
57
|
+
navigation: {
|
|
58
|
+
BEGIN: "FLOW_1",
|
|
59
|
+
FLOW_1: {
|
|
60
|
+
startState: "VIEW_1",
|
|
61
|
+
VIEW_1: {
|
|
62
|
+
state_type: "VIEW",
|
|
63
|
+
ref: "1",
|
|
64
|
+
transitions: {
|
|
65
|
+
"*": "END_Done",
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
END_Done: {
|
|
69
|
+
state_type: "END",
|
|
70
|
+
outcome: "DONE",
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
},
|
|
74
|
+
};
|
|
75
|
+
|
|
41
76
|
const asyncNodeTest = async (resolvedValue: any) => {
|
|
42
77
|
const plugin = new AsyncNodePlugin({
|
|
43
78
|
plugins: [new AsyncNodePluginPlugin()],
|
|
@@ -548,6 +583,300 @@ describe("view", () => {
|
|
|
548
583
|
expect(localNode.type).toStrictEqual("async");
|
|
549
584
|
});
|
|
550
585
|
});
|
|
586
|
+
|
|
587
|
+
test("chat-message asset - replaces async nodes with multi node flattened", async () => {
|
|
588
|
+
const plugin = new AsyncNodePlugin({
|
|
589
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
590
|
+
});
|
|
591
|
+
|
|
592
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
593
|
+
|
|
594
|
+
plugin.hooks.onAsyncNode.tap("test", async (node) => {
|
|
595
|
+
return new Promise((resolve) => {
|
|
596
|
+
deferredResolve = resolve;
|
|
597
|
+
});
|
|
598
|
+
});
|
|
599
|
+
|
|
600
|
+
let updateNumber = 0;
|
|
601
|
+
|
|
602
|
+
const plugins = [plugin, new ReferenceAssetsPlugin()];
|
|
603
|
+
|
|
604
|
+
const player = new Player({
|
|
605
|
+
plugins: plugins,
|
|
606
|
+
});
|
|
607
|
+
|
|
608
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
609
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
610
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
611
|
+
updateNumber++;
|
|
612
|
+
});
|
|
613
|
+
});
|
|
614
|
+
});
|
|
615
|
+
|
|
616
|
+
player.start(chatMessageContent as any);
|
|
617
|
+
|
|
618
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
619
|
+
.currentView?.lastUpdate;
|
|
620
|
+
|
|
621
|
+
expect(view).toBeDefined();
|
|
622
|
+
expect(view?.values[0].asset.type).toBe("text");
|
|
623
|
+
expect(updateNumber).toBe(1);
|
|
624
|
+
|
|
625
|
+
await waitFor(() => {
|
|
626
|
+
expect(deferredResolve).toBeDefined();
|
|
627
|
+
});
|
|
628
|
+
|
|
629
|
+
if (deferredResolve) {
|
|
630
|
+
deferredResolve([
|
|
631
|
+
{
|
|
632
|
+
asset: {
|
|
633
|
+
id: "2",
|
|
634
|
+
type: "text",
|
|
635
|
+
value: "Hello World!",
|
|
636
|
+
},
|
|
637
|
+
},
|
|
638
|
+
{
|
|
639
|
+
asset: {
|
|
640
|
+
id: "3",
|
|
641
|
+
type: "text",
|
|
642
|
+
value: "Hello World!",
|
|
643
|
+
},
|
|
644
|
+
},
|
|
645
|
+
]);
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
await waitFor(() => {
|
|
649
|
+
expect(updateNumber).toBe(2);
|
|
650
|
+
});
|
|
651
|
+
|
|
652
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
653
|
+
?.lastUpdate;
|
|
654
|
+
|
|
655
|
+
expect(view?.values[1][0].asset.type).toBe("text");
|
|
656
|
+
expect(view?.values[1][1].asset.type).toBe("text");
|
|
657
|
+
});
|
|
658
|
+
|
|
659
|
+
test("chat-message asset - replaces async nodes with provided node", async () => {
|
|
660
|
+
const plugin = new AsyncNodePlugin({
|
|
661
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
662
|
+
});
|
|
663
|
+
|
|
664
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
665
|
+
|
|
666
|
+
plugin.hooks.onAsyncNode.tap("test", async (node) => {
|
|
667
|
+
return new Promise((resolve) => {
|
|
668
|
+
deferredResolve = resolve;
|
|
669
|
+
});
|
|
670
|
+
});
|
|
671
|
+
|
|
672
|
+
let updateNumber = 0;
|
|
673
|
+
|
|
674
|
+
const plugins = [plugin, new ReferenceAssetsPlugin()];
|
|
675
|
+
|
|
676
|
+
const player = new Player({
|
|
677
|
+
plugins: plugins,
|
|
678
|
+
});
|
|
679
|
+
|
|
680
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
681
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
682
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
683
|
+
updateNumber++;
|
|
684
|
+
});
|
|
685
|
+
});
|
|
686
|
+
});
|
|
687
|
+
|
|
688
|
+
player.start(chatMessageContent as any);
|
|
689
|
+
|
|
690
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
691
|
+
.currentView?.lastUpdate;
|
|
692
|
+
|
|
693
|
+
expect(view).toBeDefined();
|
|
694
|
+
expect(view?.values[0].asset.type).toBe("text");
|
|
695
|
+
expect(view?.values[0].asset.value).toBe("chat message");
|
|
696
|
+
expect(updateNumber).toBe(1);
|
|
697
|
+
|
|
698
|
+
await waitFor(() => {
|
|
699
|
+
expect(deferredResolve).toBeDefined();
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
if (deferredResolve) {
|
|
703
|
+
deferredResolve({
|
|
704
|
+
asset: {
|
|
705
|
+
id: "2",
|
|
706
|
+
type: "text",
|
|
707
|
+
value: "async content",
|
|
708
|
+
},
|
|
709
|
+
});
|
|
710
|
+
}
|
|
711
|
+
|
|
712
|
+
await waitFor(() => {
|
|
713
|
+
expect(updateNumber).toBe(2);
|
|
714
|
+
});
|
|
715
|
+
|
|
716
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
717
|
+
?.lastUpdate;
|
|
718
|
+
|
|
719
|
+
expect(view?.values[1].asset.type).toBe("text");
|
|
720
|
+
expect(view?.values[1].asset.value).toBe("async content");
|
|
721
|
+
});
|
|
722
|
+
|
|
723
|
+
test("chat-message asset - replaces async nodes with chat-message asset", async () => {
|
|
724
|
+
const plugin = new AsyncNodePlugin({
|
|
725
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
726
|
+
});
|
|
727
|
+
|
|
728
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
729
|
+
|
|
730
|
+
plugin.hooks.onAsyncNode.tap("test", async (node) => {
|
|
731
|
+
return new Promise((resolve) => {
|
|
732
|
+
deferredResolve = resolve;
|
|
733
|
+
});
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
let updateNumber = 0;
|
|
737
|
+
|
|
738
|
+
const player = new Player({
|
|
739
|
+
plugins: [plugin, new ReferenceAssetsPlugin()],
|
|
740
|
+
});
|
|
741
|
+
|
|
742
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
743
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
744
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
745
|
+
updateNumber++;
|
|
746
|
+
});
|
|
747
|
+
});
|
|
748
|
+
});
|
|
749
|
+
|
|
750
|
+
player.start(chatMessageContent as any);
|
|
751
|
+
|
|
752
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
753
|
+
.currentView?.lastUpdate;
|
|
754
|
+
|
|
755
|
+
expect(view).toBeDefined();
|
|
756
|
+
expect(view?.values[0].asset.type).toBe("text");
|
|
757
|
+
expect(view?.values[0].asset.value).toBe("chat message");
|
|
758
|
+
expect(updateNumber).toBe(1);
|
|
759
|
+
|
|
760
|
+
await waitFor(() => {
|
|
761
|
+
expect(deferredResolve).toBeDefined();
|
|
762
|
+
});
|
|
763
|
+
|
|
764
|
+
if (deferredResolve) {
|
|
765
|
+
deferredResolve({
|
|
766
|
+
asset: {
|
|
767
|
+
id: "3",
|
|
768
|
+
type: "chat-message",
|
|
769
|
+
value: {
|
|
770
|
+
asset: {
|
|
771
|
+
id: "4",
|
|
772
|
+
type: "text",
|
|
773
|
+
value: "async content",
|
|
774
|
+
},
|
|
775
|
+
},
|
|
776
|
+
},
|
|
777
|
+
});
|
|
778
|
+
}
|
|
779
|
+
|
|
780
|
+
await waitFor(() => {
|
|
781
|
+
expect(updateNumber).toBe(2);
|
|
782
|
+
});
|
|
783
|
+
|
|
784
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
785
|
+
?.lastUpdate;
|
|
786
|
+
|
|
787
|
+
expect(view?.values[1].asset.type).toBe("text");
|
|
788
|
+
expect(view?.values[1].asset.value).toBe("async content");
|
|
789
|
+
});
|
|
790
|
+
|
|
791
|
+
test("chat-message asset - resolve chained chat-message", async () => {
|
|
792
|
+
const plugin = new AsyncNodePlugin({
|
|
793
|
+
plugins: [new AsyncNodePluginPlugin()],
|
|
794
|
+
});
|
|
795
|
+
|
|
796
|
+
let deferredResolve: ((value: any) => void) | undefined;
|
|
797
|
+
|
|
798
|
+
plugin.hooks.onAsyncNode.tap("test", async (node) => {
|
|
799
|
+
return new Promise((resolve) => {
|
|
800
|
+
deferredResolve = resolve;
|
|
801
|
+
});
|
|
802
|
+
});
|
|
803
|
+
|
|
804
|
+
let updateNumber = 0;
|
|
805
|
+
|
|
806
|
+
const plugins = [plugin, new ReferenceAssetsPlugin()];
|
|
807
|
+
|
|
808
|
+
const player = new Player({
|
|
809
|
+
plugins: plugins,
|
|
810
|
+
});
|
|
811
|
+
|
|
812
|
+
player.hooks.viewController.tap("async-node-test", (vc) => {
|
|
813
|
+
vc.hooks.view.tap("async-node-test", (view) => {
|
|
814
|
+
view.hooks.onUpdate.tap("async-node-test", (update) => {
|
|
815
|
+
updateNumber++;
|
|
816
|
+
});
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
|
|
820
|
+
player.start(chatMessageContent as any);
|
|
821
|
+
|
|
822
|
+
let view = (player.getState() as InProgressState).controllers.view
|
|
823
|
+
.currentView?.lastUpdate;
|
|
824
|
+
|
|
825
|
+
expect(view).toBeDefined();
|
|
826
|
+
expect(view?.values[0].asset.type).toBe("text");
|
|
827
|
+
expect(view?.values[0].asset.value).toBe("chat message");
|
|
828
|
+
expect(updateNumber).toBe(1);
|
|
829
|
+
|
|
830
|
+
await waitFor(() => {
|
|
831
|
+
expect(deferredResolve).toBeDefined();
|
|
832
|
+
});
|
|
833
|
+
|
|
834
|
+
if (deferredResolve) {
|
|
835
|
+
deferredResolve({
|
|
836
|
+
asset: {
|
|
837
|
+
id: "3",
|
|
838
|
+
type: "chat-message",
|
|
839
|
+
value: {
|
|
840
|
+
asset: {
|
|
841
|
+
id: "4",
|
|
842
|
+
type: "text",
|
|
843
|
+
value: "async content",
|
|
844
|
+
},
|
|
845
|
+
},
|
|
846
|
+
},
|
|
847
|
+
});
|
|
848
|
+
}
|
|
849
|
+
|
|
850
|
+
await waitFor(() => {
|
|
851
|
+
expect(updateNumber).toBe(2);
|
|
852
|
+
});
|
|
853
|
+
|
|
854
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
855
|
+
?.lastUpdate;
|
|
856
|
+
|
|
857
|
+
expect(view?.values[1].asset.type).toBe("text");
|
|
858
|
+
expect(view?.values[1].asset.value).toBe("async content");
|
|
859
|
+
|
|
860
|
+
if (deferredResolve) {
|
|
861
|
+
deferredResolve({
|
|
862
|
+
asset: {
|
|
863
|
+
id: "5",
|
|
864
|
+
type: "text",
|
|
865
|
+
value: "chained async content",
|
|
866
|
+
},
|
|
867
|
+
});
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
await waitFor(() => {
|
|
871
|
+
expect(updateNumber).toBe(3);
|
|
872
|
+
});
|
|
873
|
+
|
|
874
|
+
view = (player.getState() as InProgressState).controllers.view.currentView
|
|
875
|
+
?.lastUpdate;
|
|
876
|
+
|
|
877
|
+
expect(view?.values[2].asset.type).toBe("text");
|
|
878
|
+
expect(view?.values[2].asset.value).toBe("chained async content");
|
|
879
|
+
});
|
|
551
880
|
});
|
|
552
881
|
|
|
553
882
|
describe("parser", () => {
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { asyncTransform } from "..";
|
|
3
|
+
import { Builder } from "@player-ui/player";
|
|
4
|
+
|
|
5
|
+
describe("asyncTransform", () => {
|
|
6
|
+
const asset = Builder.asset({
|
|
7
|
+
id: "2",
|
|
8
|
+
type: "text",
|
|
9
|
+
value: "chat message",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
it("generates wrapper asset with asset", async () => {
|
|
13
|
+
const transformedAsset = asyncTransform("1", "collection", asset);
|
|
14
|
+
|
|
15
|
+
expect(transformedAsset).toMatchSnapshot();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it("generates wrapper asset with flatten is false", async () => {
|
|
19
|
+
const transformedAsset = asyncTransform("1", "collection", asset, false);
|
|
20
|
+
|
|
21
|
+
expect(transformedAsset?.children?.[0]?.value.values[1].flatten).toBe(
|
|
22
|
+
false,
|
|
23
|
+
);
|
|
24
|
+
});
|
|
25
|
+
});
|
package/src/index.ts
CHANGED
package/src/transform.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import { Builder, NodeType } from "@player-ui/player";
|
|
2
|
+
import type { AsyncTransformFunc } from "./types";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Util function to generate transform function for async asset
|
|
6
|
+
* @param asset - async asset to apply beforeResolve transform
|
|
7
|
+
* @param transformedAssetType: transformed asset type for rendering
|
|
8
|
+
* @param wrapperAssetType: container asset type
|
|
9
|
+
* @param flatten: flatten the streamed in content
|
|
10
|
+
* @returns - wrapper asset with children of transformed asset and async node
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export const asyncTransform: AsyncTransformFunc = (
|
|
14
|
+
assetId,
|
|
15
|
+
wrapperAssetType,
|
|
16
|
+
asset,
|
|
17
|
+
flatten,
|
|
18
|
+
) => {
|
|
19
|
+
const id = "async-" + assetId;
|
|
20
|
+
|
|
21
|
+
const asyncNode = Builder.asyncNode(id, flatten);
|
|
22
|
+
let multiNode;
|
|
23
|
+
let assetNode;
|
|
24
|
+
|
|
25
|
+
if (asset) {
|
|
26
|
+
assetNode = Builder.assetWrapper(asset);
|
|
27
|
+
multiNode = Builder.multiNode(assetNode, asyncNode);
|
|
28
|
+
} else {
|
|
29
|
+
multiNode = Builder.multiNode(asyncNode);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const wrapperAsset = Builder.asset({
|
|
33
|
+
id: wrapperAssetType + "-" + id,
|
|
34
|
+
type: wrapperAssetType,
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
Builder.addChild(wrapperAsset, ["values"], multiNode);
|
|
38
|
+
|
|
39
|
+
return wrapperAsset;
|
|
40
|
+
};
|
package/src/types.ts
CHANGED
package/types/index.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { Player, PlayerPlugin, Node, ViewInstance, Parser, ViewPlugin, Resolver } from "@player-ui/player";
|
|
2
2
|
import { AsyncParallelBailHook } from "tapable-ts";
|
|
3
3
|
export * from "./types";
|
|
4
|
+
export * from "./transform";
|
|
4
5
|
export interface AsyncNodePluginOptions {
|
|
5
6
|
/** A set of plugins to load */
|
|
6
7
|
plugins?: AsyncNodeViewPlugin[];
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { AsyncTransformFunc } from "./types";
|
|
2
|
+
/**
|
|
3
|
+
* Util function to generate transform function for async asset
|
|
4
|
+
* @param asset - async asset to apply beforeResolve transform
|
|
5
|
+
* @param transformedAssetType: transformed asset type for rendering
|
|
6
|
+
* @param wrapperAssetType: container asset type
|
|
7
|
+
* @param flatten: flatten the streamed in content
|
|
8
|
+
* @returns - wrapper asset with children of transformed asset and async node
|
|
9
|
+
*/
|
|
10
|
+
export declare const asyncTransform: AsyncTransformFunc;
|
|
11
|
+
//# sourceMappingURL=transform.d.ts.map
|
package/types/types.d.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
1
|
import type { Node } from "@player-ui/player";
|
|
2
2
|
export type AsyncNodeHandler = (node: Node.Node, update: (object: any) => void) => void;
|
|
3
|
+
export type AsyncTransformFunc = (id: string, wrapperAssetType: string, asset?: Node.Node, flatten?: boolean) => Node.Asset;
|
|
3
4
|
//# sourceMappingURL=types.d.ts.map
|