@webstudio-is/react-sdk 0.78.0 → 0.80.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.
- package/lib/cjs/context.js +8 -2
- package/lib/cjs/css/normalize.js +23 -43
- package/lib/cjs/css/presets.js +1 -111
- package/lib/cjs/embed-template.js +45 -16
- package/lib/cjs/expression.js +137 -22
- package/lib/cjs/index.js +6 -2
- package/lib/cjs/props.js +32 -2
- package/lib/cjs/tree/create-elements-tree.js +7 -2
- package/lib/cjs/tree/root.js +15 -7
- package/lib/context.js +8 -2
- package/lib/css/normalize.js +23 -33
- package/lib/css/presets.js +1 -111
- package/lib/embed-template.js +45 -16
- package/lib/expression.js +137 -22
- package/lib/index.js +13 -5
- package/lib/props.js +32 -2
- package/lib/tree/create-elements-tree.js +10 -3
- package/lib/tree/root.js +16 -8
- package/lib/types/components/component-meta.d.ts +30 -0
- package/lib/types/context.d.ts +5 -2
- package/lib/types/css/normalize.d.ts +0 -520
- package/lib/types/css/presets.d.ts +0 -282
- package/lib/types/embed-template.d.ts +38 -0
- package/lib/types/expression.d.ts +12 -4
- package/lib/types/index.d.ts +1 -1
- package/lib/types/props.d.ts +10 -0
- package/lib/types/tree/create-elements-tree.d.ts +6 -5
- package/lib/types/tree/root.d.ts +5 -5
- package/package.json +17 -16
- package/src/context.tsx +17 -4
- package/src/css/normalize.ts +23 -32
- package/src/css/presets.ts +0 -110
- package/src/embed-template.test.ts +84 -4
- package/src/embed-template.ts +51 -18
- package/src/expression.test.ts +106 -12
- package/src/expression.ts +157 -26
- package/src/index.ts +6 -2
- package/src/props.ts +33 -3
- package/src/tree/create-elements-tree.tsx +19 -10
- package/src/tree/root.ts +24 -13
package/src/css/normalize.ts
CHANGED
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
// webstudio custom opinionated presets
|
|
19
|
-
import
|
|
19
|
+
import { borders, outline } from "./presets";
|
|
20
20
|
import type { EmbedTemplateStyleDecl } from "../embed-template";
|
|
21
21
|
|
|
22
22
|
export type Styles = EmbedTemplateStyleDecl[];
|
|
@@ -37,21 +37,13 @@ const boxSizing = {
|
|
|
37
37
|
* box-sizing: border-box;
|
|
38
38
|
}
|
|
39
39
|
*/
|
|
40
|
-
const baseStyle = [
|
|
41
|
-
boxSizing,
|
|
42
|
-
...presets.borders,
|
|
43
|
-
...presets.outline,
|
|
44
|
-
] satisfies Styles;
|
|
40
|
+
const baseStyle = [boxSizing, ...borders, ...outline] satisfies Styles;
|
|
45
41
|
|
|
46
42
|
export const div = baseStyle;
|
|
47
43
|
export const address = baseStyle;
|
|
48
44
|
export const article = baseStyle;
|
|
49
45
|
export const aside = baseStyle;
|
|
50
|
-
export const
|
|
51
|
-
...baseStyle,
|
|
52
|
-
...presets.blockquote,
|
|
53
|
-
] satisfies Styles;
|
|
54
|
-
export const figure = [...baseStyle, ...presets.margins] satisfies Styles;
|
|
46
|
+
export const figure = baseStyle;
|
|
55
47
|
export const footer = baseStyle;
|
|
56
48
|
export const header = baseStyle;
|
|
57
49
|
export const main = baseStyle;
|
|
@@ -60,12 +52,12 @@ export const section = baseStyle;
|
|
|
60
52
|
export const form = baseStyle;
|
|
61
53
|
export const label = baseStyle;
|
|
62
54
|
|
|
63
|
-
export const h1 =
|
|
64
|
-
export const h2 =
|
|
65
|
-
export const h3 =
|
|
66
|
-
export const h4 =
|
|
67
|
-
export const h5 =
|
|
68
|
-
export const h6 =
|
|
55
|
+
export const h1 = baseStyle;
|
|
56
|
+
export const h2 = baseStyle;
|
|
57
|
+
export const h3 = baseStyle;
|
|
58
|
+
export const h4 = baseStyle;
|
|
59
|
+
export const h5 = baseStyle;
|
|
60
|
+
export const h6 = baseStyle;
|
|
69
61
|
|
|
70
62
|
export const i = baseStyle;
|
|
71
63
|
|
|
@@ -76,7 +68,7 @@ export const li = baseStyle;
|
|
|
76
68
|
export const ul = baseStyle;
|
|
77
69
|
export const ol = baseStyle;
|
|
78
70
|
|
|
79
|
-
export const p =
|
|
71
|
+
export const p = baseStyle;
|
|
80
72
|
export const span = baseStyle;
|
|
81
73
|
|
|
82
74
|
// @todo for now not applied to html, as we don't have html element
|
|
@@ -102,7 +94,7 @@ export const html = [
|
|
|
102
94
|
value: { type: "unit", value: 4, unit: "number" },
|
|
103
95
|
},
|
|
104
96
|
boxSizing,
|
|
105
|
-
...
|
|
97
|
+
...borders,
|
|
106
98
|
] satisfies Styles;
|
|
107
99
|
|
|
108
100
|
/**
|
|
@@ -132,7 +124,7 @@ export const body = [
|
|
|
132
124
|
property: "fontFamily",
|
|
133
125
|
value: {
|
|
134
126
|
type: "keyword",
|
|
135
|
-
value: "Arial, sans-serif",
|
|
127
|
+
value: "Arial, Roboto, sans-serif",
|
|
136
128
|
},
|
|
137
129
|
},
|
|
138
130
|
{
|
|
@@ -144,7 +136,7 @@ export const body = [
|
|
|
144
136
|
value: { type: "unit", unit: "number", value: 1.2 },
|
|
145
137
|
},
|
|
146
138
|
boxSizing,
|
|
147
|
-
...
|
|
139
|
+
...borders,
|
|
148
140
|
] satisfies Styles;
|
|
149
141
|
|
|
150
142
|
/**
|
|
@@ -163,8 +155,7 @@ export const hr = [
|
|
|
163
155
|
value: { type: "keyword", value: "inherit" },
|
|
164
156
|
},
|
|
165
157
|
boxSizing,
|
|
166
|
-
...
|
|
167
|
-
...presets.margins,
|
|
158
|
+
...borders,
|
|
168
159
|
] satisfies Styles;
|
|
169
160
|
|
|
170
161
|
/**
|
|
@@ -186,7 +177,7 @@ export const b = [
|
|
|
186
177
|
value: { type: "keyword", value: "700" },
|
|
187
178
|
},
|
|
188
179
|
boxSizing,
|
|
189
|
-
...
|
|
180
|
+
...borders,
|
|
190
181
|
] satisfies Styles;
|
|
191
182
|
export const strong = b;
|
|
192
183
|
|
|
@@ -209,7 +200,7 @@ export const code = [
|
|
|
209
200
|
value: { type: "unit", value: 1, unit: "em" },
|
|
210
201
|
},
|
|
211
202
|
boxSizing,
|
|
212
|
-
...
|
|
203
|
+
...borders,
|
|
213
204
|
] satisfies Styles;
|
|
214
205
|
|
|
215
206
|
export const kbd = code;
|
|
@@ -226,7 +217,7 @@ export const small = [
|
|
|
226
217
|
value: { type: "unit", value: 80, unit: "%" },
|
|
227
218
|
},
|
|
228
219
|
boxSizing,
|
|
229
|
-
...
|
|
220
|
+
...borders,
|
|
230
221
|
] satisfies Styles;
|
|
231
222
|
|
|
232
223
|
/**
|
|
@@ -251,7 +242,7 @@ const subSupBase = [
|
|
|
251
242
|
value: { type: "keyword", value: "baseline" },
|
|
252
243
|
},
|
|
253
244
|
boxSizing,
|
|
254
|
-
...
|
|
245
|
+
...borders,
|
|
255
246
|
] satisfies Styles;
|
|
256
247
|
|
|
257
248
|
export const sub = [
|
|
@@ -286,7 +277,7 @@ export const table = [
|
|
|
286
277
|
property: "textIndent",
|
|
287
278
|
value: { type: "unit", value: 0, unit: "number" },
|
|
288
279
|
},
|
|
289
|
-
...
|
|
280
|
+
...borders,
|
|
290
281
|
/* 2 */
|
|
291
282
|
{
|
|
292
283
|
property: "borderTopColor",
|
|
@@ -349,7 +340,7 @@ const buttonBase = [
|
|
|
349
340
|
value: { type: "unit", value: 0, unit: "number" },
|
|
350
341
|
},
|
|
351
342
|
boxSizing,
|
|
352
|
-
...
|
|
343
|
+
...borders,
|
|
353
344
|
] satisfies Styles;
|
|
354
345
|
|
|
355
346
|
export const input = buttonBase;
|
|
@@ -436,7 +427,7 @@ export const legend = [
|
|
|
436
427
|
value: { type: "unit", value: 0, unit: "number" },
|
|
437
428
|
},
|
|
438
429
|
boxSizing,
|
|
439
|
-
...
|
|
430
|
+
...borders,
|
|
440
431
|
] satisfies Styles;
|
|
441
432
|
|
|
442
433
|
/**
|
|
@@ -449,7 +440,7 @@ export const progress = [
|
|
|
449
440
|
value: { type: "keyword", value: "baseline" },
|
|
450
441
|
},
|
|
451
442
|
boxSizing,
|
|
452
|
-
...
|
|
443
|
+
...borders,
|
|
453
444
|
] satisfies Styles;
|
|
454
445
|
|
|
455
446
|
/**
|
|
@@ -512,5 +503,5 @@ export const summary = [
|
|
|
512
503
|
value: { type: "keyword", value: "list-item" },
|
|
513
504
|
},
|
|
514
505
|
boxSizing,
|
|
515
|
-
...
|
|
506
|
+
...borders,
|
|
516
507
|
] satisfies Styles;
|
package/src/css/presets.ts
CHANGED
|
@@ -25,113 +25,3 @@ export const outline: Styles = [
|
|
|
25
25
|
value: { type: "unit", value: 1, unit: "px" },
|
|
26
26
|
},
|
|
27
27
|
];
|
|
28
|
-
|
|
29
|
-
export const margins = [
|
|
30
|
-
{
|
|
31
|
-
property: "marginTop",
|
|
32
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
33
|
-
},
|
|
34
|
-
{
|
|
35
|
-
property: "marginRight",
|
|
36
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
37
|
-
},
|
|
38
|
-
{
|
|
39
|
-
property: "marginBottom",
|
|
40
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
41
|
-
},
|
|
42
|
-
{
|
|
43
|
-
property: "marginLeft",
|
|
44
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
45
|
-
},
|
|
46
|
-
] satisfies Styles;
|
|
47
|
-
|
|
48
|
-
export const verticalMargins = [
|
|
49
|
-
{
|
|
50
|
-
property: "marginTop",
|
|
51
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
52
|
-
},
|
|
53
|
-
{
|
|
54
|
-
property: "marginBottom",
|
|
55
|
-
value: { type: "unit", value: 0, unit: "px" },
|
|
56
|
-
},
|
|
57
|
-
] satisfies Styles;
|
|
58
|
-
|
|
59
|
-
export const blockquote = [
|
|
60
|
-
...margins,
|
|
61
|
-
{
|
|
62
|
-
property: "paddingTop",
|
|
63
|
-
value: { type: "unit", value: 10, unit: "px" },
|
|
64
|
-
},
|
|
65
|
-
{
|
|
66
|
-
property: "paddingBottom",
|
|
67
|
-
value: { type: "unit", value: 10, unit: "px" },
|
|
68
|
-
},
|
|
69
|
-
{
|
|
70
|
-
property: "paddingLeft",
|
|
71
|
-
value: { type: "unit", value: 20, unit: "px" },
|
|
72
|
-
},
|
|
73
|
-
{
|
|
74
|
-
property: "paddingRight",
|
|
75
|
-
value: { type: "unit", value: 20, unit: "px" },
|
|
76
|
-
},
|
|
77
|
-
{
|
|
78
|
-
property: "borderLeftWidth",
|
|
79
|
-
value: { type: "unit", value: 5, unit: "px" },
|
|
80
|
-
},
|
|
81
|
-
{
|
|
82
|
-
property: "borderLeftStyle",
|
|
83
|
-
value: { type: "keyword", value: "solid" },
|
|
84
|
-
},
|
|
85
|
-
{
|
|
86
|
-
property: "borderLeftColor",
|
|
87
|
-
value: { type: "rgb", r: 226, g: 226, b: 226, alpha: 1 },
|
|
88
|
-
},
|
|
89
|
-
] satisfies Styles;
|
|
90
|
-
|
|
91
|
-
export const h1 = [
|
|
92
|
-
...verticalMargins,
|
|
93
|
-
{
|
|
94
|
-
property: "fontSize",
|
|
95
|
-
value: { type: "unit", value: 38, unit: "px" },
|
|
96
|
-
},
|
|
97
|
-
] satisfies Styles;
|
|
98
|
-
|
|
99
|
-
export const h2 = [
|
|
100
|
-
...verticalMargins,
|
|
101
|
-
{
|
|
102
|
-
property: "fontSize",
|
|
103
|
-
value: { type: "unit", value: 32, unit: "px" },
|
|
104
|
-
},
|
|
105
|
-
] satisfies Styles;
|
|
106
|
-
|
|
107
|
-
export const h3 = [
|
|
108
|
-
...verticalMargins,
|
|
109
|
-
{
|
|
110
|
-
property: "fontSize",
|
|
111
|
-
value: { type: "unit", value: 24, unit: "px" },
|
|
112
|
-
},
|
|
113
|
-
] satisfies Styles;
|
|
114
|
-
|
|
115
|
-
export const h4 = [
|
|
116
|
-
...verticalMargins,
|
|
117
|
-
{
|
|
118
|
-
property: "fontSize",
|
|
119
|
-
value: { type: "unit", value: 18, unit: "px" },
|
|
120
|
-
},
|
|
121
|
-
] satisfies Styles;
|
|
122
|
-
|
|
123
|
-
export const h5 = [
|
|
124
|
-
...verticalMargins,
|
|
125
|
-
{
|
|
126
|
-
property: "fontSize",
|
|
127
|
-
value: { type: "unit", value: 14, unit: "px" },
|
|
128
|
-
},
|
|
129
|
-
] satisfies Styles;
|
|
130
|
-
|
|
131
|
-
export const h6 = [
|
|
132
|
-
...verticalMargins,
|
|
133
|
-
{
|
|
134
|
-
property: "fontSize",
|
|
135
|
-
value: { type: "unit", value: 12, unit: "px" },
|
|
136
|
-
},
|
|
137
|
-
] satisfies Styles;
|
|
@@ -307,10 +307,7 @@ test("generate data for embedding from props bound to data source expressions",
|
|
|
307
307
|
type: "string",
|
|
308
308
|
name: "state",
|
|
309
309
|
value: "initial",
|
|
310
|
-
dataSourceRef: {
|
|
311
|
-
type: "variable",
|
|
312
|
-
name: "boxState",
|
|
313
|
-
},
|
|
310
|
+
dataSourceRef: { type: "variable", name: "boxState" },
|
|
314
311
|
},
|
|
315
312
|
],
|
|
316
313
|
children: [],
|
|
@@ -384,3 +381,86 @@ test("generate data for embedding from props bound to data source expressions",
|
|
|
384
381
|
styles: [],
|
|
385
382
|
});
|
|
386
383
|
});
|
|
384
|
+
|
|
385
|
+
test("generate data for embedding from action props", () => {
|
|
386
|
+
expect(
|
|
387
|
+
generateDataFromEmbedTemplate(
|
|
388
|
+
[
|
|
389
|
+
{
|
|
390
|
+
type: "instance",
|
|
391
|
+
component: "Box1",
|
|
392
|
+
props: [
|
|
393
|
+
{
|
|
394
|
+
type: "string",
|
|
395
|
+
name: "state",
|
|
396
|
+
value: "initial",
|
|
397
|
+
dataSourceRef: { type: "variable", name: "boxState" },
|
|
398
|
+
},
|
|
399
|
+
],
|
|
400
|
+
children: [
|
|
401
|
+
{
|
|
402
|
+
type: "instance",
|
|
403
|
+
component: "Box2",
|
|
404
|
+
props: [
|
|
405
|
+
{
|
|
406
|
+
type: "action",
|
|
407
|
+
name: "onClick",
|
|
408
|
+
value: [{ type: "execute", code: `boxState = 'success'` }],
|
|
409
|
+
},
|
|
410
|
+
],
|
|
411
|
+
children: [],
|
|
412
|
+
},
|
|
413
|
+
],
|
|
414
|
+
},
|
|
415
|
+
],
|
|
416
|
+
defaultBreakpointId
|
|
417
|
+
)
|
|
418
|
+
).toEqual({
|
|
419
|
+
children: [{ type: "id", value: expectString }],
|
|
420
|
+
instances: [
|
|
421
|
+
{
|
|
422
|
+
type: "instance",
|
|
423
|
+
id: expectString,
|
|
424
|
+
component: "Box1",
|
|
425
|
+
children: [{ type: "id", value: expectString }],
|
|
426
|
+
},
|
|
427
|
+
{ type: "instance", id: expectString, component: "Box2", children: [] },
|
|
428
|
+
],
|
|
429
|
+
props: [
|
|
430
|
+
{
|
|
431
|
+
id: expectString,
|
|
432
|
+
instanceId: expectString,
|
|
433
|
+
type: "dataSource",
|
|
434
|
+
name: "state",
|
|
435
|
+
value: expectString,
|
|
436
|
+
},
|
|
437
|
+
{
|
|
438
|
+
id: expectString,
|
|
439
|
+
instanceId: expectString,
|
|
440
|
+
type: "action",
|
|
441
|
+
name: "onClick",
|
|
442
|
+
value: [
|
|
443
|
+
{
|
|
444
|
+
type: "execute",
|
|
445
|
+
code: expect.stringMatching(/\$ws\$dataSource\$\w+ = 'success'/),
|
|
446
|
+
},
|
|
447
|
+
],
|
|
448
|
+
},
|
|
449
|
+
],
|
|
450
|
+
dataSources: [
|
|
451
|
+
{
|
|
452
|
+
type: "variable",
|
|
453
|
+
id: expectString,
|
|
454
|
+
scopeInstanceId: expectString,
|
|
455
|
+
name: "boxState",
|
|
456
|
+
value: {
|
|
457
|
+
type: "string",
|
|
458
|
+
value: "initial",
|
|
459
|
+
},
|
|
460
|
+
},
|
|
461
|
+
],
|
|
462
|
+
styleSourceSelections: [],
|
|
463
|
+
styleSources: [],
|
|
464
|
+
styles: [],
|
|
465
|
+
});
|
|
466
|
+
});
|
package/src/embed-template.ts
CHANGED
|
@@ -21,11 +21,13 @@ const EmbedTemplateText = z.object({
|
|
|
21
21
|
|
|
22
22
|
type EmbedTemplateText = z.infer<typeof EmbedTemplateText>;
|
|
23
23
|
|
|
24
|
+
const DataSourceVariableRef = z.object({
|
|
25
|
+
type: z.literal("variable"),
|
|
26
|
+
name: z.string(),
|
|
27
|
+
});
|
|
28
|
+
|
|
24
29
|
const DataSourceRef = z.union([
|
|
25
|
-
|
|
26
|
-
type: z.literal("variable"),
|
|
27
|
-
name: z.string(),
|
|
28
|
-
}),
|
|
30
|
+
DataSourceVariableRef,
|
|
29
31
|
z.object({
|
|
30
32
|
type: z.literal("expression"),
|
|
31
33
|
name: z.string(),
|
|
@@ -58,6 +60,16 @@ const EmbedTemplateProp = z.union([
|
|
|
58
60
|
dataSourceRef: z.optional(DataSourceRef),
|
|
59
61
|
value: z.array(z.string()),
|
|
60
62
|
}),
|
|
63
|
+
z.object({
|
|
64
|
+
type: z.literal("action"),
|
|
65
|
+
name: z.string(),
|
|
66
|
+
value: z.array(
|
|
67
|
+
z.object({
|
|
68
|
+
type: z.literal("execute"),
|
|
69
|
+
code: z.string(),
|
|
70
|
+
})
|
|
71
|
+
),
|
|
72
|
+
}),
|
|
61
73
|
]);
|
|
62
74
|
|
|
63
75
|
type EmbedTemplateProp = z.infer<typeof EmbedTemplateProp>;
|
|
@@ -124,6 +136,29 @@ const createInstancesFromTemplate = (
|
|
|
124
136
|
if (item.props) {
|
|
125
137
|
for (const prop of item.props) {
|
|
126
138
|
const propId = nanoid();
|
|
139
|
+
// action cannot be bound to data source
|
|
140
|
+
if (prop.type === "action") {
|
|
141
|
+
props.push({
|
|
142
|
+
id: propId,
|
|
143
|
+
instanceId,
|
|
144
|
+
type: "action",
|
|
145
|
+
name: prop.name,
|
|
146
|
+
value: prop.value.map((value) => {
|
|
147
|
+
return {
|
|
148
|
+
type: "execute",
|
|
149
|
+
// replace all references with variable names
|
|
150
|
+
code: validateExpression(value.code, {
|
|
151
|
+
effectful: true,
|
|
152
|
+
transformIdentifier: (ref) => {
|
|
153
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
154
|
+
return encodeDataSourceVariable(id);
|
|
155
|
+
},
|
|
156
|
+
}),
|
|
157
|
+
};
|
|
158
|
+
}),
|
|
159
|
+
});
|
|
160
|
+
continue;
|
|
161
|
+
}
|
|
127
162
|
if (prop.dataSourceRef === undefined) {
|
|
128
163
|
props.push({ id: propId, instanceId, ...prop });
|
|
129
164
|
continue;
|
|
@@ -148,7 +183,13 @@ const createInstancesFromTemplate = (
|
|
|
148
183
|
id,
|
|
149
184
|
scopeInstanceId: instanceId,
|
|
150
185
|
name: dataSourceRef.name,
|
|
151
|
-
|
|
186
|
+
// replace all references with variable names
|
|
187
|
+
code: validateExpression(dataSourceRef.code, {
|
|
188
|
+
transformIdentifier: (ref) => {
|
|
189
|
+
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
190
|
+
return encodeDataSourceVariable(id);
|
|
191
|
+
},
|
|
192
|
+
}),
|
|
152
193
|
};
|
|
153
194
|
dataSourceByRef.set(dataSourceRef.name, dataSource);
|
|
154
195
|
} else {
|
|
@@ -246,25 +287,17 @@ export const generateDataFromEmbedTemplate = (
|
|
|
246
287
|
defaultBreakpointId
|
|
247
288
|
);
|
|
248
289
|
|
|
249
|
-
// replace all references with variable names
|
|
250
|
-
const dataSources: DataSource[] = [];
|
|
251
|
-
for (const dataSource of dataSourceByRef.values()) {
|
|
252
|
-
if (dataSource.type === "expression") {
|
|
253
|
-
dataSource.code = validateExpression(dataSource.code, (ref) => {
|
|
254
|
-
const id = dataSourceByRef.get(ref)?.id ?? ref;
|
|
255
|
-
return encodeDataSourceVariable(id);
|
|
256
|
-
});
|
|
257
|
-
}
|
|
258
|
-
dataSources.push(dataSource);
|
|
259
|
-
}
|
|
260
|
-
|
|
261
290
|
return {
|
|
262
291
|
children,
|
|
263
292
|
instances,
|
|
264
293
|
props,
|
|
265
|
-
dataSources,
|
|
294
|
+
dataSources: Array.from(dataSourceByRef.values()),
|
|
266
295
|
styleSourceSelections,
|
|
267
296
|
styleSources,
|
|
268
297
|
styles,
|
|
269
298
|
};
|
|
270
299
|
};
|
|
300
|
+
|
|
301
|
+
export type EmbedTemplateData = ReturnType<
|
|
302
|
+
typeof generateDataFromEmbedTemplate
|
|
303
|
+
>;
|
package/src/expression.test.ts
CHANGED
|
@@ -2,8 +2,10 @@ import { expect, test } from "@jest/globals";
|
|
|
2
2
|
import {
|
|
3
3
|
decodeDataSourceVariable,
|
|
4
4
|
encodeDataSourceVariable,
|
|
5
|
-
|
|
6
|
-
|
|
5
|
+
executeComputingExpressions,
|
|
6
|
+
executeEffectfulExpression,
|
|
7
|
+
generateComputingExpressions,
|
|
8
|
+
generateEffectfulExpression,
|
|
7
9
|
validateExpression,
|
|
8
10
|
} from "./expression";
|
|
9
11
|
|
|
@@ -17,6 +19,13 @@ test("allow unary and binary expressions", () => {
|
|
|
17
19
|
expect(validateExpression(`[-1, 1 + 1]`)).toEqual(`[-1, 1 + 1]`);
|
|
18
20
|
});
|
|
19
21
|
|
|
22
|
+
test("optionally allow assignment expressions", () => {
|
|
23
|
+
expect(() => {
|
|
24
|
+
validateExpression(`a = 2`);
|
|
25
|
+
}).toThrowError(/Cannot use assignment in this expression/);
|
|
26
|
+
expect(validateExpression(`a = 2`, { effectful: true })).toEqual(`a = 2`);
|
|
27
|
+
});
|
|
28
|
+
|
|
20
29
|
test("forbid member expressions", () => {
|
|
21
30
|
expect(() => {
|
|
22
31
|
validateExpression("var1 + obj.param");
|
|
@@ -44,6 +53,21 @@ test("forbid ternary", () => {
|
|
|
44
53
|
}).toThrowError(/Ternary operator is not supported/);
|
|
45
54
|
});
|
|
46
55
|
|
|
56
|
+
test("forbid increment and decrement", () => {
|
|
57
|
+
expect(() => {
|
|
58
|
+
validateExpression("++var1");
|
|
59
|
+
}).toThrowError(/"\+\+" operator is not supported/);
|
|
60
|
+
expect(() => {
|
|
61
|
+
validateExpression("var1++");
|
|
62
|
+
}).toThrowError(/"\+\+" operator is not supported/);
|
|
63
|
+
expect(() => {
|
|
64
|
+
validateExpression("--var1");
|
|
65
|
+
}).toThrowError(/"--" operator is not supported/);
|
|
66
|
+
expect(() => {
|
|
67
|
+
validateExpression("var1--");
|
|
68
|
+
}).toThrowError(/"--" operator is not supported/);
|
|
69
|
+
});
|
|
70
|
+
|
|
47
71
|
test("forbid multiple expressions", () => {
|
|
48
72
|
expect(() => {
|
|
49
73
|
validateExpression("a b");
|
|
@@ -57,12 +81,14 @@ test("forbid multiple expressions", () => {
|
|
|
57
81
|
});
|
|
58
82
|
|
|
59
83
|
test("transform identifiers", () => {
|
|
60
|
-
expect(
|
|
61
|
-
|
|
62
|
-
|
|
84
|
+
expect(
|
|
85
|
+
validateExpression(`a + b`, {
|
|
86
|
+
transformIdentifier: (id) => `$ws$${id}`,
|
|
87
|
+
})
|
|
88
|
+
).toEqual(`$ws$a + $ws$b`);
|
|
63
89
|
});
|
|
64
90
|
|
|
65
|
-
test("generate expressions
|
|
91
|
+
test("generate computing expressions", () => {
|
|
66
92
|
const variables = new Set(["var0"]);
|
|
67
93
|
const expressions = new Map([
|
|
68
94
|
["exp3", "exp2 + exp1"],
|
|
@@ -70,7 +96,7 @@ test("generate expressions computation", () => {
|
|
|
70
96
|
["exp2", "exp1"],
|
|
71
97
|
["exp4", "exp2"],
|
|
72
98
|
]);
|
|
73
|
-
expect(
|
|
99
|
+
expect(generateComputingExpressions(expressions, variables))
|
|
74
100
|
.toMatchInlineSnapshot(`
|
|
75
101
|
"const var0 = _variables.get('var0');
|
|
76
102
|
const exp1 = (var0);
|
|
@@ -86,10 +112,22 @@ test("generate expressions computation", () => {
|
|
|
86
112
|
`);
|
|
87
113
|
});
|
|
88
114
|
|
|
115
|
+
test("add only used variables in computing expression", () => {
|
|
116
|
+
const expressions = new Map([["exp1", "var0"]]);
|
|
117
|
+
expect(generateComputingExpressions(expressions, new Set(["var0", "var1"])))
|
|
118
|
+
.toMatchInlineSnapshot(`
|
|
119
|
+
"const var0 = _variables.get('var0');
|
|
120
|
+
const exp1 = (var0);
|
|
121
|
+
return new Map([
|
|
122
|
+
['exp1', exp1],
|
|
123
|
+
]);"
|
|
124
|
+
`);
|
|
125
|
+
});
|
|
126
|
+
|
|
89
127
|
test("execute expression", () => {
|
|
90
128
|
const variables = new Map();
|
|
91
129
|
const expressions = new Map([["exp1", "1 + 1"]]);
|
|
92
|
-
expect(
|
|
130
|
+
expect(executeComputingExpressions(expressions, variables)).toEqual(
|
|
93
131
|
new Map([["exp1", 2]])
|
|
94
132
|
);
|
|
95
133
|
});
|
|
@@ -97,7 +135,7 @@ test("execute expression", () => {
|
|
|
97
135
|
test("execute expression dependent on variables", () => {
|
|
98
136
|
const variables = new Map([["var1", 5]]);
|
|
99
137
|
const expressions = new Map([["exp1", "var1 + 1"]]);
|
|
100
|
-
expect(
|
|
138
|
+
expect(executeComputingExpressions(expressions, variables)).toEqual(
|
|
101
139
|
new Map([["exp1", 6]])
|
|
102
140
|
);
|
|
103
141
|
});
|
|
@@ -108,7 +146,7 @@ test("execute expression dependent on another expressions", () => {
|
|
|
108
146
|
["exp1", "exp0 + 1"],
|
|
109
147
|
["exp0", "var1 + 2"],
|
|
110
148
|
]);
|
|
111
|
-
expect(
|
|
149
|
+
expect(executeComputingExpressions(expressions, variables)).toEqual(
|
|
112
150
|
new Map([
|
|
113
151
|
["exp1", 6],
|
|
114
152
|
["exp0", 5],
|
|
@@ -124,7 +162,7 @@ test("forbid circular expressions", () => {
|
|
|
124
162
|
["exp2", "exp1 + 3"],
|
|
125
163
|
]);
|
|
126
164
|
expect(() => {
|
|
127
|
-
|
|
165
|
+
executeComputingExpressions(expressions, variables);
|
|
128
166
|
}).toThrowError(/Cannot access 'exp0' before initialization/);
|
|
129
167
|
});
|
|
130
168
|
|
|
@@ -132,7 +170,7 @@ test("make sure dependency exists", () => {
|
|
|
132
170
|
const variables = new Map();
|
|
133
171
|
const expressions = new Map([["exp1", "var1 + 1"]]);
|
|
134
172
|
expect(() => {
|
|
135
|
-
|
|
173
|
+
executeComputingExpressions(expressions, variables);
|
|
136
174
|
}).toThrowError(/Unknown dependency "var1"/);
|
|
137
175
|
});
|
|
138
176
|
|
|
@@ -145,3 +183,59 @@ test("encode/decode variable names", () => {
|
|
|
145
183
|
);
|
|
146
184
|
expect(decodeDataSourceVariable("myVarName")).toEqual(undefined);
|
|
147
185
|
});
|
|
186
|
+
|
|
187
|
+
test("generate effectful expression", () => {
|
|
188
|
+
expect(
|
|
189
|
+
generateEffectfulExpression(`var0 = var0 + var1`, new Set(["var0", "var1"]))
|
|
190
|
+
).toMatchInlineSnapshot(`
|
|
191
|
+
"let var0 = _variables.get('var0');
|
|
192
|
+
let var1 = _variables.get('var1');
|
|
193
|
+
var0 = var0 + var1;
|
|
194
|
+
return new Map([
|
|
195
|
+
['var0', var0],
|
|
196
|
+
]);"
|
|
197
|
+
`);
|
|
198
|
+
|
|
199
|
+
expect(
|
|
200
|
+
generateEffectfulExpression(`var0 = var1 + 1`, new Set(["var0", "var1"]))
|
|
201
|
+
).toMatchInlineSnapshot(`
|
|
202
|
+
"let var1 = _variables.get('var1');
|
|
203
|
+
let var0;
|
|
204
|
+
var0 = var1 + 1;
|
|
205
|
+
return new Map([
|
|
206
|
+
['var0', var0],
|
|
207
|
+
]);"
|
|
208
|
+
`);
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
test("add only used variables in effectful expression", () => {
|
|
212
|
+
expect(
|
|
213
|
+
generateEffectfulExpression(
|
|
214
|
+
`var0 = var1 + 1`,
|
|
215
|
+
new Set(["var0", "var1", "var2"])
|
|
216
|
+
)
|
|
217
|
+
).toMatchInlineSnapshot(`
|
|
218
|
+
"let var1 = _variables.get('var1');
|
|
219
|
+
let var0;
|
|
220
|
+
var0 = var1 + 1;
|
|
221
|
+
return new Map([
|
|
222
|
+
['var0', var0],
|
|
223
|
+
]);"
|
|
224
|
+
`);
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
test("forbid not allowed variables in effectful expression", () => {
|
|
228
|
+
expect(() => {
|
|
229
|
+
generateEffectfulExpression(`var0 = var0 + var1`, new Set(["var0"]));
|
|
230
|
+
}).toThrowError(/Unknown dependency "var1"/);
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
test("execute effectful expression", () => {
|
|
234
|
+
const variables = new Map([
|
|
235
|
+
["var0", 2],
|
|
236
|
+
["var1", 3],
|
|
237
|
+
]);
|
|
238
|
+
expect(executeEffectfulExpression(`var0 = var0 + var1`, variables)).toEqual(
|
|
239
|
+
new Map([["var0", 5]])
|
|
240
|
+
);
|
|
241
|
+
});
|