@player-tools/dsl 0.5.0--canary.62.1176 → 0.5.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.
Files changed (52) hide show
  1. package/dist/cjs/index.cjs +973 -0
  2. package/dist/cjs/index.cjs.map +1 -0
  3. package/dist/index.legacy-esm.js +910 -0
  4. package/dist/index.mjs +910 -0
  5. package/dist/index.mjs.map +1 -0
  6. package/package.json +27 -33
  7. package/src/__tests__/asset-api.test.tsx +354 -0
  8. package/src/__tests__/edge-cases.test.tsx +81 -0
  9. package/src/__tests__/helpers/asset-library.tsx +371 -0
  10. package/src/__tests__/helpers/mock-data-refs.ts +21 -0
  11. package/src/__tests__/json.test.ts +12 -0
  12. package/src/__tests__/jsx.test.tsx +138 -0
  13. package/src/__tests__/schema.test.tsx +378 -0
  14. package/src/__tests__/switch.test.tsx +251 -0
  15. package/src/__tests__/template.test.tsx +294 -0
  16. package/src/__tests__/view-api.test.tsx +46 -0
  17. package/src/auto-id.tsx +10 -10
  18. package/src/compiler/__tests__/compiler.test.tsx +264 -0
  19. package/src/compiler/__tests__/schema.test.ts +127 -0
  20. package/src/compiler/compiler.ts +50 -46
  21. package/src/compiler/index.ts +3 -3
  22. package/src/compiler/schema.ts +29 -25
  23. package/src/compiler/types.ts +15 -12
  24. package/src/compiler/utils.ts +7 -7
  25. package/src/components.tsx +17 -12
  26. package/src/index.ts +11 -11
  27. package/src/string-templates/__tests__/binding.test.ts +87 -0
  28. package/src/string-templates/__tests__/edge-cases.test.ts +6 -0
  29. package/src/string-templates/__tests__/expression.test.ts +9 -0
  30. package/src/string-templates/__tests__/react.test.tsx +75 -0
  31. package/src/string-templates/index.ts +40 -22
  32. package/src/switch.tsx +12 -12
  33. package/src/template.tsx +38 -34
  34. package/src/types.ts +5 -5
  35. package/src/utils.tsx +8 -8
  36. package/types/auto-id.d.ts +33 -0
  37. package/types/compiler/compiler.d.ts +27 -0
  38. package/types/compiler/index.d.ts +4 -0
  39. package/types/compiler/schema.d.ts +61 -0
  40. package/types/compiler/types.d.ts +55 -0
  41. package/types/compiler/utils.d.ts +4 -0
  42. package/types/components.d.ts +90 -0
  43. package/types/index.d.ts +12 -0
  44. package/types/string-templates/index.d.ts +50 -0
  45. package/types/switch.d.ts +19 -0
  46. package/types/template.d.ts +20 -0
  47. package/types/types.d.ts +42 -0
  48. package/types/utils.d.ts +33 -0
  49. package/README.md +0 -9
  50. package/dist/index.cjs.js +0 -990
  51. package/dist/index.d.ts +0 -404
  52. package/dist/index.esm.js +0 -923
