@yaoxiu/marketing-dsl 1.2.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.d.ts CHANGED
@@ -1,285 +1,5 @@
1
- /**
2
- * DSL 的类型定义。
3
- *
4
- * 分两组:
5
- * - Dsl* 是运营写的配置,也就是存进数据库的那份 JSON
6
- * - Render* 是 core 算完之后交给框架层的渲染树,纯数据,跟框架无关
7
- *
8
- * 框架层只认 Render*,永远不该去读 Dsl*——一旦读了,解析逻辑就又漏回渲染层了。
9
- */
10
- type DslViewType = 'popup' | 'banner' | 'notice';
11
- type DslNodeType = 'box' | 'flex' | 'repeat' | 'image' | 'text' | 'button' | 'tabs' | 'countdown';
12
- /** 长度:数字按 px,字符串原样交给 CSS,可以带 {{ }} */
13
- type DslLength = number | string;
14
- /** rect: [x, y, width, height],绝对定位容器里用 */
15
- type DslRect = [DslLength, DslLength, DslLength, DslLength];
16
- /** 样式对象,键必须在白名单内,值可以带 {{ }} */
17
- type DslStyle = Record<string, unknown>;
18
- interface DslActionBase {
19
- type: string;
20
- }
21
- interface DslNavigateAction extends DslActionBase {
22
- type: 'navigate';
23
- url: string;
24
- target?: '_self' | '_blank';
25
- }
26
- interface DslCloseAction extends DslActionBase {
27
- type: 'close';
28
- reason?: string;
29
- }
30
- interface DslCloseAllAction extends DslActionBase {
31
- type: 'closeAll';
32
- reason?: string;
33
- }
34
- interface DslOpenAction extends DslActionBase {
35
- type: 'open';
36
- view: string;
37
- mode?: 'stack' | 'replace';
38
- }
39
- interface DslSetStateAction extends DslActionBase {
40
- type: 'setState';
41
- key: string;
42
- value: unknown;
43
- }
44
- interface DslTrackAction extends DslActionBase {
45
- type: 'track';
46
- event: string;
47
- params?: Record<string, unknown>;
48
- }
49
- /** 调用宿主注册的方法,名字必须在 handlers 白名单内 */
50
- interface DslCallAction extends DslActionBase {
51
- type: 'call';
52
- name: string;
53
- params?: Record<string, unknown>;
54
- }
55
- interface DslSequenceAction extends DslActionBase {
56
- type: 'sequence';
57
- actions: DslAction[];
58
- }
59
- type DslAction = DslNavigateAction | DslCloseAction | DslCloseAllAction | DslOpenAction | DslSetStateAction | DslTrackAction | DslCallAction | DslSequenceAction;
60
- interface DslNode {
61
- id?: string;
62
- type: DslNodeType;
63
- rect?: DslRect;
64
- style?: DslStyle;
65
- /** 表达式,为假时整个节点不渲染 */
66
- visibleWhen?: string;
67
- action?: DslAction;
68
- /** box / flex / countdown */
69
- children?: DslNode[];
70
- /** repeat / tabs:数组来源表达式 */
71
- bind?: string;
72
- /** repeat */
73
- template?: DslNode;
74
- itemName?: string;
75
- indexName?: string;
76
- /** tabs */
77
- stateKey?: string;
78
- labelField?: string;
79
- itemStyle?: DslStyle;
80
- activeItemStyle?: DslStyle;
81
- /** image */
82
- src?: string;
83
- /** text */
84
- content?: string;
85
- /** button */
86
- text?: string;
87
- /** countdown */
88
- to?: string;
89
- precision?: 's' | 'cs';
90
- as?: string;
91
- format?: string;
92
- endText?: string;
93
- onEnd?: DslAction;
94
- }
95
- type DslClosePosition = 'top-right' | 'top-left' | 'top-center' | 'bottom-right' | 'bottom-left' | 'bottom-center';
96
- interface DslCloseButton {
97
- show?: boolean;
98
- position?: DslClosePosition;
99
- /** [x, y],负值把按钮移到弹窗外面 */
100
- offset?: [DslLength, DslLength];
101
- size?: DslLength;
102
- icon?: string;
103
- image?: string;
104
- style?: DslStyle;
105
- }
106
- interface DslStage {
107
- width?: DslLength;
108
- height?: DslLength;
109
- /** absolute(默认)子节点用 rect 定位;flow 子节点按 flex 排 */
110
- layout?: 'absolute' | 'flow';
111
- mask?: boolean;
112
- maskClosable?: boolean;
113
- closeButton?: DslCloseButton;
114
- style?: DslStyle;
115
- /** 曝光埋点:数据就绪、视图真正展示时触发一次 */
116
- onShow?: DslAction;
117
- /** 关闭埋点:点 X、点遮罩、close 动作、被 replace 顶掉都会触发 */
118
- onClose?: DslAction;
119
- }
120
- interface DslView {
121
- type: DslViewType;
122
- stage: DslStage;
123
- nodes: DslNode[];
124
- }
125
- /** 后端数据源引用,名字必须在 sources 白名单内 */
126
- interface DslSourceRef {
127
- $source: string;
128
- params?: Record<string, unknown>;
129
- }
130
- interface DslDerived {
131
- /** data 里的数组字段名 */
132
- list: string;
133
- /** state 里的下标字段名 */
134
- indexBy: string;
135
- }
136
- /** 一份完整配置。单视图直接写 type/stage/nodes,多视图写 views + entry */
137
- interface Dsl extends Partial<DslView> {
138
- version: number;
139
- meta?: {
140
- name?: string;
141
- [key: string]: unknown;
142
- };
143
- data?: Record<string, unknown | DslSourceRef>;
144
- state?: Record<string, unknown>;
145
- derived?: Record<string, DslDerived>;
146
- views?: Record<string, DslView>;
147
- entry?: string;
148
- }
149
- /** 已经算好的行内样式,键是 CSS 属性名(驼峰),值是最终字符串 */
150
- type CssStyle = Record<string, string>;
151
- interface RenderElement {
152
- /** 稳定 key,框架层做列表 diff 用 */
153
- key: string;
154
- /** 画成什么。div 带 text 就是文本节点,带 children 就是容器 */
155
- tag: 'div' | 'img';
156
- /**
157
- * 类名,如 "dsl-node dsl-text is-clickable"。
158
- * 不参与样式(样式全在 style 里),纯粹是留给调试和宿主微调的钩子。
159
- * 由 core 统一生成,不让各框架壳各拼一套,否则 DOM 结构会慢慢跑偏。
160
- */
161
- className: string;
162
- style: CssStyle;
163
- text?: string;
164
- src?: string;
165
- /**
166
- * 有值才是可点的,动作和上下文都已经绑好,框架层直接挂上去即可。
167
- *
168
- * 【框架层必须遵守】挂上去时要阻止冒泡。
169
- * 父子都可点是常见排版——公告条整条点开弹窗、行末 × 关闭公告条——
170
- * 不阻止的话点 × 会连带触发外层,关掉的瞬间又弹出来。
171
- * 没有 onClick 的节点不要绑任何事件,让它正常冒泡到有 onClick 的祖先。
172
- */
173
- onClick?: () => void;
174
- children?: RenderElement[];
175
- }
176
- /**
177
- * 一个视图层。框架层照着这个结构套四层 div 就行,不需要自带任何 CSS:
178
- *
179
- * div(layerStyle)
180
- * div(maskStyle) ← mask 为 true 时才画
181
- * div(scrollStyle)
182
- * div(stageStyle)
183
- * div(clipStyle) ← 圆角裁切,关闭按钮留在外面才能溢出
184
- * ...nodes
185
- * closeButton ← 有配才有
186
- */
187
- interface RenderLayer {
188
- /** 视图名,同时用作 key */
189
- name: string;
190
- type: DslViewType;
191
- isTop: boolean;
192
- /** 画不画遮罩。只有栈顶的弹窗层才为 true */
193
- mask: boolean;
194
- onMaskClick?: () => void;
195
- layerStyle: CssStyle;
196
- maskStyle: CssStyle;
197
- scrollStyle: CssStyle;
198
- stageStyle: CssStyle;
199
- clipStyle: CssStyle;
200
- /** 关闭按钮,没配就是 undefined */
201
- closeButton?: RenderElement;
202
- nodes: RenderElement[];
203
- }
204
- interface RenderTree {
205
- /** 数据没回来或加载失败时为 false,框架层什么都不画 */
206
- ready: boolean;
207
- /** 有弹窗层时框架层需要撑满宿主容器 */
208
- hasPopup: boolean;
209
- /** 根容器样式,已按 hasPopup 算好 */
210
- rootStyle: CssStyle;
211
- layers: RenderLayer[];
212
- /** 这一轮里所有倒计时的结束时间戳,运行时据此决定要不要起定时器 */
213
- countdownEndTimes: number[];
214
- /** 只要有一个倒计时要厘秒,整体就按厘秒刷 */
215
- countdownPrecision: 's' | 'cs';
216
- }
217
- type DslSource = (params: Record<string, unknown>, user: Record<string, unknown>) => unknown | Promise<unknown>;
218
- type DslHandler = (params: Record<string, unknown>) => void;
219
- interface RuntimeEvents {
220
- ready: {
221
- keys: string[];
222
- };
223
- close: {
224
- reason: string;
225
- };
226
- track: {
227
- event: string;
228
- params: Record<string, unknown>;
229
- };
230
- navigate: {
231
- url: string;
232
- target: string;
233
- };
234
- call: {
235
- name: string;
236
- params: Record<string, unknown>;
237
- };
238
- 'state-change': Record<string, unknown>;
239
- 'view-change': {
240
- view: string;
241
- mode: string;
242
- stack: string[];
243
- closed?: string;
244
- };
245
- open: {
246
- view: string;
247
- mode: string;
248
- };
249
- error: {
250
- type: 'unknown-source';
251
- name: string;
252
- } | {
253
- type: 'unknown-view';
254
- name: string;
255
- } | {
256
- type: 'unknown-handler';
257
- name: string;
258
- } | {
259
- type: 'unknown-action';
260
- action: string;
261
- } | {
262
- type: 'unsafe-url';
263
- raw: string;
264
- } | {
265
- type: 'data-source-failed';
266
- message: string;
267
- };
268
- }
269
- type RuntimeEventName = keyof RuntimeEvents;
270
- type RuntimeEmit = <K extends RuntimeEventName>(event: K, payload: RuntimeEvents[K]) => void;
271
- interface RuntimeOptions {
272
- /** 宿主注入的用户上下文,配置里用 {{ user.xxx }} 读 */
273
- user?: Record<string, unknown>;
274
- /** 数据源白名单 */
275
- sources?: Record<string, DslSource>;
276
- /** call 动作的方法白名单 */
277
- handlers?: Record<string, DslHandler>;
278
- /** 编辑态:动作只上报不真正执行 */
279
- editMode?: boolean;
280
- /** 所有事件都从这里出去,宿主自己决定怎么处理 */
281
- emit?: RuntimeEmit;
282
- }
1
+ import { D as Dsl, R as RuntimeOptions, a as RenderTree, b as DslView, c as DslStyle, C as CssStyle } from './types-BgUaJUAu.js';
2
+ export { q as DslAction, h as DslActionBase, o as DslCallAction, j as DslCloseAction, k as DslCloseAllAction, t as DslCloseButton, s as DslClosePosition, w as DslDerived, A as DslHandler, f as DslLength, i as DslNavigateAction, r as DslNode, e as DslNodeType, l as DslOpenAction, g as DslRect, p as DslSequenceAction, m as DslSetStateAction, z as DslSource, v as DslSourceRef, u as DslStage, n as DslTrackAction, d as DslViewType, x as RenderElement, y as RenderLayer, F as RuntimeEmit, E as RuntimeEventName, B as RuntimeEvents } from './types-BgUaJUAu.js';
283
3
 
