@yaoxiu/marketing-dsl 1.3.0 → 1.4.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/dist/index.js CHANGED
@@ -1,308 +1,5 @@
1
- // src/expression.ts
2
- var KEYWORD_LITERALS = {
3
- true: true,
4
- false: false,
5
- null: null,
6
- undefined: void 0
7
- };
8
- var PUNCTUATORS = [
9
- "===",
10
- "!==",
11
- "<=",
12
- ">=",
13
- "==",
14
- "!=",
15
- "&&",
16
- "||",
17
- "(",
18
- ")",
19
- "[",
20
- "]",
21
- ".",
22
- "?",
23
- ":",
24
- "<",
25
- ">",
26
- "!",
27
- "+",
28
- "-",
29
- "*",
30
- "/",
31
- "%"
32
- ];
33
- function tokenize(input) {
34
- const tokens = [];
35
- let i = 0;
36
- while (i < input.length) {
37
- const ch = input[i];
38
- if (/\s/.test(ch)) {
39
- i++;
40
- continue;
41
- }
42
- if (ch === '"' || ch === "'") {
43
- const quote = ch;
44
- let value = "";
45
- i++;
46
- while (i < input.length && input[i] !== quote) {
47
- if (input[i] === "\\") {
48
- value += input[i + 1] || "";
49
- i += 2;
50
- } else {
51
- value += input[i];
52
- i++;
53
- }
54
- }
55
- if (i >= input.length) throw new Error("\u5B57\u7B26\u4E32\u6CA1\u6709\u95ED\u5408");
56
- i++;
57
- tokens.push({ type: "string", value });
58
- continue;
59
- }
60
- if (/[0-9]/.test(ch) || ch === "." && /[0-9]/.test(input[i + 1] || "")) {
61
- let raw = "";
62
- while (i < input.length && /[0-9.]/.test(input[i])) {
63
- raw += input[i];
64
- i++;
65
- }
66
- tokens.push({ type: "number", value: Number(raw) });
67
- continue;
68
- }
69
- if (/[A-Za-z_$]/.test(ch)) {
70
- let name = "";
71
- while (i < input.length && /[A-Za-z0-9_$]/.test(input[i])) {
72
- name += input[i];
73
- i++;
74
- }
75
- tokens.push({ type: "ident", value: name });
76
- continue;
77
- }
78
- const punctuator = PUNCTUATORS.find((p) => input.startsWith(p, i));
79
- if (!punctuator) throw new Error(`\u65E0\u6CD5\u8BC6\u522B\u7684\u5B57\u7B26 "${ch}"`);
80
- tokens.push({ type: "punc", value: punctuator });
81
- i += punctuator.length;
82
- }
83
- return tokens;
84
- }
85
- function createParser(tokens) {
86
- let pos = 0;
87
- const peek = () => tokens[pos];
88
- const isPunc = (v) => {
89
- const token = peek();
90
- return !!token && token.type === "punc" && token.value === v;
91
- };
92
- const eat = (v) => {
93
- if (!isPunc(v)) throw new Error(`\u7F3A\u5C11 "${v}"`);
94
- pos++;
95
- };
96
- const binaryLevels = [
97
- ["||"],
98
- ["&&"],
99
- ["===", "!==", "==", "!="],
100
- ["<", ">", "<=", ">="],
101
- ["+", "-"],
102
- ["*", "/", "%"]
103
- ];
104
- function parseExpression() {
105
- return parseTernary();
106
- }
107
- function parseTernary() {
108
- const test = parseBinary(0);
109
- if (!isPunc("?")) return test;
110
- eat("?");
111
- const consequent = parseTernary();
112
- eat(":");
113
- const alternate = parseTernary();
114
- return { kind: "ternary", test, consequent, alternate };
115
- }
116
- function parseBinary(level) {
117
- if (level >= binaryLevels.length) return parseUnary();
118
- let left = parseBinary(level + 1);
119
- for (; ; ) {
120
- const token = peek();
121
- if (!token || token.type !== "punc") break;
122
- if (binaryLevels[level].indexOf(String(token.value)) === -1) break;
123
- const operator = String(token.value);
124
- pos++;
125
- const right = parseBinary(level + 1);
126
- left = { kind: "binary", operator, left, right };
127
- }
128
- return left;
129
- }
130
- function parseUnary() {
131
- if (isPunc("!") || isPunc("-")) {
132
- const operator = String(peek().value);
133
- pos++;
134
- return { kind: "unary", operator, argument: parseUnary() };
135
- }
136
- return parseMember();
137
- }
138
- function parseMember() {
139
- let object = parsePrimary();
140
- for (; ; ) {
141
- if (isPunc(".")) {
142
- eat(".");
143
- const token = peek();
144
- if (!token || token.type !== "ident") throw new Error('"." \u540E\u9762\u9700\u8981\u5C5E\u6027\u540D');
145
- pos++;
146
- object = {
147
- kind: "member",
148
- object,
149
- property: { kind: "literal", value: token.value }
150
- };
151
- } else if (isPunc("[")) {
152
- eat("[");
153
- const property = parseExpression();
154
- eat("]");
155
- object = { kind: "member", object, property };
156
- } else {
157
- return object;
158
- }
159
- }
160
- }
161
- function parsePrimary() {
162
- const token = peek();
163
- if (!token) throw new Error("\u8868\u8FBE\u5F0F\u4E0D\u5B8C\u6574");
164
- if (isPunc("(")) {
165
- eat("(");
166
- const node = parseExpression();
167
- eat(")");
168
- return node;
169
- }
170
- if (token.type === "number" || token.type === "string") {
171
- pos++;
172
- return { kind: "literal", value: token.value };
173
- }
174
- if (token.type === "ident") {
175
- pos++;
176
- const name = String(token.value);
177
- if (Object.prototype.hasOwnProperty.call(KEYWORD_LITERALS, name)) {
178
- return { kind: "literal", value: KEYWORD_LITERALS[name] };
179
- }
180
- return { kind: "identifier", name };
181
- }
182
- throw new Error(`\u610F\u5916\u7684\u7B26\u53F7 "${token.value}"`);
183
- }
184
- const ast = parseExpression();
185
- if (pos < tokens.length) throw new Error(`\u8868\u8FBE\u5F0F\u7ED3\u5C3E\u6709\u591A\u4F59\u5185\u5BB9 "${tokens[pos].value}"`);
186
- return ast;
187
- }
188
- var astCache = /* @__PURE__ */ new Map();
189
- function parse(source) {
190
- const cached = astCache.get(source);
191
- if (cached) return cached;
192
- const ast = createParser(tokenize(source));
193
- astCache.set(source, ast);
194
- return ast;
195
- }
196
- var BLOCKED_KEYS = ["__proto__", "constructor", "prototype"];
197
- function readProperty(object, key) {
198
- if (object === null || object === void 0) return void 0;
199
- if (BLOCKED_KEYS.indexOf(String(key)) > -1) return void 0;
200
- const value = object[String(key)];
201
- return typeof value === "function" ? void 0 : value;
202
- }
203
- function evaluateNode(node, context) {
204
- switch (node.kind) {
205
- case "literal":
206
- return node.value;
207
- case "identifier":
208
- return readProperty(context, node.name);
209
- case "member":
210
- return readProperty(
211
- evaluateNode(node.object, context),
212
- evaluateNode(node.property, context)
213
- );
214
- case "unary": {
215
- const value = evaluateNode(node.argument, context);
216
- return node.operator === "!" ? !value : -value;
217
- }
218
- case "ternary":
219
- return evaluateNode(node.test, context) ? evaluateNode(node.consequent, context) : evaluateNode(node.alternate, context);
220
- case "binary": {
221
- if (node.operator === "&&") {
222
- return evaluateNode(node.left, context) && evaluateNode(node.right, context);
223
- }
224
- if (node.operator === "||") {
225
- return evaluateNode(node.left, context) || evaluateNode(node.right, context);
226
- }
227
- const left = evaluateNode(node.left, context);
228
- const right = evaluateNode(node.right, context);
229
- switch (node.operator) {
230
- case "===":
231
- return left === right;
232
- case "!==":
233
- return left !== right;
234
- case "==":
235
- return left == right;
236
- case "!=":
237
- return left != right;
238
- case "<":
239
- return left < right;
240
- case ">":
241
- return left > right;
242
- case "<=":
243
- return left <= right;
244
- case ">=":
245
- return left >= right;
246
- case "+":
247
- return left + right;
248
- case "-":
249
- return left - right;
250
- case "*":
251
- return left * right;
252
- case "/":
253
- return left / right;
254
- case "%":
255
- return left % right;
256
- default:
257
- throw new Error(`\u4E0D\u652F\u6301\u7684\u8FD0\u7B97\u7B26 "${node.operator}"`);
258
- }
259
- }
260
- default:
261
- throw new Error("\u4E0D\u652F\u6301\u7684\u8282\u70B9\u7C7B\u578B");
262
- }
263
- }
264
- function evaluate(source, context) {
265
- try {
266
- return evaluateNode(parse(source), context);
267
- } catch (e) {
268
- return void 0;
269
- }
270
- }
271
- function check(source) {
272
- try {
273
- parse(source);
274
- return "";
275
- } catch (error) {
276
- return error.message;
277
- }
278
- }
279
- var INTERPOLATION_RE = /\{\{([\s\S]+?)\}\}/g;
280
- function interpolate(input, context) {
281
- if (typeof input !== "string" || input.indexOf("{{") === -1) return input;
282
- const trimmed = input.trim();
283
- const tokens = trimmed.match(INTERPOLATION_RE) || [];
284
- if (tokens.length === 1 && tokens[0] === trimmed) {
285
- return evaluate(trimmed.slice(2, -2).trim(), context);
286
- }
287
- return input.replace(INTERPOLATION_RE, (_, expr) => {
288
- const value = evaluate(expr.trim(), context);
289
- return value === void 0 || value === null ? "" : String(value);
290
- });
291
- }
292
- function interpolateDeep(input, context) {
293
- if (typeof input === "string") return interpolate(input, context);
294
- if (Array.isArray(input)) {
295
- return input.map((item) => interpolateDeep(item, context));
296
- }
297
- if (input && typeof input === "object") {
298
- const result = {};
299
- Object.keys(input).forEach((key) => {
300
- result[key] = interpolateDeep(input[key], context);
301
- });
302
- return result;
303
- }
304
- return input;
305
- }
1
+ import { normalizeViews, createTicker, interpolateDeep, interpolate, evaluate, resolveNodeStyle, toLength, toCssStyle, parseEndTime, computeParts, formatParts } from './chunk-FKZKLCVV.js';
2
+ export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, DSL_VERSION, NODE_TYPES, SINGLE_VIEW_NAME, TRACK_EVENT_PATTERN, check, computeParts, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, isValidEndTime, normalizeViews, parseEndTime, toCssStyle, toLength, validate } from './chunk-FKZKLCVV.js';
306
3
 