@@ -0,0 +1,378 @@
1
+ import { test, expect, describe, vi } from "vitest";
2
+ import React from "react";
3
+ import { render } from "react-json-reconciler";
4
+ import {
5
+ makeBindingsForObject,
6
+ SchemaGenerator,
7
+ SchemaTypeName,
8
+ } from "../compiler/schema";
9
+ import { FooTypeRef, BarTypeRef, LocalBazType } from "./helpers/mock-data-refs";
10
+
11
+ describe("Schema Bindings Generate Properly", () => {
12
+ const testObj = {
13
+ main: {
14
+ sub: {
15
+ a: FooTypeRef,
16
+ b: BarTypeRef,
17
+ },
18
+ sub2: [
19
+ {
20
+ [SchemaTypeName]: "sub2a",
21
+ val: LocalBazType,
22
+ },
23
+ ],
24
+ sub4: {
25
+ [SchemaTypeName]: "sub3",
26
+ c: FooTypeRef,
27
+ },
28
+ },
29
+ };
30
+
31
+ test("is able to get bindings for all paths", () => {
32
+ const schema = makeBindingsForObject(testObj);
33
+ expect(schema.main.toRefString()).toStrictEqual("{{main}}");
34
+ expect(schema.main.sub.toRefString()).toStrictEqual("{{main.sub}}");
35
+ expect(schema.main.sub.a.toRefString()).toStrictEqual("{{main.sub.a}}");
36
+ expect(schema.main.sub.b.toRefString()).toStrictEqual("{{main.sub.b}}");
37
+ expect(schema.main.sub2.toRefString()).toStrictEqual("{{main.sub2}}");
38
+ expect(schema.main.sub2[0].toRefString()).toStrictEqual("{{main.sub2.0}}");
39
+ expect(schema.main.sub2._index_.toRefString()).toStrictEqual(
40
+ "{{main.sub2._index_}}"
41
+ );
42
+
43
+ expect(schema.main.sub2[0].val.toRefString()).toStrictEqual(
44
+ "{{main.sub2.0.val}}"
45
+ );
46
+ expect(
47
+ // eslint-disable-next-line dot-notation
48
+ schema.main.sub2["_index_"].toRefString()
49
+ ).toStrictEqual("{{main.sub2._index_}}");
50
+ expect(
51
+ // eslint-disable-next-line dot-notation
52
+ schema.main.sub2["_index_"].val.toRefString()
53
+ ).toStrictEqual("{{main.sub2._index_.val}}");
54
+ });
55
+
56
+ test("is able to serialize to a schema object", () => {
57
+ const g = new SchemaGenerator();
58
+ const schema = g.toSchema(testObj);
59
+ expect(schema).toMatchInlineSnapshot(`
60
+ {
61
+ "ROOT": {
62
+ "main": {
63
+ "type": "mainType",
64
+ },
65
+ },
66
+ "mainType": {
67
+ "sub": {
68
+ "type": "subType",
69
+ },
70
+ "sub2": {
71
+ "isArray": true,
72
+ "type": "sub2aType",
73
+ },
74
+ "sub4": {
75
+ "type": "sub3Type",
76
+ },
77
+ },
78
+ "sub2aType": {
79
+ "val": {
80
+ "default": false,
81
+ "type": "BazType",
82
+ "validation": [
83
+ {
84
+ "message": "some message",
85
+ "options": [
86
+ "1",
87
+ "2",
88
+ ],
89
+ "type": "someValidation",
90
+ },
91
+ ],
92
+ },
93
+ },
94
+ "sub3Type": {
95
+ "c": {
96
+ "type": "FooType",
97
+ },
98
+ },
99
+ "subType": {
100
+ "a": {
101
+ "type": "FooType",
102
+ },
103
+ "b": {
104
+ "type": "BarType",
105
+ },
106
+ },
107
+ }
108
+ `);
109
+ });
110
+
111
+ test("is able to serialize to a schema object with a custom array indicator", () => {
112
+ const g = new SchemaGenerator();
113
+ const schema = g.toSchema(testObj);
114
+ expect(schema).toMatchInlineSnapshot(`
115
+ {
116
+ "ROOT": {
117
+ "main": {
118
+ "type": "mainType",
119
+ },
120
+ },
121
+ "mainType": {
122
+ "sub": {
123
+ "type": "subType",
124
+ },
125
+ "sub2": {
126
+ "isArray": true,
127
+ "type": "sub2aType",
128
+ },
129
+ "sub4": {
130
+ "type": "sub3Type",
131
+ },
132
+ },
133
+ "sub2aType": {
134
+ "val": {
135
+ "default": false,
136
+ "type": "BazType",
137
+ "validation": [
138
+ {
139
+ "message": "some message",
140
+ "options": [
141
+ "1",
142
+ "2",
143
+ ],
144
+ "type": "someValidation",
145
+ },
146
+ ],
147
+ },
148
+ },
149
+ "sub3Type": {
150
+ "c": {
151
+ "type": "FooType",
152
+ },
153
+ },
154
+ "subType": {
155
+ "a": {
156
+ "type": "FooType",
157
+ },
158
+ "b": {
159
+ "type": "BarType",
160
+ },
161
+ },
162
+ }
163
+ `);
164
+ });
165
+
166
+ test("logs warning if two types have the same name but are different", () => {
167
+ const mockLogger = {
168
+ error: vi.fn(),
169
+ warn: vi.fn(),
170
+ log: vi.fn(),
171
+ };
172
+
173
+ const g = new SchemaGenerator(mockLogger);
174
+
175
+ const badObj = {
176
+ main: {
177
+ sub: {
178
+ a: FooTypeRef,
179
+ b: BarTypeRef,
180
+ c: BarTypeRef,
181
+ },
182
+ sub2: {
183
+ sub: {
184
+ a: FooTypeRef,
185
+ b: BarTypeRef,
186
+ },
187
+ },
188
+ },
189
+ };
190
+
191
+ const results = g.toSchema(badObj);
192
+ expect(mockLogger.warn).toHaveBeenCalledTimes(1);
193
+ expect(mockLogger.warn).toHaveBeenCalledWith(
194
+ "WARNING: Generated two intermediate types with the name: subType that are of different shapes, using artificial type subType2"
195
+ );
196
+ expect(results).toMatchInlineSnapshot(`
197
+ {
198
+ "ROOT": {
199
+ "main": {
200
+ "type": "mainType",
201
+ },
202
+ },
203
+ "mainType": {
204
+ "sub": {
205
+ "type": "subType",
206
+ },
207
+ "sub2": {
208
+ "type": "sub2Type",
209
+ },
210
+ },
211
+ "sub2Type": {
212
+ "sub": {
213
+ "type": "subType2",
214
+ },
215
+ },
216
+ "subType": {
217
+ "a": {
218
+ "type": "FooType",
219
+ },
220
+ "b": {
221
+ "type": "BarType",
222
+ },
223
+ "c": {
224
+ "type": "BarType",
225
+ },
226
+ },
227
+ "subType2": {
228
+ "a": {
229
+ "type": "FooType",
230
+ },
231
+ "b": {
232
+ "type": "BarType",
233
+ },
234
+ },
235
+ }
236
+ `);
237
+ });
238
+
239
+ test("doesnt throw errors if two types have the same name and are the same", () => {
240
+ const g = new SchemaGenerator();
241
+
242
+ const badObj = {
243
+ main: {
244
+ sub: {
245
+ a: FooTypeRef,
246
+ b: BarTypeRef,
247
+ },
248
+ sub2: {
249
+ sub: {
250
+ a: FooTypeRef,
251
+ b: BarTypeRef,
252
+ },
253
+ },
254
+ },
255
+ };
256
+
257
+ expect(g.toSchema(badObj)).toMatchInlineSnapshot(`
258
+ {
259
+ "ROOT": {
260
+ "main": {
261
+ "type": "mainType",
262
+ },
263
+ },
264
+ "mainType": {
265
+ "sub": {
266
+ "type": "subType",
267
+ },
268
+ "sub2": {
269
+ "type": "sub2Type",
270
+ },
271
+ },
272
+ "sub2Type": {
273
+ "sub": {
274
+ "type": "subType",
275
+ },
276
+ },
277
+ "subType": {
278
+ "a": {
279
+ "type": "FooType",
280
+ },
281
+ "b": {
282
+ "type": "BarType",
283
+ },
284
+ },
285
+ }
286
+ `);
287
+ });
288
+
289
+ test("works when used as a jsx element", async () => {
290
+ const schema = makeBindingsForObject(testObj);
291
+
292
+ const content = await render(
293
+ <obj>
294
+ <property name="test">{schema.main.sub.a}</property>
295
+ </obj>
296
+ );
297
+
298
+ expect(content.jsonValue).toMatchInlineSnapshot(`
299
+ {
300
+ "test": "{{main.sub.a}}",
301
+ }
302
+ `);
303
+ });
304
+
305
+ test("primitive arrays are not treated as bindings nor further proxied", () => {
306
+ const schema = makeBindingsForObject({
307
+ main: {
308
+ sub: {
309
+ a: FooTypeRef,
310
+ b: BarTypeRef,
311
+ c: {
312
+ type: "enumtype",
313
+ enum: ["A", "B", "C"],
314
+ },
315
+ },
316
+ sub2: [
317
+ {
318
+ val: LocalBazType,
319
+ },
320
+ ],
321
+ sub4: {
322
+ [SchemaTypeName]: "sub3",
323
+ c: FooTypeRef,
324
+ },
325
+ },
326
+ });
327
+
328
+ expect(schema.main.toRefString()).toStrictEqual("{{main}}");
329
+ expect(schema.main.sub.toRefString()).toStrictEqual("{{main.sub}}");
330
+ expect(schema.main.sub.a.toRefString()).toStrictEqual("{{main.sub.a}}");
331
+ expect(schema.main.sub.c.toRefString()).toStrictEqual("{{main.sub.c}}");
332
+ expect(schema.main.sub.c.enum).toStrictEqual(["A", "B", "C"]);
333
+ // make sure iterable method is still there and works
334
+ expect(
335
+ schema.main.sub.c.enum.every((it: any) => typeof it === "string")
336
+ ).toStrictEqual(true);
337
+ });
338
+ });
339
+
340
+ describe("schema plugins", () => {
341
+ const MetaData = Symbol("Meta Data");
342
+ const testObj = {
343
+ foo: {
344
+ [MetaData]: {
345
+ testProp: false,
346
+ },
347
+ },
348
+ };
349
+
350
+ test("enables node modification", () => {
351
+ const schemaGenerator = new SchemaGenerator();
352
+
353
+ schemaGenerator.hooks.createSchemaNode.tap("test", (node, prop) => {
354
+ if (prop[MetaData]) {
355
+ return {
356
+ ...node,
357
+ metaData: prop[MetaData],
358
+ };
359
+ }
360
+
361
+ return node;
362
+ });
363
+
364
+ expect(schemaGenerator.toSchema(testObj)).toMatchInlineSnapshot(`
365
+ {
366
+ "ROOT": {
367
+ "foo": {
368
+ "metaData": {
369
+ "testProp": false,
370
+ },
371
+ "type": "fooType",
372
+ },
373
+ },
374
+ "fooType": {},
375
+ }
376
+ `);
377
+ });
378
+ });
@@ -0,0 +1,251 @@
1
+ import { test, expect, describe } from "vitest";
2
+ import React from "react";
3
+ import { render } from "react-json-reconciler";
4
+ import { expression as e } from "..";
5
+ import { Switch } from "../switch";
6
+ import { Text, Collection, Input } from "./helpers/asset-library";
7
+
8
+ describe("staticSwitch", () => {
9
+ test("works for basic cases", async () => {
10
+ const element = (
11
+ <Collection>
12
+ <Collection.Label>
13
+ <Switch>
14
+ <Switch.Case exp={e`foo() = bar()`}>
15
+ <Text>Text 1</Text>
16
+ </Switch.Case>
17
+ <Switch.Case>
18
+ <Text>Text 1</Text>
19
+ </Switch.Case>
20
+ </Switch>
21
+ </Collection.Label>
22
+ </Collection>
23
+ );
24
+
25
+ expect((await render(element)).jsonValue).toStrictEqual({
26
+ id: "root",
27
+ type: "collection",
28
+ label: {
29
+ staticSwitch: [
30
+ {
31
+ case: "foo() = bar()",
32
+ asset: {
33
+ id: "label-staticSwitch-0",
34
+ type: "text",
35
+ value: "Text 1",
36
+ },
37
+ },
38
+ {
39
+ case: true,
40
+ asset: {
41
+ id: "label-staticSwitch-1",
42
+ type: "text",
43
+ value: "Text 1",
44
+ },
45
+ },
46
+ ],
47
+ },
48
+ });
49
+ });
50
+
51
+ test("works for dynamic switch", async () => {
52
+ const element = (
53
+ <Collection>
54
+ <Collection.Label>
55
+ <Switch isDynamic>
56
+ <Switch.Case exp={e`foo() = bar()`}>
57
+ <Text>Text 1</Text>
58
+ </Switch.Case>
59
+ <Switch.Case>
60
+ <Input>
61
+ <Input.Label>
62
+ <Switch>
63
+ <Switch.Case exp={e`bar() == bar()`}>
64
+ <Text>Text 1</Text>
65
+ </Switch.Case>
66
+ </Switch>
67
+ </Input.Label>
68
+ </Input>
69
+ </Switch.Case>
70
+ </Switch>
71
+ </Collection.Label>
72
+ </Collection>
73
+ );
74
+
75
+ expect((await render(element)).jsonValue).toMatchInlineSnapshot(`
76
+ {
77
+ "id": "root",
78
+ "label": {
79
+ "dynamicSwitch": [
80
+ {
81
+ "asset": {
82
+ "id": "label-dynamicSwitch-0",
83
+ "type": "text",
84
+ "value": "Text 1",
85
+ },
86
+ "case": "foo() = bar()",
87
+ },
88
+ {
89
+ "asset": {
90
+ "id": "label-dynamicSwitch-1",
91
+ "label": {
92
+ "staticSwitch": [
93
+ {
94
+ "asset": {
95
+ "id": "label-dynamicSwitch-1-label-staticSwitch-0",
96
+ "type": "text",
97
+ "value": "Text 1",
98
+ },
99
+ "case": "bar() == bar()",
100
+ },
101
+ ],
102
+ },
103
+ "type": "input",
104
+ },
105
+ "case": true,
106
+ },
107
+ ],
108
+ },
109
+ "type": "collection",
110
+ }
111
+ `);
112
+ });
113
+
114
+ test("static switch with boolean exp", async () => {
115
+ const element = (
116
+ <Collection>
117
+ <Collection.Label>
118
+ <Switch>
119
+ <Switch.Case exp>
120
+ <Text>Text 1</Text>
121
+ </Switch.Case>
122
+ <Switch.Case exp={false}>
123
+ <Text>Text 1</Text>
124
+ </Switch.Case>
125
+ </Switch>
126
+ </Collection.Label>
127
+ </Collection>
128
+ );
129
+
130
+ expect((await render(element)).jsonValue).toStrictEqual({
131
+ id: "root",
132
+ type: "collection",
133
+ label: {
134
+ staticSwitch: [
135
+ {
136
+ case: true,
137
+ asset: {
138
+ id: "label-staticSwitch-0",
139
+ type: "text",
140
+ value: "Text 1",
141
+ },
142
+ },
143
+ {
144
+ case: false,
145
+ asset: {
146
+ id: "label-staticSwitch-1",
147
+ type: "text",
148
+ value: "Text 1",
149
+ },
150
+ },
151
+ ],
152
+ },
153
+ });
154
+ });
155
+
156
+ test("dynamic switch with boolean exp", async () => {
157
+ const element = (
158
+ <Collection>
159
+ <Collection.Label>
160
+ <Switch isDynamic>
161
+ <Switch.Case exp>
162
+ <Text>Text 1</Text>
163
+ </Switch.Case>
164
+ <Switch.Case exp={false}>
165
+ <Text>Text 1</Text>
166
+ </Switch.Case>
167
+ </Switch>
168
+ </Collection.Label>
169
+ </Collection>
170
+ );
171
+
172
+ expect((await render(element)).jsonValue).toStrictEqual({
173
+ id: "root",
174
+ type: "collection",
175
+ label: {
176
+ dynamicSwitch: [
177
+ {
178
+ case: true,
179
+ asset: {
180
+ id: "label-dynamicSwitch-0",
181
+ type: "text",
182
+ value: "Text 1",
183
+ },
184
+ },
185
+ {
186
+ case: false,
187
+ asset: {
188
+ id: "label-dynamicSwitch-1",
189
+ type: "text",
190
+ value: "Text 1",
191
+ },
192
+ },
193
+ ],
194
+ },
195
+ });
196
+ });
197
+ });
198
+
199
+ describe("generates ids", () => {
200
+ test("works for collection items", async () => {
201
+ const content = (
202
+ <Collection>
203
+ <Collection.Values>
204
+ <Switch>
205
+ <Switch.Case>
206
+ <Text>Test 1</Text>
207
+ </Switch.Case>
208
+ </Switch>
209
+ <Switch>
210
+ <Switch.Case>
211
+ <Text>Test 2</Text>
212
+ </Switch.Case>
213
+ </Switch>
214
+ </Collection.Values>
215
+ </Collection>
216
+ );
217
+
218
+ expect((await render(content)).jsonValue).toMatchInlineSnapshot(`
219
+ {
220
+ "id": "root",
221
+ "type": "collection",
222
+ "values": [
223
+ {
224
+ "staticSwitch": [
225
+ {
226
+ "asset": {
227
+ "id": "values-0-staticSwitch-0",
228
+ "type": "text",
229
+ "value": "Test 1",
230
+ },
231
+ "case": true,
232
+ },
233
+ ],
234
+ },
235
+ {
236
+ "staticSwitch": [
237
+ {
238
+ "asset": {
239
+ "id": "values-1-staticSwitch-0",
240
+ "type": "text",
241
+ "value": "Test 2",
242
+ },
243
+ "case": true,
244
+ },
245
+ ],
246
+ },
247
+ ],
248
+ }
249
+ `);
250
+ });
251
+ });