@player-tools/fluent 0.13.0--canary.221.5662

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.
Files changed (121) hide show
  1. package/dist/cjs/index.cjs +2257 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/index.legacy-esm.js +2143 -0
  4. package/dist/index.mjs +2143 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +36 -0
  7. package/src/core/base-builder/__tests__/fluent-builder-base.test.ts +2257 -0
  8. package/src/core/base-builder/__tests__/id-generator.test.ts +658 -0
  9. package/src/core/base-builder/__tests__/registry.test.ts +411 -0
  10. package/src/core/base-builder/__tests__/switch.test.ts +501 -0
  11. package/src/core/base-builder/__tests__/template.test.ts +449 -0
  12. package/src/core/base-builder/__tests__/value-extraction.test.ts +200 -0
  13. package/src/core/base-builder/conditional/index.ts +64 -0
  14. package/src/core/base-builder/context.ts +151 -0
  15. package/src/core/base-builder/fluent-builder-base.ts +261 -0
  16. package/src/core/base-builder/guards.ts +137 -0
  17. package/src/core/base-builder/id/generator.ts +286 -0
  18. package/src/core/base-builder/id/registry.ts +152 -0
  19. package/src/core/base-builder/index.ts +60 -0
  20. package/src/core/base-builder/resolution/path-resolver.ts +108 -0
  21. package/src/core/base-builder/resolution/pipeline.ts +96 -0
  22. package/src/core/base-builder/resolution/steps/asset-id.ts +77 -0
  23. package/src/core/base-builder/resolution/steps/asset-wrappers.ts +64 -0
  24. package/src/core/base-builder/resolution/steps/builders.ts +85 -0
  25. package/src/core/base-builder/resolution/steps/mixed-arrays.ts +117 -0
  26. package/src/core/base-builder/resolution/steps/static-values.ts +35 -0
  27. package/src/core/base-builder/resolution/steps/switches.ts +63 -0
  28. package/src/core/base-builder/resolution/steps/templates.ts +30 -0
  29. package/src/core/base-builder/resolution/value-resolver.ts +308 -0
  30. package/src/core/base-builder/storage/auxiliary-storage.ts +82 -0
  31. package/src/core/base-builder/storage/value-storage.ts +280 -0
  32. package/src/core/base-builder/types.ts +184 -0
  33. package/src/core/base-builder/utils.ts +10 -0
  34. package/src/core/flow/__tests__/index.test.ts +292 -0
  35. package/src/core/flow/index.ts +141 -0
  36. package/src/core/index.ts +8 -0
  37. package/src/core/mocks/generated/action.builder.ts +109 -0
  38. package/src/core/mocks/generated/choice.builder.ts +161 -0
  39. package/src/core/mocks/generated/choiceItem.builder.ts +133 -0
  40. package/src/core/mocks/generated/collection.builder.ts +117 -0
  41. package/src/core/mocks/generated/index.ts +7 -0
  42. package/src/core/mocks/generated/info.builder.ts +80 -0
  43. package/src/core/mocks/generated/input.builder.ts +75 -0
  44. package/src/core/mocks/generated/text.builder.ts +63 -0
  45. package/src/core/mocks/index.ts +1 -0
  46. package/src/core/mocks/types/action.ts +92 -0
  47. package/src/core/mocks/types/choice.ts +129 -0
  48. package/src/core/mocks/types/collection.ts +140 -0
  49. package/src/core/mocks/types/info.ts +7 -0
  50. package/src/core/mocks/types/input.ts +7 -0
  51. package/src/core/mocks/types/text.ts +5 -0
  52. package/src/core/schema/__tests__/index.test.ts +127 -0
  53. package/src/core/schema/index.ts +195 -0
  54. package/src/core/schema/types.ts +7 -0
  55. package/src/core/switch/__tests__/index.test.ts +156 -0
  56. package/src/core/switch/index.ts +76 -0
  57. package/src/core/tagged-template/README.md +448 -0
  58. package/src/core/tagged-template/__tests__/extract-bindings-from-schema.test.ts +207 -0
  59. package/src/core/tagged-template/__tests__/index.test.ts +190 -0
  60. package/src/core/tagged-template/__tests__/schema-std-integration.test.ts +580 -0
  61. package/src/core/tagged-template/binding.ts +95 -0
  62. package/src/core/tagged-template/expression.ts +92 -0
  63. package/src/core/tagged-template/extract-bindings-from-schema.ts +120 -0
  64. package/src/core/tagged-template/index.ts +5 -0
  65. package/src/core/tagged-template/std.ts +472 -0
  66. package/src/core/tagged-template/types.ts +123 -0
  67. package/src/core/template/__tests__/index.test.ts +380 -0
  68. package/src/core/template/index.ts +191 -0
  69. package/src/core/utils/index.ts +160 -0
  70. package/src/fp/README.md +411 -0
  71. package/src/fp/__tests__/index.test.ts +1178 -0
  72. package/src/fp/index.ts +386 -0
  73. package/src/gen/common.ts +2 -0
  74. package/src/gen/plugin.mjs +315 -0
  75. package/src/index.ts +5 -0
  76. package/src/types.ts +203 -0
  77. package/types/core/base-builder/conditional/index.d.ts +21 -0
  78. package/types/core/base-builder/context.d.ts +39 -0
  79. package/types/core/base-builder/fluent-builder-base.d.ts +132 -0
  80. package/types/core/base-builder/guards.d.ts +58 -0
  81. package/types/core/base-builder/id/generator.d.ts +69 -0
  82. package/types/core/base-builder/id/registry.d.ts +93 -0
  83. package/types/core/base-builder/index.d.ts +8 -0
  84. package/types/core/base-builder/resolution/path-resolver.d.ts +15 -0
  85. package/types/core/base-builder/resolution/pipeline.d.ts +25 -0
  86. package/types/core/base-builder/resolution/steps/asset-id.d.ts +14 -0
  87. package/types/core/base-builder/resolution/steps/asset-wrappers.d.ts +14 -0
  88. package/types/core/base-builder/resolution/steps/builders.d.ts +14 -0
  89. package/types/core/base-builder/resolution/steps/mixed-arrays.d.ts +14 -0
  90. package/types/core/base-builder/resolution/steps/static-values.d.ts +14 -0
  91. package/types/core/base-builder/resolution/steps/switches.d.ts +15 -0
  92. package/types/core/base-builder/resolution/steps/templates.d.ts +14 -0
  93. package/types/core/base-builder/resolution/value-resolver.d.ts +37 -0
  94. package/types/core/base-builder/storage/auxiliary-storage.d.ts +50 -0
  95. package/types/core/base-builder/storage/value-storage.d.ts +82 -0
  96. package/types/core/base-builder/types.d.ts +141 -0
  97. package/types/core/base-builder/utils.d.ts +2 -0
  98. package/types/core/flow/index.d.ts +23 -0
  99. package/types/core/index.d.ts +8 -0
  100. package/types/core/mocks/index.d.ts +2 -0
  101. package/types/core/mocks/types/action.d.ts +58 -0
  102. package/types/core/mocks/types/choice.d.ts +95 -0
  103. package/types/core/mocks/types/collection.d.ts +102 -0
  104. package/types/core/mocks/types/info.d.ts +7 -0
  105. package/types/core/mocks/types/input.d.ts +7 -0
  106. package/types/core/mocks/types/text.d.ts +5 -0
  107. package/types/core/schema/index.d.ts +34 -0
  108. package/types/core/schema/types.d.ts +5 -0
  109. package/types/core/switch/index.d.ts +21 -0
  110. package/types/core/tagged-template/binding.d.ts +19 -0
  111. package/types/core/tagged-template/expression.d.ts +11 -0
  112. package/types/core/tagged-template/extract-bindings-from-schema.d.ts +7 -0
  113. package/types/core/tagged-template/index.d.ts +6 -0
  114. package/types/core/tagged-template/std.d.ts +174 -0
  115. package/types/core/tagged-template/types.d.ts +69 -0
  116. package/types/core/template/index.d.ts +97 -0
  117. package/types/core/utils/index.d.ts +47 -0
  118. package/types/fp/index.d.ts +149 -0
  119. package/types/gen/common.d.ts +3 -0
  120. package/types/index.d.ts +3 -0
  121. package/types/types.d.ts +163 -0