307
4
  // src/url.ts
308
5
  var SAFE_PROTOCOLS = ["http:", "https:", "mailto:", "tel:"];
@@ -390,229 +87,6 @@ function createDispatcher(options) {
390
87
  return dispatch;
391
88
  }
392
89
 
393
- // src/countdown.ts
394
- function pad(value, len = 2) {
395
- return String(value).padStart(len, "0");
396
- }
397
- function parseEndTime(to) {
398
- if (typeof to === "number") return to;
399
- if (to === void 0 || to === null || to === "") return 0;
400
- const raw = String(to).trim();
401
- if (!raw) return 0;
402
- if (/^\d+$/.test(raw)) return Number(raw);
403
- if (/^\d{4}年/.test(raw)) {
404
- const normalizedZh = raw.replace(/年|月/g, "/").replace(/日/g, " ").replace(/时|点|分/g, ":").replace(/秒/g, "").replace(/:+/g, ":").replace(/\s+/g, " ").replace(/[:\s]+$/, "").replace(/(\s\d{1,2})$/, "$1:00").trim();
405
- const time2 = new Date(normalizedZh).getTime();
406
- return isNaN(time2) ? 0 : time2;
407
- }
408
- const isIso = /^\d{4}-\d{2}-\d{2}T/.test(raw);
409
- const normalized = isIso ? raw : raw.replace(/-/g, "/");
410
- const time = new Date(normalized).getTime();
411
- return isNaN(time) ? 0 : time;
412
- }
413
- function isValidEndTime(to) {
414
- if (typeof to === "number") return isFinite(to) && to > 0;
415
- if (typeof to !== "string") return false;
416
- if (to.indexOf("{{") > -1) return true;
417
- return parseEndTime(to) > 0;
418
- }
419
- function computeParts(endTime, now = Date.now()) {
420
- const raw = endTime - now;
421
- const remain = raw > 0 ? raw : 0;
422
- const cs = Math.floor(remain / 10);
423
- const sec = Math.floor(cs / 100);
424
- return {
425
- d: String(Math.floor(sec / 86400)),
426
- // h 是 0~23;跨天还想连着数小时的用 hAll(如 143:58:07)
427
- h: pad(Math.floor(sec % 86400 / 3600)),
428
- hAll: pad(Math.floor(sec / 3600)),
429
- m: pad(Math.floor(sec % 3600 / 60)),
430
- s: pad(sec % 60),
431
- cs: pad(cs % 100),
432
- ended: !endTime || remain <= 0
433
- };
434
- }
435
- function formatParts(parts, format) {
436
- return (format || "{d}\u5929 {h}:{m}:{s}").replace("{d}", parts.d).replace("{hAll}", parts.hAll).replace("{h}", parts.h).replace("{m}", parts.m).replace("{s}", parts.s).replace("{cs}", parts.cs);
437
- }
438
- function createTicker(options) {
439
- let timer = null;
440
- let raf = 0;
441
- let running = false;
442
- let precision = "s";
443
- let endTimes = [];
444
- const hasRaf = typeof requestAnimationFrame === "function";
445
- function allEnded() {
446
- const now = Date.now();
447
- return endTimes.every((end) => !end || end - now <= 0);
448
- }
449
- function tick() {
450
- options.onTick();
451
- if (allEnded()) {
452
- stop();
453
- if (options.onAllEnded) options.onAllEnded();
454
- }
455
- }
456
- function stop() {
457
- running = false;
458
- if (timer) {
459
- clearInterval(timer);
460
- timer = null;
461
- }
462
- if (raf) {
463
- cancelAnimationFrame(raf);
464
- raf = 0;
465
- }
466
- }
467
- function sync(nextEndTimes, nextPrecision) {
468
- const changed = nextPrecision !== precision || nextEndTimes.length !== endTimes.length || nextEndTimes.some((end, i) => end !== endTimes[i]);
469
- endTimes = nextEndTimes;
470
- precision = nextPrecision;
471
- if (!changed && running) return;
472
- stop();
473
- if (!endTimes.length || allEnded()) return;
474
- running = true;
475
- if (precision === "cs" && hasRaf) {
476
- const loop = () => {
477
- tick();
478
- if (running) raf = requestAnimationFrame(loop);
479
- };
480
- raf = requestAnimationFrame(loop);
481
- } else {
482
- timer = setInterval(tick, 1e3);
483
- }
484
- }
485
- return { sync, stop };
486
- }
487
-
488
- // src/views.ts
489
- var SINGLE_VIEW_NAME = "main";
490
- function normalizeViews(dsl) {
491
- if (!dsl || typeof dsl !== "object") {
492
- return { entry: SINGLE_VIEW_NAME, views: {}, isMulti: false };
493
- }
494
- if (dsl.views && typeof dsl.views === "object" && !Array.isArray(dsl.views)) {
495
- const names = Object.keys(dsl.views);
496
- return {
497
- entry: dsl.entry && dsl.views[dsl.entry] ? dsl.entry : names[0],
498
- views: dsl.views,
499
- isMulti: true
500
- };
501
- }
502
- return {
503
- entry: SINGLE_VIEW_NAME,
504
- views: {
505
- [SINGLE_VIEW_NAME]: {
506
- type: dsl.type,
507
- stage: dsl.stage,
508
- nodes: dsl.nodes
509
- }
510
- },
511
- isMulti: false
512
- };
513
- }
514
-
515
- // src/style.ts
516
- function toLength(value) {
517
- return typeof value === "number" ? `${value}px` : String(value);
518
- }
519
- var px = toLength;
520
- var LENGTH_RE = /^-?(\d+(\.\d+)?)(px|%|em|rem|vw|vh)$/;
521
- function isLength(value) {
522
- if (typeof value === "number") return isFinite(value);
523
- if (typeof value !== "string") return false;
524
- const trimmed = value.trim();
525
- if (trimmed === "auto" || trimmed === "0") return true;
526
- if (/^calc\([^;{}]*\)$/.test(trimmed)) return true;
527
- return LENGTH_RE.test(trimmed);
528
- }
529
- var STYLE_MAP = {
530
- // 文字
531
- color: ["color", String],
532
- fontSize: ["fontSize", px],
533
- fontWeight: ["fontWeight", String],
534
- fontFamily: ["fontFamily", String],
535
- lineHeight: ["lineHeight", (v) => typeof v === "number" && v > 4 ? px(v) : String(v)],
536
- letterSpacing: ["letterSpacing", px],
537
- textAlign: ["textAlign", String],
538
- textDecoration: ["textDecoration", String],
539
- whiteSpace: ["whiteSpace", String],
540
- // 倒计时这类逐帧变化的数字必须等宽,否则数字会左右抖动
541
- fontVariantNumeric: ["fontVariantNumeric", String],
542
- // 背景
543
- background: ["background", String],
544
- backgroundImage: ["backgroundImage", (v) => `url(${JSON.stringify(String(v))})`],
545
- backgroundSize: ["backgroundSize", String],
546
- backgroundPosition: ["backgroundPosition", String],
547
- backgroundRepeat: ["backgroundRepeat", String],
548
- // 边框与圆角
549
- border: ["border", String],
550
- borderColor: ["borderColor", String],
551
- borderWidth: ["borderWidth", px],
552
- borderStyle: ["borderStyle", String],
553
- radius: ["borderRadius", px],
554
- // 盒模型
555
- padding: ["padding", px],
556
- margin: ["margin", px],
557
- marginTop: ["marginTop", px],
558
- marginBottom: ["marginBottom", px],
559
- marginLeft: ["marginLeft", px],
560
- marginRight: ["marginRight", px],
561
- overflow: ["overflow", String],
562
- opacity: ["opacity", String],
563
- shadow: ["boxShadow", String],
564
- cursor: ["cursor", String],
565
- // flex 容器
566
- direction: ["flexDirection", (v) => v === "column" ? "column" : "row"],
567
- gap: ["gap", px],
568
- wrap: ["flexWrap", (v) => v ? "wrap" : "nowrap"],
569
- align: ["alignItems", String],
570
- justify: ["justifyContent", String],
571
- // flex 子项
572
- flex: ["flex", String],
573
- // 不写时子项会被拉满父级交叉轴,标签这类「按内容宽度」的元素要显式声明
574
- alignSelf: ["alignSelf", String],
575
- width: ["width", px],
576
- height: ["height", px],
577
- minWidth: ["minWidth", px],
578
- minHeight: ["minHeight", px],
579
- maxWidth: ["maxWidth", px],
580
- maxHeight: ["maxHeight", px],
581
- // 图片
582
- objectFit: ["objectFit", String],
583
- // 宽度给百分比、高度按比例算。整图 banner 的热区必须靠它才能用百分比定位:
584
- // 容器没有真实高度时,子节点的百分比 rect 算出来全是 0。
585
- aspectRatio: ["aspectRatio", String]
586
- };
587
- var ALLOWED_STYLE_KEYS = Object.keys(STYLE_MAP);
588
- function toCssStyle(style) {
589
- const css = {};
590
- if (!style) return css;
591
- Object.keys(style).forEach((key) => {
592
- const rule = STYLE_MAP[key];
593
- if (!rule) return;
594
- const value = style[key];
595
- if (value === void 0 || value === null || value === "") return;
596
- css[rule[0]] = rule[1](value);
597
- });
598
- return css;
599
- }
600
- function toRectStyle(rect) {
601
- if (!Array.isArray(rect)) return {};
602
- const [x, y, w, h] = rect;
603
- const css = { position: "absolute", left: px(x || 0), top: px(y || 0) };
604
- if (w !== void 0 && w !== null && w !== "auto") css.width = px(w);
605
- if (h !== void 0 && h !== null && h !== "auto") css.height = px(h);
606
- return css;
607
- }
608
- function resolveNodeStyle(node, layout) {
609
- return Object.assign(
610
- {},
611
- layout === "absolute" ? toRectStyle(node.rect) : {},
612
- toCssStyle(node.style)
613
- );
614
- }
615
-
616
90
  // src/resolve.ts
