@blocklet/pages-kit-core 0.5.29 → 0.5.31

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.
@@ -1,3 +1 @@
1
- export * from './types';
2
- export * from './core';
3
- export * from './dataset';
1
+ export * from './template-model';
package/lib/cjs/index.js CHANGED
@@ -14,6 +14,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- __exportStar(require("./types"), exports);
18
- __exportStar(require("./core"), exports);
19
- __exportStar(require("./dataset"), exports);
17
+ // export * from './types';
18
+ // export * from './core';
19
+ // export * from './dataset';
20
+ __exportStar(require("./template-model"), exports);
package/lib/cjs/page.js CHANGED
@@ -45,7 +45,6 @@ class Page {
45
45
  backgroundColor: this.data.meta.backgroundColor,
46
46
  ...input,
47
47
  };
48
- // @FIXME: 这个 map 应该是不需要的
49
48
  // 使用 Block 实例渲染 sections
50
49
  const sections = await Promise.all(this.data.sections.map(async (section) => {
51
50
  try {
@@ -0,0 +1,124 @@
1
+ export declare const DEFAULT_CHILDREN_PROPERTIES: string[];
2
+ export declare const PAGES_KIT_CHILDREN_PROPERTIES: ((node: Node) => any)[];
3
+ type WalkStrategy = 'pre' | 'post' | 'breadth';
4
+ export type ChildrenResolver = string | ((node: Node, locale?: string) => any[]);
5
+ interface TemplateModelConfig {
6
+ childrenProperties?: ChildrenResolver[];
7
+ locale?: string;
8
+ }
9
+ interface NodeModel {
10
+ [key: string]: any;
11
+ }
12
+ interface WalkOptions {
13
+ strategy?: WalkStrategy;
14
+ }
15
+ interface WalkFunction<T = any> {
16
+ (node: Node): boolean | void | T;
17
+ }
18
+ /**
19
+ * 表示树中的一个节点
20
+ */
21
+ export declare class Node {
22
+ parent?: Node;
23
+ children: Node[];
24
+ config: TemplateModelConfig;
25
+ model: NodeModel;
26
+ constructor(config: TemplateModelConfig, model: NodeModel);
27
+ isRoot(): boolean;
28
+ hasChildren(): boolean;
29
+ getPath(): Node[];
30
+ walk(options: WalkOptions, fn?: WalkFunction, ctx?: any): void;
31
+ walk(fn: WalkFunction, ctx?: any): void;
32
+ all(options: WalkOptions, fn?: WalkFunction, ctx?: any): Node[];
33
+ all(fn?: WalkFunction, ctx?: any): Node[];
34
+ first(options: WalkOptions, fn?: WalkFunction, ctx?: any): Node | undefined;
35
+ first(fn?: WalkFunction, ctx?: any): Node | undefined;
36
+ /**
37
+ * 在所有子节点源中查找节点
38
+ */
39
+ findAll(predicate: WalkFunction): Node[];
40
+ private parseArgs;
41
+ /**
42
+ * 获取节点在父节点中的索引
43
+ */
44
+ getIndex(): number;
45
+ /**
46
+ * 获取节点完整的JSON路径表示
47
+ * 返回一个能直接访问JSON对象的路径数组
48
+ */
49
+ getJsonPath(): string[];
50
+ /**
51
+ * 获取节点导出数据
52
+ */
53
+ getExportData(): NodeModel;
54
+ /**
55
+ * 获取深拷贝
56
+ */
57
+ private _cloneObject;
58
+ }
59
+ /**
60
+ * 树模型类,用于将普通对象转换为树结构
61
+ */
62
+ export declare class TemplateModel {
63
+ private config;
64
+ private componentsById;
65
+ private rootComponentIds;
66
+ originalModel: NodeModel | null;
67
+ parseModel: NodeModel | null;
68
+ root: Node | null;
69
+ constructor(config?: TemplateModelConfig);
70
+ /**
71
+ * 添加子节点解析器
72
+ */
73
+ addChildrenResolver(resolver: ChildrenResolver): void;
74
+ /**
75
+ * 新增: 构建扁平索引
76
+ */
77
+ private _buildFlatIndex;
78
+ parse(model: NodeModel, { isClone, }?: {
79
+ isClone?: boolean;
80
+ }): Node;
81
+ /**
82
+ * 新增: 根据ID快速获取组件节点
83
+ */
84
+ getComponentById(id: string): Node | null;
85
+ /**
86
+ * 新增: 获取组件所有父节点
87
+ */
88
+ getComponentAncestors(id: string): Node[];
89
+ /**
90
+ * 新增: 获取组件的子组件
91
+ */
92
+ getChildComponents(id: string): Node[];
93
+ /**
94
+ * 新增: 获取组件的兄弟组件
95
+ */
96
+ getSiblingComponents(id: string): Node[];
97
+ findAll(tree: Node, predicate: WalkFunction): Node[];
98
+ /**
99
+ * 新增: 获取所有根组件
100
+ */
101
+ getRootComponents(): Node[];
102
+ /**
103
+ * 新增: 检查组件是否存在
104
+ */
105
+ hasComponent(id: string): boolean;
106
+ /**
107
+ * 获取组件的完整JSON路径表示
108
+ * 返回一个能直接访问JSON对象的路径数组
109
+ */
110
+ getComponentJsonPath(id: string): string[];
111
+ /**
112
+ * 获取根节点
113
+ */
114
+ getRoot(): Node | null;
115
+ /**
116
+ * 获取根节点导出数据
117
+ */
118
+ getRootExportData(): NodeModel | null;
119
+ /**
120
+ * 获取深拷贝
121
+ */
122
+ private _cloneObject;
123
+ }
124
+ export default TemplateModel;
@@ -0,0 +1,475 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TemplateModel = exports.Node = exports.PAGES_KIT_CHILDREN_PROPERTIES = exports.DEFAULT_CHILDREN_PROPERTIES = void 0;
7
+ const cloneDeep_1 = __importDefault(require("lodash/cloneDeep"));
8
+ exports.DEFAULT_CHILDREN_PROPERTIES = ['children'];
9
+ exports.PAGES_KIT_CHILDREN_PROPERTIES = [
10
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
11
+ (node) => {
12
+ if (Object.keys(node.model.sections || {}).length) {
13
+ return node.model.sectionIds?.map((id) => node.model.sections?.[id]);
14
+ }
15
+ return [];
16
+ },
17
+ ];
18
+ /**
19
+ * 辅助函数:根据属性路径获取值
20
+ */
21
+ function getValueByPath(obj, path) {
22
+ if (!path || !obj)
23
+ return undefined;
24
+ return path.split('.').reduce((o, key) => {
25
+ return o && typeof o === 'object' && key in o ? o[key] : undefined;
26
+ }, obj);
27
+ }
28
+ /**
29
+ * 表示树中的一个节点
30
+ */
31
+ class Node {
32
+ parent;
33
+ children = [];
34
+ config;
35
+ model;
36
+ constructor(config, model) {
37
+ this.config = config;
38
+ this.model = model;
39
+ }
40
+ isRoot() {
41
+ return this.parent === undefined;
42
+ }
43
+ hasChildren() {
44
+ return this.children.length > 0;
45
+ }
46
+ getPath() {
47
+ const path = [];
48
+ const addToPath = (node) => {
49
+ path.unshift(node);
50
+ if (!node.isRoot() && node.parent) {
51
+ addToPath(node.parent);
52
+ }
53
+ };
54
+ addToPath(this);
55
+ return path;
56
+ }
57
+ walk(...args) {
58
+ const parsedArgs = this.parseArgs(...args);
59
+ const strategy = parsedArgs.options.strategy;
60
+ walkStrategies[strategy].call(this, parsedArgs.fn, parsedArgs.ctx);
61
+ }
62
+ all(...args) {
63
+ const all = [];
64
+ const parsedArgs = this.parseArgs(...args);
65
+ parsedArgs.fn = parsedArgs.fn || createConstantFunction(true);
66
+ walkStrategies[parsedArgs.options.strategy].call(this, (node) => {
67
+ if (parsedArgs.fn.call(parsedArgs.ctx, node)) {
68
+ all.push(node);
69
+ }
70
+ return undefined;
71
+ }, parsedArgs.ctx);
72
+ return all;
73
+ }
74
+ first(...args) {
75
+ let first;
76
+ const parsedArgs = this.parseArgs(...args);
77
+ parsedArgs.fn = parsedArgs.fn || createConstantFunction(true);
78
+ walkStrategies[parsedArgs.options.strategy].call(this, (node) => {
79
+ if (parsedArgs.fn.call(parsedArgs.ctx, node)) {
80
+ first = node;
81
+ return false;
82
+ }
83
+ return undefined;
84
+ }, parsedArgs.ctx);
85
+ return first;
86
+ }
87
+ /**
88
+ * 在所有子节点源中查找节点
89
+ */
90
+ findAll(predicate) {
91
+ // 首先使用标准遍历找到直接子节点中符合条件的
92
+ const standardResults = this.all(predicate);
93
+ return standardResults;
94
+ }
95
+ parseArgs(...args) {
96
+ const parsedArgs = {
97
+ options: {},
98
+ fn: () => true,
99
+ };
100
+ if (args.length === 1) {
101
+ if (typeof args[0] === 'function') {
102
+ const [fn] = args;
103
+ parsedArgs.fn = fn;
104
+ }
105
+ else {
106
+ const [options] = args;
107
+ parsedArgs.options = options;
108
+ }
109
+ }
110
+ else if (args.length === 2) {
111
+ if (typeof args[0] === 'function') {
112
+ const [fn, ctx] = args;
113
+ parsedArgs.fn = fn;
114
+ parsedArgs.ctx = ctx;
115
+ }
116
+ else {
117
+ const [options, fn] = args;
118
+ parsedArgs.options = options;
119
+ parsedArgs.fn = fn;
120
+ }
121
+ }
122
+ else if (args.length >= 3) {
123
+ const [options, fn, ctx] = args;
124
+ parsedArgs.options = options;
125
+ parsedArgs.fn = fn;
126
+ parsedArgs.ctx = ctx;
127
+ }
128
+ parsedArgs.options = parsedArgs.options || {};
129
+ if (!parsedArgs.options.strategy) {
130
+ parsedArgs.options.strategy = 'pre';
131
+ }
132
+ const strategy = parsedArgs.options.strategy;
133
+ if (!walkStrategies[strategy]) {
134
+ throw new Error("Unknown tree walk strategy. Valid strategies are 'pre' [default], 'post' and 'breadth'.");
135
+ }
136
+ return parsedArgs;
137
+ }
138
+ /**
139
+ * 获取节点在父节点中的索引
140
+ */
141
+ getIndex() {
142
+ return this.parent?.children.indexOf(this) || 0;
143
+ }
144
+ /**
145
+ * 获取节点完整的JSON路径表示
146
+ * 返回一个能直接访问JSON对象的路径数组
147
+ */
148
+ getJsonPath() {
149
+ const jsonPath = [];
150
+ const buildJsonPath = (node) => {
151
+ if (!node.parent) {
152
+ // 根节点
153
+ return;
154
+ }
155
+ const { parent } = node;
156
+ // 先构建父节点的路径
157
+ buildJsonPath(parent);
158
+ // 查找当前节点在父节点中的路径
159
+ if (Array.isArray(parent.config.childrenProperties) && parent.config.childrenProperties.length > 0) {
160
+ for (const resolver of parent.config.childrenProperties) {
161
+ if (typeof resolver === 'string') {
162
+ // 字符串路径
163
+ const pathParts = resolver.split('.');
164
+ let current = parent.model;
165
+ let isValid = true;
166
+ // 检查路径是否有效
167
+ for (let i = 0; i < pathParts.length; i++) {
168
+ const part = pathParts[i];
169
+ if (!part || !current || typeof current !== 'object' || !(part in current)) {
170
+ isValid = false;
171
+ break;
172
+ }
173
+ current = current[part];
174
+ }
175
+ if (isValid && Array.isArray(current)) {
176
+ // 在数组中查找当前节点
177
+ const index = current.findIndex((item) => item === node.model);
178
+ if (index !== -1) {
179
+ jsonPath.push(...pathParts, index.toString());
180
+ return;
181
+ }
182
+ }
183
+ }
184
+ else if (typeof resolver === 'function') {
185
+ // 对于函数解析器,尝试通过特殊情况处理
186
+ // 处理layout-block的情况
187
+ if (parent.model.component === 'layout-block' && parent.model.sections) {
188
+ const index = parent.model.sections.findIndex((section) => section === node.model);
189
+ if (index !== -1) {
190
+ jsonPath.push('sections', index.toString());
191
+ return;
192
+ }
193
+ }
194
+ // 处理根节点的sections情况
195
+ if (parent.isRoot() && parent.model.sections) {
196
+ const sections = Object.values(parent.model.sections);
197
+ const index = sections.findIndex((section) => section === node.model);
198
+ if (index !== -1 && parent.model.sections) {
199
+ const keys = Object.keys(parent.model.sections);
200
+ if (index < keys.length) {
201
+ const key = keys[index];
202
+ if (key) {
203
+ jsonPath.push('sections', key);
204
+ return;
205
+ }
206
+ }
207
+ }
208
+ }
209
+ }
210
+ }
211
+ }
212
+ // 默认处理方式
213
+ if (node.model.id && parent.model.sections && node.model.id in parent.model.sections) {
214
+ jsonPath.push('sections', node.model.id);
215
+ }
216
+ else {
217
+ // 最后尝试查找节点在children数组中的位置
218
+ const index = parent.children.indexOf(node);
219
+ if (index !== -1 && Array.isArray(parent.model.children)) {
220
+ jsonPath.push('children', index.toString());
221
+ }
222
+ }
223
+ };
224
+ buildJsonPath(this);
225
+ return jsonPath;
226
+ }
227
+ /**
228
+ * 获取节点导出数据
229
+ */
230
+ getExportData() {
231
+ return this._cloneObject(this.model);
232
+ }
233
+ /**
234
+ * 获取深拷贝
235
+ */
236
+ _cloneObject(obj) {
237
+ return (0, cloneDeep_1.default)(obj);
238
+ }
239
+ }
240
+ exports.Node = Node;
241
+ // 定义遍历策略
242
+ const walkStrategies = {
243
+ pre: function depthFirstPreOrder(callback, context) {
244
+ let keepGoing = callback.call(context, this);
245
+ for (let i = 0, childCount = this.children.length; i < childCount; i++) {
246
+ if (keepGoing === false) {
247
+ return false;
248
+ }
249
+ // 类型安全调用
250
+ const child = this.children[i];
251
+ if (child instanceof Node) {
252
+ keepGoing = depthFirstPreOrder.call(child, callback, context);
253
+ }
254
+ }
255
+ return keepGoing;
256
+ },
257
+ post: function depthFirstPostOrder(callback, context) {
258
+ let keepGoing;
259
+ for (let i = 0, childCount = this.children.length; i < childCount; i++) {
260
+ // 类型安全调用
261
+ const child = this.children[i];
262
+ if (child instanceof Node) {
263
+ keepGoing = depthFirstPostOrder.call(child, callback, context);
264
+ if (keepGoing === false) {
265
+ return false;
266
+ }
267
+ }
268
+ }
269
+ keepGoing = callback.call(context, this);
270
+ return keepGoing;
271
+ },
272
+ breadth: function breadthFirst(callback, context) {
273
+ const queue = [this];
274
+ const processQueue = () => {
275
+ if (queue.length === 0) {
276
+ return;
277
+ }
278
+ const node = queue.shift();
279
+ if (!node)
280
+ return;
281
+ for (let i = 0, childCount = node.children.length; i < childCount; i++) {
282
+ const child = node.children[i];
283
+ if (child instanceof Node) {
284
+ queue.push(child);
285
+ }
286
+ }
287
+ if (callback.call(context, node) !== false) {
288
+ processQueue();
289
+ }
290
+ };
291
+ processQueue();
292
+ },
293
+ };
294
+ function createConstantFunction(result) {
295
+ return () => result;
296
+ }
297
+ /**
298
+ * 树模型类,用于将普通对象转换为树结构
299
+ */
300
+ class TemplateModel {
301
+ config;
302
+ componentsById = {};
303
+ rootComponentIds = [];
304
+ originalModel = null;
305
+ parseModel = null;
306
+ root = null;
307
+ constructor(config = {}) {
308
+ this.config = {};
309
+ // 处理子节点解析配置
310
+ if (config.childrenProperties) {
311
+ // 使用多源配置
312
+ this.config.childrenProperties = config.childrenProperties;
313
+ }
314
+ else {
315
+ // 默认使用children
316
+ this.config.childrenProperties = exports.DEFAULT_CHILDREN_PROPERTIES;
317
+ }
318
+ this.config.locale = config.locale || 'en';
319
+ }
320
+ /**
321
+ * 添加子节点解析器
322
+ */
323
+ addChildrenResolver(resolver) {
324
+ if (!this.config.childrenProperties) {
325
+ this.config.childrenProperties = [];
326
+ }
327
+ this.config.childrenProperties.push(resolver);
328
+ }
329
+ /**
330
+ * 新增: 构建扁平索引
331
+ */
332
+ _buildFlatIndex(rootNode) {
333
+ // 清空现有索引
334
+ this.componentsById = {};
335
+ this.rootComponentIds = [];
336
+ // 如果根节点有ID,将其加入根组件列表
337
+ if (rootNode.model.id) {
338
+ this.rootComponentIds.push(rootNode.model.id);
339
+ }
340
+ // 遍历所有节点建立索引
341
+ rootNode.walk((node) => {
342
+ if (node.model.id) {
343
+ this.componentsById[node.model.id] = node;
344
+ }
345
+ return undefined;
346
+ });
347
+ }
348
+ parse(model, { isClone = false, } = {}) {
349
+ this.originalModel = model;
350
+ // 创建深拷贝,避免直接修改原始对象
351
+ const realModel = isClone ? this._cloneObject(model) : model;
352
+ if (!(realModel instanceof Object)) {
353
+ throw new TypeError('Model must be of type object.');
354
+ }
355
+ const node = new Node(this.config, realModel);
356
+ // 获取子节点模型
357
+ const childrenModels = [];
358
+ if (Array.isArray(this.config.childrenProperties)) {
359
+ // 使用解析器获取子节点
360
+ for (const resolver of this.config.childrenProperties) {
361
+ if (typeof resolver === 'string') {
362
+ // 字符串路径
363
+ const value = getValueByPath(realModel, resolver);
364
+ if (Array.isArray(value)) {
365
+ childrenModels.push(...value);
366
+ }
367
+ }
368
+ else if (typeof resolver === 'function') {
369
+ // 函数解析器 - 创建临时节点以便调用
370
+ const tempNode = new Node(this.config, realModel);
371
+ const value = resolver(tempNode, this.config.locale);
372
+ if (Array.isArray(value)) {
373
+ childrenModels.push(...value);
374
+ }
375
+ }
376
+ }
377
+ }
378
+ // 解析所有子节点
379
+ for (let i = 0; i < childrenModels.length; i++) {
380
+ const childNode = this.parse(childrenModels[i], {
381
+ isClone: false,
382
+ });
383
+ childNode.parent = node;
384
+ node.children.push(childNode);
385
+ }
386
+ // 新增: 构建扁平索引
387
+ this._buildFlatIndex(node);
388
+ this.root = node;
389
+ this.parseModel = realModel;
390
+ return node;
391
+ }
392
+ /**
393
+ * 新增: 根据ID快速获取组件节点
394
+ */
395
+ getComponentById(id) {
396
+ return this.componentsById[id] || null;
397
+ }
398
+ /**
399
+ * 新增: 获取组件所有父节点
400
+ */
401
+ getComponentAncestors(id) {
402
+ const node = this.getComponentById(id);
403
+ if (!node)
404
+ return [];
405
+ // 使用现有getPath方法,但排除自身
406
+ const path = node.getPath();
407
+ return path.slice(0, -1);
408
+ }
409
+ /**
410
+ * 新增: 获取组件的子组件
411
+ */
412
+ getChildComponents(id) {
413
+ const node = this.getComponentById(id);
414
+ if (!node)
415
+ return [];
416
+ return node.children;
417
+ }
418
+ /**
419
+ * 新增: 获取组件的兄弟组件
420
+ */
421
+ getSiblingComponents(id) {
422
+ const node = this.getComponentById(id);
423
+ if (!node || !node.parent)
424
+ return [];
425
+ return node.parent.children.filter((child) => child !== node);
426
+ }
427
+ // 新增:递归查找所有匹配节点(包括嵌套源)
428
+ findAll(tree, predicate) {
429
+ return tree.findAll(predicate);
430
+ }
431
+ /**
432
+ * 新增: 获取所有根组件
433
+ */
434
+ getRootComponents() {
435
+ return this.rootComponentIds.map((id) => this.componentsById[id]).filter((item) => item !== undefined);
436
+ }
437
+ /**
438
+ * 新增: 检查组件是否存在
439
+ */
440
+ hasComponent(id) {
441
+ return !!this.componentsById[id];
442
+ }
443
+ /**
444
+ * 获取组件的完整JSON路径表示
445
+ * 返回一个能直接访问JSON对象的路径数组
446
+ */
447
+ getComponentJsonPath(id) {
448
+ const node = this.getComponentById(id);
449
+ if (!node)
450
+ return [];
451
+ return node.getJsonPath();
452
+ }
453
+ /**
454
+ * 获取根节点
455
+ */
456
+ getRoot() {
457
+ return this.root;
458
+ }
459
+ /**
460
+ * 获取根节点导出数据
461
+ */
462
+ getRootExportData() {
463
+ if (!this.root)
464
+ return null;
465
+ return this.root.getExportData();
466
+ }
467
+ /**
468
+ * 获取深拷贝
469
+ */
470
+ _cloneObject(obj) {
471
+ return (0, cloneDeep_1.default)(obj);
472
+ }
473
+ }
474
+ exports.TemplateModel = TemplateModel;
475
+ exports.default = TemplateModel;