@player-ui/markdown-plugin 0.8.0--canary.307.9621 → 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.
@@ -0,0 +1,464 @@
1
+ import { describe, it, expect } from "vitest";
2
+ import type { InProgressState, Flow } from "@player-ui/player";
3
+ import { Player } from "@player-ui/player";
4
+ import { Registry } from "@player-ui/partial-match-registry";
5
+ import { PartialMatchFingerprintPlugin } from "@player-ui/partial-match-fingerprint-plugin";
6
+ import { mockMappers } from "./helpers";
7
+ import { MarkdownPlugin } from "..";
8
+
9
+ describe("MarkdownPlugin", () => {
10
+ describe("Transform Operation", () => {
11
+ const unparsedFlow: Flow = {
12
+ id: "markdown-flow",
13
+ data: {
14
+ internal: {
15
+ locale: {
16
+ linkMarkdown:
17
+ "Learn more at [TurboTax Canada](https://turbotax.intuit.ca)",
18
+ },
19
+ },
20
+ },
21
+ views: [
22
+ {
23
+ id: "markdown-view",
24
+ type: "questionAnswer",
25
+ title: {
26
+ asset: {
27
+ id: "markdown-view-title",
28
+ type: "markdown",
29
+ value: "{{internal.locale.linkMarkdown}}",
30
+ },
31
+ },
32
+ primaryInfo: {
33
+ asset: {
34
+ id: "markdown-primaryInfo-collection",
35
+ type: "collection",
36
+ values: [
37
+ {
38
+ asset: {
39
+ id: "markdown-primaryInfo-collection-bold",
40
+ type: "markdown",
41
+ value: "some **bold text**",
42
+ },
43
+ },
44
+ {
45
+ asset: {
46
+ id: "markdown-primaryInfo-collection-italic",
47
+ type: "markdown",
48
+ value: "*italicized text*",
49
+ },
50
+ },
51
+ {
52
+ asset: {
53
+ id: "markdown-primaryInfo-collection-orderd-list",
54
+ type: "markdown",
55
+ value: "1. First\n2. Second\n3. Third",
56
+ },
57
+ },
58
+ {
59
+ asset: {
60
+ id: "markdown-primaryInfo-collection-unorderd-list",
61
+ type: "markdown",
62
+ value:
63
+ "- [First](https://turbotax.intuit.ca)\n- Second\n- Third",
64
+ },
65
+ },
66
+ {
67
+ asset: {
68
+ id: "markdown-primaryInfo-collection-image",
69
+ type: "markdown",
70
+ value: "![alt text](image.png)",
71
+ },
72
+ },
73
+ {
74
+ asset: {
75
+ id: "markdown-primaryInfo-collection-unsupported",
76
+ type: "markdown",
77
+ value: "Highlights are ==not supported==",
78
+ },
79
+ },
80
+ ],
81
+ },
82
+ },
83
+ },
84
+ ],
85
+ navigation: {
86
+ BEGIN: "FLOW_1",
87
+ FLOW_1: {
88
+ startState: "VIEW_1",
89
+ VIEW_1: {
90
+ state_type: "VIEW",
91
+ ref: "markdown-view",
92
+ transitions: {
93
+ "*": "END_Done",
94
+ },
95
+ },
96
+ END_Done: {
97
+ state_type: "END",
98
+ outcome: "done",
99
+ },
100
+ },
101
+ },
102
+ };
103
+
104
+ it("parses the flow containing markdown into valid FRF, based on the given mappers", () => {
105
+ const player = new Player({
106
+ plugins: [new MarkdownPlugin(mockMappers)],
107
+ });
108
+ player.start(unparsedFlow);
109
+
110
+ const view = (player.getState() as InProgressState).controllers.view
111
+ .currentView?.lastUpdate;
112
+
113
+ expect(view).toMatchInlineSnapshot(`
114
+ {
115
+ "id": "markdown-view",
116
+ "primaryInfo": {
117
+ "asset": {
118
+ "id": "markdown-primaryInfo-collection",
119
+ "type": "collection",
120
+ "values": [
121
+ {
122
+ "asset": {
123
+ "id": "markdown-primaryInfo-collection-bold-composite-7",
124
+ "type": "composite",
125
+ "values": [
126
+ {
127
+ "asset": {
128
+ "id": "markdown-primaryInfo-collection-bold-text-4",
129
+ "type": "text",
130
+ "value": "some ",
131
+ },
132
+ },
133
+ {
134
+ "asset": {
135
+ "id": "markdown-primaryInfo-collection-bold-text-5",
136
+ "modifiers": [
137
+ {
138
+ "type": "tag",
139
+ "value": "important",
140
+ },
141
+ ],
142
+ "type": "text",
143
+ "value": "bold text",
144
+ },
145
+ },
146
+ ],
147
+ },
148
+ },
149
+ {
150
+ "asset": {
151
+ "id": "markdown-primaryInfo-collection-italic-text-8",
152
+ "modifiers": [
153
+ {
154
+ "type": "tag",
155
+ "value": "emphasis",
156
+ },
157
+ ],
158
+ "type": "text",
159
+ "value": "italicized text",
160
+ },
161
+ },
162
+ {
163
+ "asset": {
164
+ "id": "markdown-primaryInfo-collection-orderd-list-list-20",
165
+ "metaData": {
166
+ "listType": "ordered",
167
+ },
168
+ "type": "list",
169
+ "values": [
170
+ {
171
+ "asset": {
172
+ "id": "markdown-primaryInfo-collection-orderd-list-text-11",
173
+ "type": "text",
174
+ "value": "First",
175
+ },
176
+ },
177
+ {
178
+ "asset": {
179
+ "id": "markdown-primaryInfo-collection-orderd-list-text-14",
180
+ "type": "text",
181
+ "value": "Second",
182
+ },
183
+ },
184
+ {
185
+ "asset": {
186
+ "id": "markdown-primaryInfo-collection-orderd-list-text-17",
187
+ "type": "text",
188
+ "value": "Third",
189
+ },
190
+ },
191
+ ],
192
+ },
193
+ },
194
+ {
195
+ "asset": {
196
+ "id": "markdown-primaryInfo-collection-unorderd-list-list-31",
197
+ "type": "list",
198
+ "values": [
199
+ {
200
+ "asset": {
201
+ "id": "markdown-primaryInfo-collection-unorderd-list-text-21",
202
+ "modifiers": [
203
+ {
204
+ "metaData": {
205
+ "ref": "https://turbotax.intuit.ca",
206
+ },
207
+ "type": "link",
208
+ },
209
+ ],
210
+ "type": "text",
211
+ "value": "First",
212
+ },
213
+ },
214
+ {
215
+ "asset": {
216
+ "id": "markdown-primaryInfo-collection-unorderd-list-text-25",
217
+ "type": "text",
218
+ "value": "Second",
219
+ },
220
+ },
221
+ {
222
+ "asset": {
223
+ "id": "markdown-primaryInfo-collection-unorderd-list-text-28",
224
+ "type": "text",
225
+ "value": "Third",
226
+ },
227
+ },
228
+ ],
229
+ },
230
+ },
231
+ {
232
+ "asset": {
233
+ "accessibility": "alt text",
234
+ "id": "markdown-primaryInfo-collection-image-image-32",
235
+ "metaData": {
236
+ "ref": "image.png",
237
+ },
238
+ "type": "image",
239
+ },
240
+ },
241
+ {
242
+ "asset": {
243
+ "id": "markdown-primaryInfo-collection-unsupported-text-34",
244
+ "type": "text",
245
+ "value": "Highlights are ==not supported==",
246
+ },
247
+ },
248
+ ],
249
+ },
250
+ },
251
+ "title": {
252
+ "asset": {
253
+ "id": "markdown-view-title-composite-3",
254
+ "type": "composite",
255
+ "values": [
256
+ {
257
+ "asset": {
258
+ "id": "markdown-view-title-text-0",
259
+ "type": "text",
260
+ "value": "Learn more at ",
261
+ },
262
+ },
263
+ {
264
+ "asset": {
265
+ "id": "markdown-view-title-text-1",
266
+ "modifiers": [
267
+ {
268
+ "metaData": {
269
+ "ref": "https://turbotax.intuit.ca",
270
+ },
271
+ "type": "link",
272
+ },
273
+ ],
274
+ "type": "text",
275
+ "value": "TurboTax Canada",
276
+ },
277
+ },
278
+ ],
279
+ },
280
+ },
281
+ "type": "questionAnswer",
282
+ }
283
+ `);
284
+ });
285
+
286
+ it("parses the flow, with only the required mappers", () => {
287
+ const player = new Player({
288
+ plugins: [
289
+ new MarkdownPlugin({
290
+ text: mockMappers.text,
291
+ paragraph: mockMappers.paragraph,
292
+ collection: mockMappers.collection,
293
+ }),
294
+ ],
295
+ });
296
+ player.start(unparsedFlow);
297
+
298
+ const view = (player.getState() as InProgressState).controllers.view
299
+ .currentView?.lastUpdate;
300
+
301
+ expect(view).toMatchInlineSnapshot(`
302
+ {
303
+ "id": "markdown-view",
304
+ "primaryInfo": {
305
+ "asset": {
306
+ "id": "markdown-primaryInfo-collection",
307
+ "type": "collection",
308
+ "values": [
309
+ {
310
+ "asset": {
311
+ "id": "markdown-primaryInfo-collection-bold",
312
+ "type": "text",
313
+ "value": "some **bold text**",
314
+ },
315
+ },
316
+ {
317
+ "asset": {
318
+ "id": "markdown-primaryInfo-collection-italic",
319
+ "type": "text",
320
+ "value": "*italicized text*",
321
+ },
322
+ },
323
+ {
324
+ "asset": {
325
+ "id": "markdown-primaryInfo-collection-orderd-list",
326
+ "type": "text",
327
+ "value": "1. First
328
+ 2. Second
329
+ 3. Third",
330
+ },
331
+ },
332
+ {
333
+ "asset": {
334
+ "id": "markdown-primaryInfo-collection-unorderd-list",
335
+ "type": "text",
336
+ "value": "- [First](https://turbotax.intuit.ca)
337
+ - Second
338
+ - Third",
339
+ },
340
+ },
341
+ {
342
+ "asset": {
343
+ "id": "markdown-primaryInfo-collection-image",
344
+ "type": "text",
345
+ "value": "![alt text](image.png)",
346
+ },
347
+ },
348
+ {
349
+ "asset": {
350
+ "id": "markdown-primaryInfo-collection-unsupported-text-36",
351
+ "type": "text",
352
+ "value": "Highlights are ==not supported==",
353
+ },
354
+ },
355
+ ],
356
+ },
357
+ },
358
+ "title": {
359
+ "asset": {
360
+ "id": "markdown-view-title",
361
+ "type": "text",
362
+ "value": "Learn more at [TurboTax Canada](https://turbotax.intuit.ca)",
363
+ },
364
+ },
365
+ "type": "questionAnswer",
366
+ }
367
+ `);
368
+ });
369
+ });
370
+
371
+ describe("Interactions with Asset Registry", () => {
372
+ it("parses regular flow and maps assets", () => {
373
+ const fingerprint = new PartialMatchFingerprintPlugin(new Registry());
374
+
375
+ fingerprint.register({ type: "action" }, 0);
376
+ fingerprint.register({ type: "text" }, 1);
377
+ fingerprint.register({ type: "composite" }, 2);
378
+
379
+ const player = new Player({
380
+ plugins: [fingerprint, new MarkdownPlugin(mockMappers)],
381
+ });
382
+
383
+ player.start({
384
+ id: "action-with-expression",
385
+ views: [
386
+ {
387
+ id: "action",
388
+ type: "action",
389
+ exp: "{{count}} = {{count}} + 1",
390
+ label: {
391
+ asset: {
392
+ id: "action-label",
393
+ type: "markdown",
394
+ value: "Clicked {{count}} *times*",
395
+ },
396
+ },
397
+ },
398
+ ],
399
+ data: {
400
+ count: 0,
401
+ },
402
+ navigation: {
403
+ BEGIN: "FLOW_1",
404
+ FLOW_1: {
405
+ startState: "VIEW_1",
406
+ VIEW_1: {
407
+ state_type: "VIEW",
408
+ ref: "action",
409
+ transitions: {
410
+ "*": "END_Done",
411
+ },
412
+ },
413
+ END_Done: {
414
+ state_type: "END",
415
+ outcome: "done",
416
+ },
417
+ },
418
+ },
419
+ });
420
+
421
+ // the parser should create 2 text assets: `Clicked {{count}}` and a italicized `times`:
422
+ const view = (player.getState() as InProgressState).controllers.view
423
+ .currentView?.lastUpdate;
424
+
425
+ expect(view).toMatchInlineSnapshot(`
426
+ {
427
+ "exp": "{{count}} = {{count}} + 1",
428
+ "id": "action",
429
+ "label": {
430
+ "asset": {
431
+ "id": "action-label-composite-41",
432
+ "type": "composite",
433
+ "values": [
434
+ {
435
+ "asset": {
436
+ "id": "action-label-text-38",
437
+ "type": "text",
438
+ "value": "Clicked 0 ",
439
+ },
440
+ },
441
+ {
442
+ "asset": {
443
+ "id": "action-label-text-39",
444
+ "modifiers": [
445
+ {
446
+ "type": "tag",
447
+ "value": "emphasis",
448
+ },
449
+ ],
450
+ "type": "text",
451
+ "value": "times",
452
+ },
453
+ },
454
+ ],
455
+ },
456
+ },
457
+ "type": "action",
458
+ }
459
+ `);
460
+ expect(fingerprint.get("action-label-text-38")).toBe(1);
461
+ expect(fingerprint.get("action-label-text-39")).toBe(1);
462
+ });
463
+ });
464
+ });
package/src/index.ts CHANGED
@@ -1,15 +1,15 @@
1
- import type { Player, PlayerPlugin } from '@player-ui/player';
2
- import { resolveDataRefsInString, NodeType } from '@player-ui/player';
3
- import type { Mappers } from './types';
4
- import { parseAssetMarkdownContent } from './utils';
1
+ import type { Player, PlayerPlugin } from "@player-ui/player";
2
+ import { resolveDataRefsInString, NodeType } from "@player-ui/player";
3
+ import type { Mappers } from "./types";
4
+ import { parseAssetMarkdownContent } from "./utils";
5
5
 