@@ -0,0 +1,501 @@
1
+ import { describe, test, expect, beforeEach } from "vitest";
2
+ import { FluentBuilderBase } from "../fluent-builder-base";
3
+ import { BaseBuildContext, FluentBuilder } from "../types";
4
+ import { resetGlobalIdSet } from "../id/generator";
5
+ import { expression } from "../../tagged-template";
6
+ import type { Asset } from "@player-ui/types";
7
+
8
+ interface TestAsset extends Asset<"test"> {
9
+ value: string;
10
+ }
11
+
12
+ class TestAssetBuilder
13
+ extends FluentBuilderBase<TestAsset>
14
+ implements FluentBuilder<TestAsset, BaseBuildContext>
15
+ {
16
+ constructor() {
17
+ super({ type: "test" });
18
+ }
19
+
20
+ value(v: string): this {
21
+ return this.set("value", v);
22
+ }
23
+
24
+ id(v: string): this {
25
+ return this.set("id", v);
26
+ }
27
+
28
+ build(context?: BaseBuildContext): TestAsset {
29
+ return this.buildWithDefaults({ type: "test", value: "" }, context);
30
+ }
31
+ }
32
+
33
+ interface CollectionAsset extends Asset<"collection"> {
34
+ values?: Array<{ asset: Asset }>;
35
+ }
36
+
37
+ class CollectionBuilder
38
+ extends FluentBuilderBase<CollectionAsset>
39
+ implements FluentBuilder<CollectionAsset, BaseBuildContext>
40
+ {
41
+ constructor() {
42
+ super({ type: "collection" });
43
+ }
44
+
45
+ withValues(v: Array<FluentBuilder<Asset, BaseBuildContext> | Asset>): this {
46
+ return this.set("values", { asset: v });
47
+ }
48
+
49
+ id(v: string): this {
50
+ return this.set("id", v);
51
+ }
52
+
53
+ build(context?: BaseBuildContext): CollectionAsset {
54
+ return this.buildWithDefaults({ type: "collection" }, context);
55
+ }
56
+ }
57
+
58
+ describe("Switch Integration with FluentBuilderBase", () => {
59
+ beforeEach(() => {
60
+ resetGlobalIdSet();
61
+ });
62
+
63
+ describe("Basic switch() method", () => {
64
+ test("can add a switch to a builder using the switch() method", () => {
65
+ const builder = new TestAssetBuilder()
66
+ .value("original")
67
+ .switch(["value"], {
68
+ cases: [
69
+ {
70
+ case: expression`user.lang === 'es'`,
71
+ asset: new TestAssetBuilder().value("Hola"),
72
+ },
73
+ { case: true, asset: new TestAssetBuilder().value("Hello") },
74
+ ],
75
+ });
76
+
77
+ const result = builder.build({ parentId: "test" });
78
+
79
+ expect(result).toEqual({
80
+ id: "test-test",
81
+ type: "test",
82
+ value: {
83
+ staticSwitch: [
84
+ {
85
+ case: "@[user.lang === 'es']@",
86
+ asset: {
87
+ value: "Hola",
88
+ type: "test",
89
+ id: "test-test-value-staticSwitch-0-test",
90
+ },
91
+ },
92
+ {
93
+ case: true,
94
+ asset: {
95
+ value: "Hello",
96
+ type: "test",
97
+ id: "test-test-value-staticSwitch-1-test",
98
+ },
99
+ },
100
+ ],
101
+ },
102
+ });
103
+ });
104
+
105
+ test("can add dynamic switch", () => {
106
+ const builder = new TestAssetBuilder()
107
+ .value("original")
108
+ .switch(["value"], {
109
+ cases: [{ case: true, asset: new TestAssetBuilder().value("Hi") }],
110
+ isDynamic: true,
111
+ });
112
+
113
+ const result = builder.build({ parentId: "test" });
114
+
115
+ expect(result).toEqual({
116
+ id: "test-test",
117
+ type: "test",
118
+ value: {
119
+ dynamicSwitch: [
120
+ {
121
+ case: true,
122
+ asset: {
123
+ value: "Hi",
124
+ type: "test",
125
+ id: "test-test-value-dynamicSwitch-0-test",
126
+ },
127
+ },
128
+ ],
129
+ },
130
+ });
131
+ });
132
+
133
+ test("preserves existing asset id when provided", () => {
134
+ const builder = new TestAssetBuilder()
135
+ .value("original")
136
+ .switch(["value"], {
137
+ cases: [
138
+ {
139
+ case: true,
140
+ asset: new TestAssetBuilder().value("Hello").id("custom-id"),
141
+ },
142
+ ],
143
+ });
144
+
145
+ const result = builder.build({ parentId: "test" });
146
+
147
+ expect(result.value).toEqual({
148
+ staticSwitch: [
149
+ {
150
+ case: true,
151
+ asset: {
152
+ value: "Hello",
153
+ type: "test",
154
+ id: "custom-id",
155
+ },
156
+ },
157
+ ],
158
+ });
159
+ });
160
+
161
+ test("handles multiple cases with sequential indexing", () => {
162
+ const builder = new TestAssetBuilder()
163
+ .value("original")
164
+ .switch(["value"], {
165
+ cases: [
166
+ {
167
+ case: expression`name.first === 'John'`,
168
+ asset: new TestAssetBuilder().value("First"),
169
+ },
170
+ {
171
+ case: expression`name.first === 'Jane'`,
172
+ asset: new TestAssetBuilder().value("Second"),
173
+ },
174
+ { case: true, asset: new TestAssetBuilder().value("Default") },
175
+ ],
176
+ });
177
+
178
+ const result = builder.build({ parentId: "test" });
179
+
180
+ expect(result.value).toEqual({
181
+ staticSwitch: [
182
+ {
183
+ case: "@[name.first === 'John']@",
184
+ asset: {
185
+ value: "First",
186
+ type: "test",
187
+ id: "test-test-value-staticSwitch-0-test",
188
+ },
189
+ },
190
+ {
191
+ case: "@[name.first === 'Jane']@",
192
+ asset: {
193
+ value: "Second",
194
+ type: "test",
195
+ id: "test-test-value-staticSwitch-1-test",
196
+ },
197
+ },
198
+ {
199
+ case: true,
200
+ asset: {
201
+ value: "Default",
202
+ type: "test",
203
+ id: "test-test-value-staticSwitch-2-test",
204
+ },
205
+ },
206
+ ],
207
+ });
208
+ });
209
+ });
210
+
211
+ describe("Switch with nested paths", () => {
212
+ test("can replace array element with switch", () => {
213
+ const builder = new CollectionBuilder()
214
+ .withValues([
215
+ new TestAssetBuilder().value("Item 1"),
216
+ new TestAssetBuilder().value("Item 2"),
217
+ new TestAssetBuilder().value("Item 3"),
218
+ ])
219
+ .switch(["values", 1], {
220
+ cases: [
221
+ {
222
+ case: expression`user.isAdmin`,
223
+ asset: new TestAssetBuilder().value("Admin Item"),
224
+ },
225
+ { case: true, asset: new TestAssetBuilder().value("Default") },
226
+ ],
227
+ });
228
+
229
+ const result = builder.build({ parentId: "test" });
230
+
231
+ expect(result).toEqual({
232
+ id: "test-collection",
233
+ type: "collection",
234
+ values: [
235
+ {
236
+ asset: {
237
+ id: "test-collection-values-0-test",
238
+ type: "test",
239
+ value: "Item 1",
240
+ },
241
+ },
242
+ {
243
+ staticSwitch: [
244
+ {
245
+ case: "@[user.isAdmin]@",
246
+ asset: {
247
+ value: "Admin Item",
248
+ type: "test",
249
+ id: "test-collection-values-staticSwitch-0-test",
250
+ },
251
+ },
252
+ {
253
+ case: true,
254
+ asset: {
255
+ value: "Default",
256
+ type: "test",
257
+ id: "test-collection-values-staticSwitch-1-test",
258
+ },
259
+ },
260
+ ],
261
+ },
262
+ {
263
+ asset: {
264
+ id: "test-collection-values-2-test",
265
+ type: "test",
266
+ value: "Item 3",
267
+ },
268
+ },
269
+ ],
270
+ });
271
+ });
272
+
273
+ test("can add multiple switches at different array indices", () => {
274
+ const builder = new CollectionBuilder()
275
+ .withValues([
276
+ new TestAssetBuilder().value("Item 1"),
277
+ new TestAssetBuilder().value("Item 2"),
278
+ new TestAssetBuilder().value("Item 3"),
279
+ ])
280
+ .switch(["values", 0], {
281
+ cases: [
282
+ {
283
+ case: expression`showSpecial`,
284
+ asset: new TestAssetBuilder().value("Special First"),
285
+ },
286
+ {
287
+ case: true,
288
+ asset: new TestAssetBuilder().value("Regular First"),
289
+ },
290
+ ],
291
+ })
292
+ .switch(["values", 2], {
293
+ cases: [
294
+ {
295
+ case: expression`user.isPremium`,
296
+ asset: new TestAssetBuilder().value("Premium Last"),
297
+ },
298
+ {
299
+ case: true,
300
+ asset: new TestAssetBuilder().value("Standard Last"),
301
+ },
302
+ ],
303
+ });
304
+
305
+ const result = builder.build({ parentId: "test" });
306
+
307
+ expect(result).toEqual({
308
+ id: "test-collection",
309
+ type: "collection",
310
+ values: [
311
+ {
312
+ staticSwitch: [
313
+ {
314
+ case: "@[showSpecial]@",
315
+ asset: {
316
+ value: "Special First",
317
+ type: "test",
318
+ id: "test-collection-values-staticSwitch-0-test",
319
+ },
320
+ },
321
+ {
322
+ case: true,
323
+ asset: {
324
+ value: "Regular First",
325
+ type: "test",
326
+ id: "test-collection-values-staticSwitch-1-test",
327
+ },
328
+ },
329
+ ],
330
+ },
331
+ {
332
+ asset: {
333
+ id: "test-collection-values-1-test",
334
+ type: "test",
335
+ value: "Item 2",
336
+ },
337
+ },
338
+ {
339
+ staticSwitch: [
340
+ {
341
+ case: "@[user.isPremium]@",
342
+ asset: {
343
+ value: "Premium Last",
344
+ type: "test",
345
+ id: "test-collection-values-staticSwitch-2-test",
346
+ },
347
+ },
348
+ {
349
+ case: true,
350
+ asset: {
351
+ value: "Standard Last",
352
+ type: "test",
353
+ id: "test-collection-values-staticSwitch-3-test",
354
+ },
355
+ },
356
+ ],
357
+ },
358
+ ],
359
+ });
360
+ });
361
+ });
362
+
363
+ describe("Switch reusability", () => {
364
+ test("can reuse the same builder with different contexts", () => {
365
+ const builder = new TestAssetBuilder()
366
+ .value("original")
367
+ .switch(["value"], {
368
+ cases: [{ case: true, asset: new TestAssetBuilder().value("Hi") }],
369
+ });
370
+
371
+ const result1 = builder.build({ parentId: "test1" });
372
+ const result2 = builder.build({ parentId: "test2" });
373
+
374
+ expect(result1.id).toBe("test1-test");
375
+ expect(result2.id).toBe("test2-test");
376
+
377
+ const switch1: unknown = result1.value;
378
+ const switch2: unknown = result2.value;
379
+
380
+ expect(switch1).toHaveProperty("staticSwitch");
381
+ expect(switch2).toHaveProperty("staticSwitch");
382
+
383
+ if (
384
+ typeof switch1 === "object" &&
385
+ switch1 !== null &&
386
+ "staticSwitch" in switch1 &&
387
+ typeof switch2 === "object" &&
388
+ switch2 !== null &&
389
+ "staticSwitch" in switch2
390
+ ) {
391
+ const staticSwitch1 = switch1.staticSwitch;
392
+ const staticSwitch2 = switch2.staticSwitch;
393
+
394
+ if (
395
+ Array.isArray(staticSwitch1) &&
396
+ Array.isArray(staticSwitch2) &&
397
+ staticSwitch1.length > 0 &&
398
+ staticSwitch2.length > 0
399
+ ) {
400
+ const case1 = staticSwitch1[0];
401
+ const case2 = staticSwitch2[0];
402
+
403
+ if (typeof case1 === "object" && case1 !== null && "asset" in case1) {
404
+ const asset1 = case1.asset;
405
+ if (
406
+ typeof asset1 === "object" &&
407
+ asset1 !== null &&
408
+ "id" in asset1
409
+ ) {
410
+ expect(asset1.id).toBe("test1-test-value-staticSwitch-0-test");
411
+ }
412
+ }
413
+
414
+ if (typeof case2 === "object" && case2 !== null && "asset" in case2) {
415
+ const asset2 = case2.asset;
416
+ if (
417
+ typeof asset2 === "object" &&
418
+ asset2 !== null &&
419
+ "id" in asset2
420
+ ) {
421
+ expect(asset2.id).toBe("test2-test-value-staticSwitch-0-test");
422
+ }
423
+ }
424
+ }
425
+ }
426
+ });
427
+ });
428
+
429
+ describe("Switch with string case expressions", () => {
430
+ test("handles string case expressions", () => {
431
+ const builder = new TestAssetBuilder()
432
+ .value("original")
433
+ .switch(["value"], {
434
+ cases: [
435
+ {
436
+ case: "{{foo}} === 'bar'",
437
+ asset: new TestAssetBuilder().value("Match"),
438
+ },
439
+ { case: true, asset: new TestAssetBuilder().value("No Match") },
440
+ ],
441
+ });
442
+
443
+ const result = builder.build({ parentId: "test" });
444
+
445
+ expect(result.value).toEqual({
446
+ staticSwitch: [
447
+ {
448
+ case: "{{foo}} === 'bar'",
449
+ asset: {
450
+ value: "Match",
451
+ type: "test",
452
+ id: "test-test-value-staticSwitch-0-test",
453
+ },
454
+ },
455
+ {
456
+ case: true,
457
+ asset: {
458
+ value: "No Match",
459
+ type: "test",
460
+ id: "test-test-value-staticSwitch-1-test",
461
+ },
462
+ },
463
+ ],
464
+ });
465
+ });
466
+
467
+ test("handles boolean case expressions", () => {
468
+ const builder = new TestAssetBuilder()
469
+ .value("original")
470
+ .switch(["value"], {
471
+ cases: [
472
+ { case: false, asset: new TestAssetBuilder().value("False") },
473
+ { case: true, asset: new TestAssetBuilder().value("True") },
474
+ ],
475
+ });
476
+
477
+ const result = builder.build({ parentId: "test" });
478
+
479
+ expect(result.value).toEqual({
480
+ staticSwitch: [
481
+ {
482
+ case: false,
483
+ asset: {
484
+ value: "False",
485
+ type: "test",
486
+ id: "test-test-value-staticSwitch-0-test",
487
+ },
488
+ },
489
+ {
490
+ case: true,
491
+ asset: {
492
+ value: "True",
493
+ type: "test",
494
+ id: "test-test-value-staticSwitch-1-test",
495
+ },
496
+ },
497
+ ],
498
+ });
499
+ });
500
+ });
501
+ });