284
4
  /**
285
5
  * 运行时。
@@ -334,6 +54,13 @@ interface ValidateResult {
334
54
  declare const DSL_VERSION = 1;
335
55
  declare const NODE_TYPES: string[];
336
56
  declare const ACTION_TYPES: string[];
57
+ /**
58
+ * 埋点事件名格式:小写字母开头,后接小写字母 / 数字 / 下划线,总长 3~64。
59
+ *
60
+ * 只校验格式、不做白名单——事件名由运营自由定义,后端按前缀聚合,
61
+ * 格式统一才能聚合得干净(中文、驼峰、中划线混着来就没法分组)。
62
+ */
63
+ declare const TRACK_EVENT_PATTERN: RegExp;
337
64
  declare const CLOSE_POSITIONS: string[];
338
65
  declare function validate(dsl: Dsl | unknown): ValidateResult;
339
66
  /** 把校验结果拼成可以直接展示的文本 */
@@ -438,9 +165,16 @@ interface CountdownParts {
438
165
  type CountdownPrecision = 's' | 'cs';
439
166
  /** 把 to 解析成时间戳。兼容 '2026-09-01 00:00:00' 这种 Safari 不认的格式 */
440
167
  declare function parseEndTime(to: unknown): number;
168
+ /**
169
+ * 判断一个 to 能不能解析。给校验用。
170
+ *
171
+ * 解析失败会当成「已结束」,页面上只会看到一行「已结束」,
172
+ * 运营根本意识不到是自己时间写错了——所以必须在保存前就拦下来。
173
+ */
174
+ declare function isValidEndTime(to: unknown): boolean;
441
175
  /** 算出某个时刻的时间片段 */
442
176
  declare function computeParts(endTime: number, now?: number): CountdownParts;
443
177
  /** 不给 children 时退化成一行文本,占位符 {d} {h} {hAll} {m} {s} {cs} */
444
178
  declare function formatParts(parts: CountdownParts, format?: string): string;
445
179
 
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 };
180
+ export { ACTION_TYPES, ALLOWED_STYLE_KEYS, CLOSE_POSITIONS, type CountdownParts, type CountdownPrecision, CssStyle, DSL_VERSION, Dsl, type DslRuntime, DslStyle, DslView, type Issue, NODE_TYPES, type NormalizedViews, RenderTree, RuntimeOptions, SINGLE_VIEW_NAME, TRACK_EVENT_PATTERN, type ValidateResult, check, computeParts, createRuntime, evaluate, formatIssues, formatParts, interpolate, interpolateDeep, isLength, isValidEndTime, normalizeViews, parseEndTime, safeImageUrl, safeUrl, toCssStyle, toLength, validate };