617
91
  function resolveTree(input) {
618
92
  const { normalized, viewStack, ready } = input;
@@ -728,11 +202,12 @@ function resolveCloseButton(config, layerName, closeTop) {
728
202
  const offset = config.offset || [8, 8];
729
203
  const size = config.size === void 0 ? 26 : config.size;
730
204
  const position = config.position || "top-right";
205
+ const image = config.image ? safeImageUrl(config.image) : "";
206
+ const iconMode = image ? "image" : config.icon ? "text" : "svg";
731
207
  const style = {
732
208
  position: "absolute",
733
209
  width: toLength(size),
734
210
  height: toLength(size),
735
- lineHeight: toLength(size),
736
211
  display: "flex",
737
212
  alignItems: "center",
738
213
  justifyContent: "center",
@@ -740,12 +215,15 @@ function resolveCloseButton(config, layerName, closeTop) {
740
215
  borderRadius: "50%",
741
216
  background: "rgba(0, 0, 0, 0.35)",
742
217
  color: "#fff",
743
- fontSize: "18px",
744
- textAlign: "center",
745
218
  cursor: "pointer",
746
219
  userSelect: "none",
747
220
  zIndex: "1"
748
221
  };
222
+ if (iconMode !== "svg") {
223
+ style.lineHeight = toLength(size);
224
+ style.fontSize = "18px";
225
+ style.textAlign = "center";
226
+ }
749
227
  if (position.indexOf("bottom") === 0) style.bottom = toLength(offset[1]);
750
228
  else style.top = toLength(offset[1]);
751
229
  if (position.indexOf("center") > -1) {
@@ -758,8 +236,7 @@ function resolveCloseButton(config, layerName, closeTop) {
758
236
  }
759
237
  Object.assign(style, toCssStyle(config.style));
760
238
  const onClick = () => closeTop("close-button");
761
- const image = config.image ? safeImageUrl(config.image) : "";
762
- if (image) {
239
+ if (iconMode === "image") {
763
240
  return {
764
241
  key: `${layerName}-close`,
765
242
  tag: "div",
@@ -782,15 +259,81 @@ function resolveCloseButton(config, layerName, closeTop) {
782
259
  ]
783
260
  };
784
261
  }
262
+ if (iconMode === "text") {
263
+ return {
264
+ key: `${layerName}-close`,
265
+ tag: "div",
266
+ className: "dsl-close",
267
+ style,
268
+ onClick,
269
+ text: config.icon
270
+ };
271
+ }
785
272
  return {
786
273
  key: `${layerName}-close`,
787
274
  tag: "div",
788
275
  className: "dsl-close",
789
276
  style,
790
277
  onClick,
791
- text: config.icon || "\xD7"
278
+ children: [closeIcon(`${layerName}-close-icon`, size)]
279
+ };
280
+ }
281
+ function closeIcon(key, size) {
282
+ const box = clamp(Math.round(toPx(size, 26) * 0.42), 8, 18);
283
+ const stroke = Math.max(1.2, round2(box * 0.15));
284
+ const a = round2(stroke / 2);
285
+ const b = round2(box - stroke / 2);
286
+ const lineAttrs = {
287
+ stroke: "currentColor",
288
+ "stroke-width": String(stroke),
289
+ "stroke-linecap": "round"
290
+ };
291
+ return {
292
+ key,
293
+ tag: "svg",
294
+ className: "dsl-close-icon",
295
+ style: { display: "block" },
296
+ attrs: {
297
+ width: String(box),
298
+ height: String(box),
299
+ viewBox: `0 0 ${box} ${box}`,
300
+ fill: "none",
301
+ "aria-hidden": "true"
302
+ },
303
+ children: [
304
+ {
305
+ key: `${key}-1`,
306
+ tag: "line",
307
+ className: "dsl-close-icon-line",
308
+ style: {},
309
+ attrs: Object.assign(
310
+ { x1: String(a), y1: String(a), x2: String(b), y2: String(b) },
311
+ lineAttrs
312
+ )
313
+ },
314
+ {
315
+ key: `${key}-2`,
316
+ tag: "line",
317
+ className: "dsl-close-icon-line",
318
+ style: {},
319
+ attrs: Object.assign(
320
+ { x1: String(b), y1: String(a), x2: String(a), y2: String(b) },
321
+ lineAttrs
322
+ )
323
+ }
324
+ ]
792
325
  };
793
326
  }
327
+ function toPx(value, fallback) {
328
+ const num = typeof value === "number" ? value : parseFloat(String(value));
329
+ return isFinite(num) && num > 0 ? num : fallback;
330
+ }
331
+ function clamp(value, min, max) {
332
+ return Math.min(max, Math.max(min, value));
333
+ }
334
+ function round2(value) {
335
+ return Math.round(value * 100) / 100;
336
+ }
794
337
  var BASE_STYLE = { boxSizing: "border-box" };
795
338
  var NODE_CLASS = {
796
339
  box: "dsl-box",
@@ -1195,434 +738,4 @@ function createRuntime(dsl, options = {}) {
1195
738
  };
1196
739
  }
1197
740
 
1198
- // src/validate.ts
1199
- var LENGTH_STYLE_KEYS = [
1200
- "width",
1201
- "height",
1202
- "minWidth",
1203
- "minHeight",
1204
- "maxWidth",
1205
- "maxHeight",
1206
- "radius",
1207
- "padding",
1208
- "margin",
1209
- "marginTop",
1210
- "marginBottom",
1211
- "marginLeft",
1212
- "marginRight",
1213
- "gap",
1214
- "fontSize",
1215
- "letterSpacing",
1216
- "borderWidth"
1217
- ];
1218
- var DSL_VERSION = 1;
1219
- var NODE_TYPES = [
1220
- "box",
1221
- "flex",
1222
- "repeat",
1223
- "image",
1224
- "text",
1225
- "button",
1226
- "tabs",
1227
- "countdown"
1228
- ];
1229
- var ACTION_TYPES = [
1230
- "navigate",
1231
- "close",
1232
- "closeAll",
1233
- "open",
1234
- "setState",
1235
- "track",
1236
- "call",
1237
- "sequence"
1238
- ];
1239
- var CLOSE_POSITIONS = [
1240
- "top-right",
1241
- "top-left",
1242
- "top-center",
1243
- "bottom-right",
1244
- "bottom-left",
1245
- "bottom-center"
1246
- ];
1247
- var CONTAINER_TYPES = ["box", "flex"];
1248
- function validate(dsl) {
1249
- const errors = [];
1250
- const warnings = [];
1251
- const add = (path, message) => errors.push({ path, message });
1252
- const warn = (path, message) => warnings.push({ path, message });
1253
- if (!dsl || typeof dsl !== "object" || Array.isArray(dsl)) {
1254
- return {
1255
- valid: false,
1256
- errors: [{ path: "", message: "\u6839\u8282\u70B9\u5FC5\u987B\u662F\u4E00\u4E2A\u5BF9\u8C61" }],
1257
- warnings
1258
- };
1259
- }
1260
- const doc = dsl;
1261
- if (doc.version !== DSL_VERSION) {
1262
- add(
1263
- "version",
1264
- `version \u5FC5\u987B\u662F ${DSL_VERSION}\uFF0C\u5F53\u524D\u4E3A ${JSON.stringify(doc.version)}`
1265
- );
1266
- }
1267
- const dataKeys = validateData(doc.data, add);
1268
- const stateKeys = validateState(doc.state, add);
1269
- validateDerived(doc.derived, dataKeys, stateKeys, add);
1270
- const isMulti = doc.views !== void 0;
1271
- if (isMulti) validateMultiView(doc, add);
1272
- const { views } = normalizeViews(doc);
1273
- const viewNames = Object.keys(views);
1274
- const ctx = { add, warn, viewNames };
1275
- viewNames.forEach((name) => {
1276
- validateView(views[name], isMulti ? `views.${name}` : "", ctx);
1277
- });
1278
- return { valid: errors.length === 0, errors, warnings };
1279
- }
1280
- function validateMultiView(dsl, add) {
1281
- if (typeof dsl.views !== "object" || dsl.views === null || Array.isArray(dsl.views)) {
1282
- add("views", 'views \u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u5F62\u5982 { "main": { type, stage, nodes } }');
1283
- return;
1284
- }
1285
- if (!Object.keys(dsl.views).length) {
1286
- add("views", "views \u81F3\u5C11\u8981\u6709\u4E00\u4E2A\u89C6\u56FE");
1287
- return;
1288
- }
1289
- if (dsl.entry === void 0) {
1290
- add("entry", "\u591A\u89C6\u56FE\u5FC5\u987B\u6307\u5B9A entry\uFF08\u9996\u4E2A\u5C55\u793A\u7684\u89C6\u56FE\u540D\uFF09");
1291
- } else if (!dsl.views[dsl.entry]) {
1292
- add("entry", `entry "${dsl.entry}" \u5728 views \u91CC\u4E0D\u5B58\u5728`);
1293
- }
1294
- ["stage", "nodes"].forEach((key) => {
1295
- if (dsl[key] !== void 0) {
1296
- add(key, `\u7528\u4E86 views \u4E4B\u540E\uFF0C${key} \u8981\u5199\u5728\u6BCF\u4E2A\u89C6\u56FE\u91CC\uFF0C\u4E0D\u80FD\u7559\u5728\u9876\u5C42`);
1297
- }
1298
- });
1299
- }
1300
- function validateView(view, prefix, ctx) {
1301
- const { add, warn } = ctx;
1302
- const at = (key) => prefix ? `${prefix}.${key}` : key;
1303
- if (!view || typeof view !== "object" || Array.isArray(view)) {
1304
- add(prefix || "view", "\u89C6\u56FE\u5FC5\u987B\u662F\u5BF9\u8C61\uFF0C\u5305\u542B type / stage / nodes");
1305
- return;
1306
- }
1307
- if (["popup", "banner", "notice"].indexOf(view.type) === -1) {
1308
- add(at("type"), "type \u5FC5\u987B\u662F popup / banner / notice \u4E4B\u4E00");
1309
- }
1310
- validateStage(
1311
- view.stage,
1312
- (path, message) => add(prefix ? `${prefix}.${path}` : path, message),
1313
- warn,
1314
- ctx,
1315
- prefix
1316
- );
1317
- if (!Array.isArray(view.nodes) || view.nodes.length === 0) {
1318
- add(at("nodes"), "nodes \u5FC5\u987B\u662F\u975E\u7A7A\u6570\u7EC4");
1319
- return;
1320
- }
1321
- const rootLayout = (view.stage || {}).layout === "flow" ? "flow" : "absolute";
1322
- view.nodes.forEach((node, index) => {
1323
- validateNode(node, at(`nodes[${index}]`), rootLayout, ctx);
1324
- });
1325
- }
1326
- function checkLength(value) {
1327
- if (typeof value === "string" && value.indexOf("{{") > -1) return true;
1328
- if (typeof value === "number") return isLength(value);
1329
- if (typeof value !== "string") return false;
1330
- if (isLength(value)) return true;
1331
- return value.trim().split(/\s+/).every(isLength);
1332
- }
1333
- function checkAspectRatio(value) {
1334
- if (typeof value === "string" && value.indexOf("{{") > -1) return true;
1335
- if (typeof value === "number") return isFinite(value) && value > 0;
1336
- if (typeof value !== "string") return false;
1337
- return /^\s*\d+(\.\d+)?\s*(\/\s*\d+(\.\d+)?\s*)?$/.test(value);
1338
- }
1339
- function validateStage(stage, add, warn, ctx, prefix) {
1340
- if (stage === void 0) {
1341
- add("stage", "\u7F3A\u5C11 stage");
1342
- return;
1343
- }
1344
- if (typeof stage !== "object" || stage === null) {
1345
- add("stage", "stage \u5FC5\u987B\u662F\u5BF9\u8C61");
1346
- return;
1347
- }
1348
- if (!checkLength(stage.width)) {
1349
- add(
1350
- "stage.width",
1351
- "stage.width \u5FC5\u987B\u662F\u6570\u5B57(px)\u6216\u957F\u5EA6\u5B57\u7B26\u4E32\uFF0C\u5982 460 / '100%' / 'calc(100% - 32px)'"
1352
- );
1353
- }
1354
- if (!checkLength(stage.height)) {
1355
- add("stage.height", "stage.height \u5FC5\u987B\u662F\u6570\u5B57(px)\u6216\u957F\u5EA6\u5B57\u7B26\u4E32\uFF0C\u5982 520 / 'auto'");
1356
- }
1357
- if (stage.layout !== void 0 && ["absolute", "flow"].indexOf(stage.layout) === -1) {
1358
- add("stage.layout", "stage.layout \u53EA\u80FD\u662F 'absolute'\uFF08\u9ED8\u8BA4\uFF09\u6216 'flow'");
1359
- }
1360
- validateCloseButton(stage.closeButton, add, warn);
1361
- const at = (key) => prefix ? `${prefix}.stage.${key}` : `stage.${key}`;
1362
- if (stage.onShow !== void 0) validateAction(stage.onShow, at("onShow"), ctx);
1363
- if (stage.onClose !== void 0) validateAction(stage.onClose, at("onClose"), ctx);
1364
- if (stage.height === "auto" && stage.layout !== "flow") {
1365
- add(
1366
- "stage.height",
1367
- "height: 'auto' \u9700\u8981\u540C\u65F6\u8BBE\u7F6E stage.layout: 'flow'\uFF0C\u5426\u5219\u9AD8\u5EA6\u4F1A\u584C\u6210 0"
1368
- );
1369
- }
1370
- }
1371
- function validateCloseButton(config, add, warn) {
1372
- if (config === void 0) return;
1373
- if (typeof config !== "object" || config === null || Array.isArray(config)) {
1374
- add("stage.closeButton", "closeButton \u5FC5\u987B\u662F\u5BF9\u8C61");
1375
- return;
1376
- }
1377
- if (config.position !== void 0 && CLOSE_POSITIONS.indexOf(config.position) === -1) {
1378
- add("stage.closeButton.position", `position \u53EA\u80FD\u662F ${CLOSE_POSITIONS.join(" / ")}`);
1379
- }
1380
- if (config.offset !== void 0) {
1381
- if (!Array.isArray(config.offset) || config.offset.length !== 2) {
1382
- add(
1383
- "stage.closeButton.offset",
1384
- "offset \u5FC5\u987B\u662F [x, y] \u4E24\u9879\u6570\u7EC4\uFF0C\u8D1F\u503C\u4F1A\u628A\u6309\u94AE\u79FB\u5230\u5F39\u7A97\u5916\u9762"
1385
- );
1386
- } else {
1387
- config.offset.forEach((value, index) => {
1388
- if (!checkLength(value)) {
1389
- add(`stage.closeButton.offset[${index}]`, `"${value}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6`);
1390
- }
1391
- });
1392
- }
1393
- }
1394
- if (config.size !== void 0 && !checkLength(config.size)) {
1395
- add("stage.closeButton.size", `"${config.size}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6`);
1396
- }
1397
- if (config.icon !== void 0 && typeof config.icon !== "string") {
1398
- add("stage.closeButton.icon", "icon \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
1399
- }
1400
- if (config.image !== void 0 && typeof config.image !== "string") {
1401
- add("stage.closeButton.image", "image \u5FC5\u987B\u662F\u56FE\u7247\u94FE\u63A5\u5B57\u7B26\u4E32");
1402
- }
1403
- if (config.style) {
1404
- Object.keys(config.style).forEach((key) => {
1405
- if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
1406
- warn(
1407
- `stage.closeButton.style.${key}`,
1408
- `\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`
1409
- );
1410
- }
1411
- });
1412
- }
1413
- }
1414
- function validateData(data, add) {
1415
- if (data === void 0) return [];
1416
- if (typeof data !== "object" || data === null || Array.isArray(data)) {
1417
- add("data", "data \u5FC5\u987B\u662F\u5BF9\u8C61");
1418
- return [];
1419
- }
1420
- Object.keys(data).forEach((key) => {
1421
- const value = data[key];
1422
- if (value && typeof value === "object" && !Array.isArray(value) && value.$source) {
1423
- if (typeof value.$source !== "string") {
1424
- add(`data.${key}.$source`, "$source \u5FC5\u987B\u662F\u6570\u636E\u6E90\u540D\u79F0\u5B57\u7B26\u4E32");
1425
- }
1426
- if (value.params !== void 0 && (typeof value.params !== "object" || value.params === null)) {
1427
- add(`data.${key}.params`, "params \u5FC5\u987B\u662F\u5BF9\u8C61");
1428
- }
1429
- }
1430
- });
1431
- return Object.keys(data);
1432
- }
1433
- function validateState(state, add) {
1434
- if (state === void 0) return [];
1435
- if (typeof state !== "object" || state === null || Array.isArray(state)) {
1436
- add("state", "state \u5FC5\u987B\u662F\u5BF9\u8C61");
1437
- return [];
1438
- }
1439
- return Object.keys(state);
1440
- }
1441
- function validateDerived(derived, dataKeys, stateKeys, add) {
1442
- if (derived === void 0) return;
1443
- if (typeof derived !== "object" || derived === null || Array.isArray(derived)) {
1444
- add("derived", "derived \u5FC5\u987B\u662F\u5BF9\u8C61");
1445
- return;
1446
- }
1447
- Object.keys(derived).forEach((key) => {
1448
- const item = derived[key] || {};
1449
- if (typeof item.list !== "string") {
1450
- add(`derived.${key}.list`, "list \u5FC5\u987B\u662F data \u4E2D\u7684\u6570\u7EC4\u5B57\u6BB5\u540D");
1451
- } else if (dataKeys.indexOf(item.list) === -1) {
1452
- add(`derived.${key}.list`, `data \u4E2D\u4E0D\u5B58\u5728 "${item.list}"`);
1453
- }
1454
- if (typeof item.indexBy !== "string") {
1455
- add(`derived.${key}.indexBy`, "indexBy \u5FC5\u987B\u662F state \u4E2D\u7684\u5B57\u6BB5\u540D");
1456
- } else if (stateKeys.indexOf(item.indexBy) === -1) {
1457
- add(`derived.${key}.indexBy`, `state \u4E2D\u4E0D\u5B58\u5728 "${item.indexBy}"`);
1458
- }
1459
- });
1460
- }
1461
- function validateNode(node, path, layout, ctx) {
1462
- const { add, warn } = ctx;
1463
- if (!node || typeof node !== "object" || Array.isArray(node)) {
1464
- add(path, "\u8282\u70B9\u5FC5\u987B\u662F\u5BF9\u8C61");
1465
- return;
1466
- }
1467
- if (NODE_TYPES.indexOf(node.type) === -1) {
1468
- add(`${path}.type`, `\u672A\u77E5\u8282\u70B9\u7C7B\u578B "${node.type}"\uFF0C\u53EF\u7528\uFF1A${NODE_TYPES.join(" / ")}`);
1469
- return;
1470
- }
1471
- if (layout === "absolute" && !Array.isArray(node.rect)) {
1472
- add(`${path}.rect`, "\u5904\u4E8E\u7EDD\u5BF9\u5B9A\u4F4D\u5BB9\u5668\u4E2D\uFF0C\u5FC5\u987B\u63D0\u4F9B rect: [x, y, w, h]");
1473
- }
1474
- if (node.rect !== void 0) {
1475
- if (!Array.isArray(node.rect)) {
1476
- add(`${path}.rect`, "rect \u5FC5\u987B\u662F [x, y, w, h] \u6570\u7EC4");
1477
- } else {
1478
- node.rect.forEach((value, index) => {
1479
- if (value !== void 0 && value !== null && !checkLength(value)) {
1480
- add(
1481
- `${path}.rect[${index}]`,
1482
- `"${value}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6\uFF0C\u652F\u6301\u6570\u5B57(px) / '100%' / 'auto' \u7B49`
1483
- );
1484
- }
1485
- });
1486
- }
1487
- }
1488
- if (node.style) {
1489
- Object.keys(node.style).forEach((key) => {
1490
- if (ALLOWED_STYLE_KEYS.indexOf(key) === -1) {
1491
- warn(`${path}.style.${key}`, `\u6837\u5F0F\u5C5E\u6027 "${key}" \u4E0D\u5728\u767D\u540D\u5355\u5185\uFF0C\u6E32\u67D3\u65F6\u4F1A\u88AB\u5FFD\u7565`);
1492
- return;
1493
- }
1494
- if (LENGTH_STYLE_KEYS.indexOf(key) > -1 && !checkLength(node.style[key])) {
1495
- add(
1496
- `${path}.style.${key}`,
1497
- `"${node.style[key]}" \u4E0D\u662F\u5408\u6CD5\u957F\u5EA6\uFF0C\u652F\u6301\u6570\u5B57(px) / '100%' / 'auto' \u7B49`
1498
- );
1499
- }
1500
- if (key === "aspectRatio" && !checkAspectRatio(node.style[key])) {
1501
- add(
1502
- `${path}.style.aspectRatio`,
1503
- "aspectRatio \u8981\u5199\u6210 '750 / 200' \u6216 1.5 \u8FD9\u6837\u7684\u5BBD\u9AD8\u6BD4"
1504
- );
1505
- }
1506
- });
1507
- }
1508
- if (node.visibleWhen !== void 0) {
1509
- if (typeof node.visibleWhen !== "string") {
1510
- add(`${path}.visibleWhen`, "visibleWhen \u5FC5\u987B\u662F\u8868\u8FBE\u5F0F\u5B57\u7B26\u4E32");
1511
- } else {
1512
- const error = check(node.visibleWhen);
1513
- if (error) add(`${path}.visibleWhen`, `\u8868\u8FBE\u5F0F\u6709\u8BEF\uFF1A${error}`);
1514
- }
1515
- }
1516
- if (node.action !== void 0) validateAction(node.action, `${path}.action`, ctx);
1517
- validateNodeByType(node, path, ctx);
1518
- }
1519
- function validateNodeByType(node, path, ctx) {
1520
- const { add } = ctx;
1521
- if (node.type === "image" && !node.src) {
1522
- add(`${path}.src`, "image \u5FC5\u987B\u63D0\u4F9B src");
1523
- }
1524
- if (node.type === "text" && node.content === void 0) {
1525
- add(`${path}.content`, "text \u5FC5\u987B\u63D0\u4F9B content");
1526
- }
1527
- if (node.type === "button" && node.text === void 0) {
1528
- add(`${path}.text`, "button \u5FC5\u987B\u63D0\u4F9B text");
1529
- }
1530
- if (node.type === "tabs") {
1531
- if (typeof node.bind !== "string") {
1532
- add(`${path}.bind`, "tabs \u5FC5\u987B\u63D0\u4F9B bind\uFF08data \u4E2D\u7684\u6570\u7EC4\u5B57\u6BB5\u540D\uFF09");
1533
- }
1534
- if (typeof node.stateKey !== "string")
1535
- add(`${path}.stateKey`, "tabs \u5FC5\u987B\u63D0\u4F9B stateKey");
1536
- if (node.labelField !== void 0 && typeof node.labelField !== "string") {
1537
- add(`${path}.labelField`, "labelField \u5FC5\u987B\u662F\u5B57\u7B26\u4E32");
1538
- }
1539
- }
1540
- if (node.type === "countdown") {
1541
- if (!node.to) {
1542
- add(`${path}.to`, "countdown \u5FC5\u987B\u63D0\u4F9B to\uFF08\u7ED3\u675F\u65F6\u95F4\uFF09");
1543
- } else if (!isValidEndTime(node.to)) {
1544
- add(
1545
- `${path}.to`,
1546
- `"${node.to}" \u4E0D\u662F\u80FD\u8BC6\u522B\u7684\u65F6\u95F4\u3002\u53EF\u4EE5\u5199 "2026-09-01 18:00:00" / "2026-09-01" / "2026\u5E749\u67081\u65E5 18\u70B9" / ISO \u683C\u5F0F / \u65F6\u95F4\u6233`
1547
- );
1548
- }
1549
- if (node.precision !== void 0 && ["s", "cs"].indexOf(node.precision) === -1) {
1550
- add(`${path}.precision`, "precision \u53EA\u80FD\u662F 's'\uFF08\u6BCF\u79D2\uFF09\u6216 'cs'\uFF08\u5398\u79D2\uFF0C\u9010\u5E27\u5237\u65B0\uFF09");
1551
- }
1552
- if (node.children !== void 0 && !Array.isArray(node.children)) {
1553
- add(`${path}.children`, "children \u5FC5\u987B\u662F\u6570\u7EC4");
1554
- } else {
1555
- (node.children || []).forEach((child, index) => {
1556
- validateNode(child, `${path}.children[${index}]`, "flow", ctx);
1557
- });
1558
- }
1559
- }
1560
- if (node.type === "repeat") {
1561
- if (typeof node.bind !== "string") add(`${path}.bind`, "repeat \u5FC5\u987B\u63D0\u4F9B bind");
1562
- if (!node.template) {
1563
- add(`${path}.template`, "repeat \u5FC5\u987B\u63D0\u4F9B template");
1564
- } else {
1565
- validateNode(node.template, `${path}.template`, "flow", ctx);
1566
- }
1567
- }
1568
- if (CONTAINER_TYPES.indexOf(node.type) > -1) {
1569
- const childLayout = node.type === "box" ? "absolute" : "flow";
1570
- if (node.children !== void 0 && !Array.isArray(node.children)) {
1571
- add(`${path}.children`, "children \u5FC5\u987B\u662F\u6570\u7EC4");
1572
- } else {
1573
- (node.children || []).forEach((child, index) => {
1574
- validateNode(child, `${path}.children[${index}]`, childLayout, ctx);
1575
- });
1576
- }
1577
- }
1578
- }
1579
- function validateAction(action, path, ctx) {
1580
- const { add } = ctx;
1581
- if (!action || typeof action !== "object" || Array.isArray(action)) {
1582
- add(path, "action \u5FC5\u987B\u662F\u5BF9\u8C61");
1583
- return;
1584
- }
1585
- if (ACTION_TYPES.indexOf(action.type) === -1) {
1586
- add(`${path}.type`, `\u672A\u77E5\u52A8\u4F5C "${action.type}"\uFF0C\u53EF\u7528\uFF1A${ACTION_TYPES.join(" / ")}`);
1587
- return;
1588
- }
1589
- if (action.type === "navigate" && !action.url) {
1590
- add(`${path}.url`, "navigate \u5FC5\u987B\u63D0\u4F9B url");
1591
- }
1592
- if (action.type === "setState" && typeof action.key !== "string") {
1593
- add(`${path}.key`, "setState \u5FC5\u987B\u63D0\u4F9B key");
1594
- }
1595
- if (action.type === "track" && !action.event) {
1596
- add(`${path}.event`, "track \u5FC5\u987B\u63D0\u4F9B event");
1597
- }
1598
- if (action.type === "call" && !action.name) {
1599
- add(`${path}.name`, "call \u5FC5\u987B\u63D0\u4F9B name\uFF08\u5BBF\u4E3B\u6CE8\u518C\u7684\u65B9\u6CD5\u540D\uFF09");
1600
- }
1601
- if (action.type === "open") {
1602
- if (!action.view) {
1603
- add(`${path}.view`, "open \u5FC5\u987B\u63D0\u4F9B view\uFF08\u8981\u6253\u5F00\u7684\u89C6\u56FE\u540D\uFF09");
1604
- } else if (ctx.viewNames && ctx.viewNames.indexOf(action.view) === -1) {
1605
- add(`${path}.view`, `views \u91CC\u4E0D\u5B58\u5728\u89C6\u56FE "${action.view}"`);
1606
- }
1607
- if (action.mode !== void 0 && ["stack", "replace"].indexOf(action.mode) === -1) {
1608
- add(
1609
- `${path}.mode`,
1610
- "mode \u53EA\u80FD\u662F 'stack'\uFF08\u9ED8\u8BA4\uFF0C\u53E0\u4E00\u5C42\uFF09\u6216 'replace'\uFF08\u6362\u6389\u5F53\u524D\u5C42\uFF09"
1611
- );
1612
- }
1613
- }
1614
- if (action.type === "sequence") {
1615
- if (!Array.isArray(action.actions)) {
1616
- add(`${path}.actions`, "sequence \u5FC5\u987B\u63D0\u4F9B actions \u6570\u7EC4");
1617
- } else {
1618
- action.actions.forEach(
1619
- (item, index) => validateAction(item, `${path}.actions[${index}]`, ctx)
1620
- );
1621
- }
1622
- }
1623
- }
1624
- function formatIssues(issues) {
1625
- return issues.map((item) => item.path ? `${item.path}: ${item.message}` : item.message).join("\n");
1626
- }
1627
-
1628
- export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, DSL_VERSION, NODE_TYPES, SINGLE_VIEW_NAME, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, isValidEndTime, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
741
+ export { createRuntime, safeImageUrl, safeUrl };