6
- export * from './types';
6
+ export * from "./types";
7
7
 
8
8
  /**
9
9
  * A plugin that parses markdown written into text assets using the given converters for markdown features into existing assets.
10
10
  */
11
11
  export class MarkdownPlugin implements PlayerPlugin {
12
- name = 'MarkdownPlugin';
12
+ name = "MarkdownPlugin";
13
13
 
14
14
  private mappers: Mappers;
15
15
 
@@ -21,13 +21,13 @@ export class MarkdownPlugin implements PlayerPlugin {
21
21
  player.hooks.view.tap(this.name, (view) => {
22
22
  view.hooks.resolver.tap(this.name, (resolver) => {
23
23
  resolver.hooks.beforeResolve.tap(this.name, (node, options) => {
24
- if (node?.type === NodeType.Asset && node.value.type === 'markdown') {
24
+ if (node?.type === NodeType.Asset && node.value.type === "markdown") {
25
25
  const resolvedContent = resolveDataRefsInString(
26
26
  node.value.value as string,
27
27
  {
28
28
  evaluate: options.evaluate,
29
29
  model: options.data.model,
30
- }
30
+ },
31
31
  );
32
32
 
33
33
  const parsed = parseAssetMarkdownContent({
package/src/types.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { Asset } from '@player-ui/types';
1
+ import type { Asset } from "@player-ui/types";
2
2
 
3
3
  export interface BaseArgs {
4
4
  /**
@@ -14,7 +14,7 @@ export type LiteralMapper<T extends object = object> = (
14
14
  */
15
15
  value: string;
16
16
  } & BaseArgs &
17
- T
17
+ T,
18
18
  ) => Asset;
19
19
 
20
20
  export type CompositeMapper<T extends object = object> = (
@@ -24,7 +24,7 @@ export type CompositeMapper<T extends object = object> = (
24
24
  */
25
25
  value: Asset[];
26
26
  } & BaseArgs &
27
- T
27
+ T,
28
28
  ) => Asset;
29
29
 
30
30
  export type FallbackMapper = (
@@ -33,7 +33,7 @@ export type FallbackMapper = (
33
33
  * markdown element value
34
34
  */
35
35
  value: string | Asset[];
36
- } & BaseArgs
36
+ } & BaseArgs,
37
37
  ) => Asset;
38
38
 
39
39
  export interface Mappers {
@@ -1,2 +1,2 @@
1
- export * from './markdownParser';
2
- export * from './transformers';
1
+ export * from "./markdownParser";
2
+ export * from "./transformers";
@@ -1,9 +1,9 @@
1
- import type { Node, ParseObjectOptions } from '@player-ui/player';
2
- import { NodeType } from '@player-ui/player';
3
- import type { Asset } from '@player-ui/types';
4
- import { fromMarkdown } from 'mdast-util-from-markdown';
5
- import type { Mappers } from '../types';
6
- import { transformers } from './transformers';
1
+ import type { Node, ParseObjectOptions } from "@player-ui/player";
2
+ import { NodeType } from "@player-ui/player";
3
+ import type { Asset } from "@player-ui/types";
4
+ import { fromMarkdown } from "mdast-util-from-markdown";
5
+ import type { Mappers } from "../types";
6
+ import { transformers } from "./transformers";
7
7
 
8
8
  /**
9
9
  * Parses markdown content using a provided mappers record.
@@ -29,7 +29,7 @@ export function parseAssetMarkdownContent({
29
29
  parser?: (
30
30
  obj: object,
31
31
  type?: Node.ChildrenTypes,
32
- options?: ParseObjectOptions
32
+ options?: ParseObjectOptions,
33
33
  ) => Node.Node | null;
34
34
  }): Node.Node | null {
35
35
  const { children } = fromMarkdown(asset.value as string);
@@ -1,4 +1,4 @@
1
- import type { Asset } from '@player-ui/types';
1
+ import type { Asset } from "@player-ui/types";
2
2
  import type {
3
3
  Blockquote,
4
4
  Code,
@@ -13,14 +13,14 @@ import type {
13
13
  Strong,
14
14
  Text,
15
15
  ThematicBreak,
16
- } from 'mdast-util-from-markdown/lib';
17
- import type { Transformer } from '../types';
16
+ } from "mdast-util-from-markdown/lib";
17
+ import type { Transformer } from "../types";
18
18
 
19
19
  /**
20
20
  * Swap markdown type to text
21
21
  */
22
22
  function swapMarkdownType(asset: Asset): Asset {
23
- return { ...asset, type: 'text' };
23
+ return { ...asset, type: "text" };
24
24
  }
25
25
 
26
26
  /**
@@ -48,7 +48,7 @@ const emphasisTransformer: Transformer<Emphasis> = ({
48
48
  const { children } = astNode;
49
49
 
50
50
  const value = children.map((node) =>
51
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
51
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
52
52
  );
53
53
 
54
54
  return mappers.emphasis({
@@ -73,7 +73,7 @@ const strongTransformer: Transformer<Strong> = ({
73
73
  const { children } = astNode;
74
74
 
75
75
  const value = children.map((node) =>
76
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
76
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
77
77
  );
78
78
 
79
79
  return mappers.strong({
@@ -100,7 +100,7 @@ const paragraphTransformer: Transformer<Paragraph> = ({
100
100
  children.every(({ type }) => Boolean(mappers[type as keyof typeof mappers]))
101
101
  ) {
102
102
  const value = children.map((node) =>
103
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
103
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
104
104
  );
105
105
 
106
106
  return mappers.paragraph({
@@ -125,7 +125,7 @@ const listTransformer: Transformer<List> = ({
125
125
  const { children, ordered, start } = astNode;
126
126
 
127
127
  const value = children.map((node) =>
128
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
128
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
129
129
  );
130
130
 
131
131
  return mappers.list({
@@ -151,7 +151,7 @@ const listItemTransformer: Transformer<ListItem> = ({
151
151
  const { children } = astNode;
152
152
 
153
153
  const value = children.map((node) =>
154
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
154
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
155
155
  );
156
156
 
157
157
  const mapper = mappers.listItem || mappers.paragraph;
@@ -175,7 +175,7 @@ const linkTransformer: Transformer<Link> = ({
175
175
  const { children, url } = astNode;
176
176
 
177
177
  const value = children.map((node) =>
178
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
178
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
179
179
  );
180
180
 
181
181
  return mappers.link({
@@ -198,7 +198,7 @@ const imageTransformer: Transformer<Image> = ({ astNode, asset, mappers }) => {
198
198
  return mappers.image({
199
199
  originalAsset: asset,
200
200
  src: url,
201
- value: title || alt || '',
201
+ value: title || alt || "",
202
202
  });
203
203
  }
204
204
 
@@ -218,7 +218,7 @@ const blockquoteTransformer: Transformer<Blockquote> = ({
218
218
  const { children } = astNode;
219
219
 
220
220
  const value = children.map((node) =>
221
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
221
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
222
222
  );
223
223
 
224
224
  return mappers.blockquote({
@@ -277,7 +277,7 @@ const horizontalRuleTransformer: Transformer<ThematicBreak> = ({
277
277
  if (mappers.horizontalRule) {
278
278
  return mappers.horizontalRule({
279
279
  originalAsset: asset,
280
- value: '---',
280
+ value: "---",
281
281
  });
282
282
  }
283
283
 
@@ -297,7 +297,7 @@ const headingTransformer: Transformer<Heading> = ({
297
297
  const { children, depth } = astNode;
298
298
 
299
299
  const value = children.map((node) =>
300
- transformers[node.type]({ astNode: node, asset, mappers, transformers })
300
+ transformers[node.type]({ astNode: node, asset, mappers, transformers }),
301
301
  );
302
302
 
303
303
  return mappers.heading({
@@ -0,0 +1,13 @@
1
+ import type { Player, PlayerPlugin } from "@player-ui/player";
2
+ import type { Mappers } from "./types";
3
+ export * from "./types";
4
+ /**
5
+ * A plugin that parses markdown written into text assets using the given converters for markdown features into existing assets.
6
+ */
7
+ export declare class MarkdownPlugin implements PlayerPlugin {
8
+ name: string;
9
+ private mappers;
10
+ constructor(mappers: Mappers);
11
+ apply(player: Player): void;
12
+ }
13
+ //# sourceMappingURL=index.d.ts.map