@yaoxiu/marketing-dsl 1.2.0 → 1.3.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.cjs +32 -7
- package/dist/index.d.cts +8 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +32 -8
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -400,10 +400,24 @@ function parseEndTime(to) {
|
|
|
400
400
|
if (typeof to === "number") return to;
|
|
401
401
|
if (to === void 0 || to === null || to === "") return 0;
|
|
402
402
|
const raw = String(to).trim();
|
|
403
|
+
if (!raw) return 0;
|
|
403
404
|
if (/^\d+$/.test(raw)) return Number(raw);
|
|
404
|
-
|
|
405
|
+
if (/^\d{4}年/.test(raw)) {
|
|
406
|
+
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();
|
|
407
|
+
const time2 = new Date(normalizedZh).getTime();
|
|
408
|
+
return isNaN(time2) ? 0 : time2;
|
|
409
|
+
}
|
|
410
|
+
const isIso = /^\d{4}-\d{2}-\d{2}T/.test(raw);
|
|
411
|
+
const normalized = isIso ? raw : raw.replace(/-/g, "/");
|
|
412
|
+
const time = new Date(normalized).getTime();
|
|
405
413
|
return isNaN(time) ? 0 : time;
|
|
406
414
|
}
|
|
415
|
+
function isValidEndTime(to) {
|
|
416
|
+
if (typeof to === "number") return isFinite(to) && to > 0;
|
|
417
|
+
if (typeof to !== "string") return false;
|
|
418
|
+
if (to.indexOf("{{") > -1) return true;
|
|
419
|
+
return parseEndTime(to) > 0;
|
|
420
|
+
}
|
|
407
421
|
function computeParts(endTime, now = Date.now()) {
|
|
408
422
|
const raw = endTime - now;
|
|
409
423
|
const remain = raw > 0 ? raw : 0;
|
|
@@ -956,10 +970,13 @@ function resolveCountdown(node, key, style, context, input, countdowns) {
|
|
|
956
970
|
const parts = computeParts(endTime);
|
|
957
971
|
countdowns.endTimes.push(endTime);
|
|
958
972
|
if (node.precision === "cs") countdowns.precision = "cs";
|
|
959
|
-
if (
|
|
973
|
+
if (endTime && node.onEnd) {
|
|
960
974
|
const token = `${key}@${endTime}`;
|
|
961
|
-
|
|
962
|
-
|
|
975
|
+
const status = input.countdownEnds.get(token);
|
|
976
|
+
if (status === void 0) {
|
|
977
|
+
input.countdownEnds.set(token, parts.ended ? "done" : "waiting");
|
|
978
|
+
} else if (status === "waiting" && parts.ended) {
|
|
979
|
+
input.countdownEnds.set(token, "done");
|
|
963
980
|
input.dispatch(node.onEnd, context);
|
|
964
981
|
}
|
|
965
982
|
}
|
|
@@ -1019,7 +1036,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1019
1036
|
let loadFailed = false;
|
|
1020
1037
|
let destroyed = false;
|
|
1021
1038
|
const listeners = /* @__PURE__ */ new Set();
|
|
1022
|
-
const
|
|
1039
|
+
const countdownEnds = /* @__PURE__ */ new Map();
|
|
1023
1040
|
const notify = () => {
|
|
1024
1041
|
if (destroyed) return;
|
|
1025
1042
|
listeners.forEach((fn) => fn());
|
|
@@ -1153,7 +1170,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1153
1170
|
dispatch,
|
|
1154
1171
|
setState,
|
|
1155
1172
|
closeTop,
|
|
1156
|
-
|
|
1173
|
+
countdownEnds
|
|
1157
1174
|
});
|
|
1158
1175
|
ticker.sync(tree.countdownEndTimes, tree.countdownPrecision);
|
|
1159
1176
|
return tree;
|
|
@@ -1523,7 +1540,14 @@ function validateNodeByType(node, path, ctx) {
|
|
|
1523
1540
|
}
|
|
1524
1541
|
}
|
|
1525
1542
|
if (node.type === "countdown") {
|
|
1526
|
-
if (!node.to)
|
|
1543
|
+
if (!node.to) {
|
|
1544
|
+
add(`${path}.to`, "countdown \u5FC5\u987B\u63D0\u4F9B to\uFF08\u7ED3\u675F\u65F6\u95F4\uFF09");
|
|
1545
|
+
} else if (!isValidEndTime(node.to)) {
|
|
1546
|
+
add(
|
|
1547
|
+
`${path}.to`,
|
|
1548
|
+
`"${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`
|
|
1549
|
+
);
|
|
1550
|
+
}
|
|
1527
1551
|
if (node.precision !== void 0 && ["s", "cs"].indexOf(node.precision) === -1) {
|
|
1528
1552
|
add(`${path}.precision`, "precision \u53EA\u80FD\u662F 's'\uFF08\u6BCF\u79D2\uFF09\u6216 'cs'\uFF08\u5398\u79D2\uFF0C\u9010\u5E27\u5237\u65B0\uFF09");
|
|
1529
1553
|
}
|
|
@@ -1618,6 +1642,7 @@ exports.formatParts = formatParts;
|
|
|
1618
1642
|
exports.interpolate = interpolate;
|
|
1619
1643
|
exports.interpolateDeep = interpolateDeep;
|
|
1620
1644
|
exports.isLength = isLength;
|
|
1645
|
+
exports.isValidEndTime = isValidEndTime;
|
|
1621
1646
|
exports.normalizeViews = normalizeViews;
|
|
1622
1647
|
exports.parseEndTime = parseEndTime;
|
|
1623
1648
|
exports.safeImageUrl = safeImageUrl;
|
package/dist/index.d.cts
CHANGED
|
@@ -438,9 +438,16 @@ interface CountdownParts {
|
|
|
438
438
|
type CountdownPrecision = 's' | 'cs';
|
|
439
439
|
/** 把 to 解析成时间戳。兼容 '2026-09-01 00:00:00' 这种 Safari 不认的格式 */
|
|
440
440
|
declare function parseEndTime(to: unknown): number;
|
|
441
|
+
/**
|
|
442
|
+
* 判断一个 to 能不能解析。给校验用。
|
|
443
|
+
*
|
|
444
|
+
* 解析失败会当成「已结束」,页面上只会看到一行「已结束」,
|
|
445
|
+
* 运营根本意识不到是自己时间写错了——所以必须在保存前就拦下来。
|
|
446
|
+
*/
|
|
447
|
+
declare function isValidEndTime(to: unknown): boolean;
|
|
441
448
|
/** 算出某个时刻的时间片段 */
|
|
442
449
|
declare function computeParts(endTime: number, now?: number): CountdownParts;
|
|
443
450
|
/** 不给 children 时退化成一行文本,占位符 {d} {h} {hAll} {m} {s} {cs} */
|
|
444
451
|
declare function formatParts(parts: CountdownParts, format?: string): string;
|
|
445
452
|
|
|
446
|
-
export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, type CountdownParts, type CountdownPrecision, type CssStyle, DSL_VERSION, type Dsl, type DslAction, type DslActionBase, type DslCallAction, type DslCloseAction, type DslCloseAllAction, type DslCloseButton, type DslClosePosition, type DslDerived, type DslHandler, type DslLength, type DslNavigateAction, type DslNode, type DslNodeType, type DslOpenAction, type DslRect, type DslRuntime, type DslSequenceAction, type DslSetStateAction, type DslSource, type DslSourceRef, type DslStage, type DslStyle, type DslTrackAction, type DslView, type DslViewType, type Issue, NODE_TYPES, type NormalizedViews, type RenderElement, type RenderLayer, type RenderTree, type RuntimeEmit, type RuntimeEventName, type RuntimeEvents, type RuntimeOptions, SINGLE_VIEW_NAME, type ValidateResult, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
|
|
453
|
+
export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, type CountdownParts, type CountdownPrecision, type CssStyle, DSL_VERSION, type Dsl, type DslAction, type DslActionBase, type DslCallAction, type DslCloseAction, type DslCloseAllAction, type DslCloseButton, type DslClosePosition, type DslDerived, type DslHandler, type DslLength, type DslNavigateAction, type DslNode, type DslNodeType, type DslOpenAction, type DslRect, type DslRuntime, type DslSequenceAction, type DslSetStateAction, type DslSource, type DslSourceRef, type DslStage, type DslStyle, type DslTrackAction, type DslView, type DslViewType, type Issue, NODE_TYPES, type NormalizedViews, type RenderElement, type RenderLayer, type RenderTree, type RuntimeEmit, type RuntimeEventName, type RuntimeEvents, type RuntimeOptions, SINGLE_VIEW_NAME, type ValidateResult, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, isValidEndTime, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
|
package/dist/index.d.ts
CHANGED
|
@@ -438,9 +438,16 @@ interface CountdownParts {
|
|
|
438
438
|
type CountdownPrecision = 's' | 'cs';
|
|
439
439
|
/** 把 to 解析成时间戳。兼容 '2026-09-01 00:00:00' 这种 Safari 不认的格式 */
|
|
440
440
|
declare function parseEndTime(to: unknown): number;
|
|
441
|
+
/**
|
|
442
|
+
* 判断一个 to 能不能解析。给校验用。
|
|
443
|
+
*
|
|
444
|
+
* 解析失败会当成「已结束」,页面上只会看到一行「已结束」,
|
|
445
|
+
* 运营根本意识不到是自己时间写错了——所以必须在保存前就拦下来。
|
|
446
|
+
*/
|
|
447
|
+
declare function isValidEndTime(to: unknown): boolean;
|
|
441
448
|
/** 算出某个时刻的时间片段 */
|
|
442
449
|
declare function computeParts(endTime: number, now?: number): CountdownParts;
|
|
443
450
|
/** 不给 children 时退化成一行文本,占位符 {d} {h} {hAll} {m} {s} {cs} */
|
|
444
451
|
declare function formatParts(parts: CountdownParts, format?: string): string;
|
|
445
452
|
|
|
446
|
-
export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, type CountdownParts, type CountdownPrecision, type CssStyle, DSL_VERSION, type Dsl, type DslAction, type DslActionBase, type DslCallAction, type DslCloseAction, type DslCloseAllAction, type DslCloseButton, type DslClosePosition, type DslDerived, type DslHandler, type DslLength, type DslNavigateAction, type DslNode, type DslNodeType, type DslOpenAction, type DslRect, type DslRuntime, type DslSequenceAction, type DslSetStateAction, type DslSource, type DslSourceRef, type DslStage, type DslStyle, type DslTrackAction, type DslView, type DslViewType, type Issue, NODE_TYPES, type NormalizedViews, type RenderElement, type RenderLayer, type RenderTree, type RuntimeEmit, type RuntimeEventName, type RuntimeEvents, type RuntimeOptions, SINGLE_VIEW_NAME, type ValidateResult, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
|
|
453
|
+
export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, type CountdownParts, type CountdownPrecision, type CssStyle, DSL_VERSION, type Dsl, type DslAction, type DslActionBase, type DslCallAction, type DslCloseAction, type DslCloseAllAction, type DslCloseButton, type DslClosePosition, type DslDerived, type DslHandler, type DslLength, type DslNavigateAction, type DslNode, type DslNodeType, type DslOpenAction, type DslRect, type DslRuntime, type DslSequenceAction, type DslSetStateAction, type DslSource, type DslSourceRef, type DslStage, type DslStyle, type DslTrackAction, type DslView, type DslViewType, type Issue, NODE_TYPES, type NormalizedViews, type RenderElement, type RenderLayer, type RenderTree, type RuntimeEmit, type RuntimeEventName, type RuntimeEvents, type RuntimeOptions, SINGLE_VIEW_NAME, type ValidateResult, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, isValidEndTime, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
|
package/dist/index.js
CHANGED
|
@@ -398,10 +398,24 @@ function parseEndTime(to) {
|
|
|
398
398
|
if (typeof to === "number") return to;
|
|
399
399
|
if (to === void 0 || to === null || to === "") return 0;
|
|
400
400
|
const raw = String(to).trim();
|
|
401
|
+
if (!raw) return 0;
|
|
401
402
|
if (/^\d+$/.test(raw)) return Number(raw);
|
|
402
|
-
|
|
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();
|
|
403
411
|
return isNaN(time) ? 0 : time;
|
|
404
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
|
+
}
|
|
405
419
|
function computeParts(endTime, now = Date.now()) {
|
|
406
420
|
const raw = endTime - now;
|
|
407
421
|
const remain = raw > 0 ? raw : 0;
|
|
@@ -954,10 +968,13 @@ function resolveCountdown(node, key, style, context, input, countdowns) {
|
|
|
954
968
|
const parts = computeParts(endTime);
|
|
955
969
|
countdowns.endTimes.push(endTime);
|
|
956
970
|
if (node.precision === "cs") countdowns.precision = "cs";
|
|
957
|
-
if (
|
|
971
|
+
if (endTime && node.onEnd) {
|
|
958
972
|
const token = `${key}@${endTime}`;
|
|
959
|
-
|
|
960
|
-
|
|
973
|
+
const status = input.countdownEnds.get(token);
|
|
974
|
+
if (status === void 0) {
|
|
975
|
+
input.countdownEnds.set(token, parts.ended ? "done" : "waiting");
|
|
976
|
+
} else if (status === "waiting" && parts.ended) {
|
|
977
|
+
input.countdownEnds.set(token, "done");
|
|
961
978
|
input.dispatch(node.onEnd, context);
|
|
962
979
|
}
|
|
963
980
|
}
|
|
@@ -1017,7 +1034,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1017
1034
|
let loadFailed = false;
|
|
1018
1035
|
let destroyed = false;
|
|
1019
1036
|
const listeners = /* @__PURE__ */ new Set();
|
|
1020
|
-
const
|
|
1037
|
+
const countdownEnds = /* @__PURE__ */ new Map();
|
|
1021
1038
|
const notify = () => {
|
|
1022
1039
|
if (destroyed) return;
|
|
1023
1040
|
listeners.forEach((fn) => fn());
|
|
@@ -1151,7 +1168,7 @@ function createRuntime(dsl, options = {}) {
|
|
|
1151
1168
|
dispatch,
|
|
1152
1169
|
setState,
|
|
1153
1170
|
closeTop,
|
|
1154
|
-
|
|
1171
|
+
countdownEnds
|
|
1155
1172
|
});
|
|
1156
1173
|
ticker.sync(tree.countdownEndTimes, tree.countdownPrecision);
|
|
1157
1174
|
return tree;
|
|
@@ -1521,7 +1538,14 @@ function validateNodeByType(node, path, ctx) {
|
|
|
1521
1538
|
}
|
|
1522
1539
|
}
|
|
1523
1540
|
if (node.type === "countdown") {
|
|
1524
|
-
if (!node.to)
|
|
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
|
+
}
|
|
1525
1549
|
if (node.precision !== void 0 && ["s", "cs"].indexOf(node.precision) === -1) {
|
|
1526
1550
|
add(`${path}.precision`, "precision \u53EA\u80FD\u662F 's'\uFF08\u6BCF\u79D2\uFF09\u6216 'cs'\uFF08\u5398\u79D2\uFF0C\u9010\u5E27\u5237\u65B0\uFF09");
|
|
1527
1551
|
}
|
|
@@ -1601,4 +1625,4 @@ function formatIssues(issues) {
|
|
|
1601
1625
|
return issues.map((item) => item.path ? `${item.path}: ${item.message}` : item.message).join("\n");
|
|
1602
1626
|
}
|
|
1603
1627
|
|
|
1604
|
-
export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, DSL_VERSION, NODE_TYPES, SINGLE_VIEW_NAME, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };
|
|
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 };
|