apaas-oapi-client 0.1.34 → 0.1.35
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/README.md +1 -0
- package/UserManual.md +43 -0
- package/dist/index.js +236 -0
- package/dist/src/index.d.ts +30 -0
- package/package.json +1 -1
- package/src/index.ts +261 -0
package/README.md
CHANGED
package/UserManual.md
CHANGED
|
@@ -332,6 +332,49 @@ const res = await client.object.metadata.fields({
|
|
|
332
332
|
console.log(res);
|
|
333
333
|
```
|
|
334
334
|
|
|
335
|
+
### **导出数据对象文档为 Markdown**
|
|
336
|
+
|
|
337
|
+
将数据对象的元数据导出为详细的 Markdown 文档,包含完整的字段信息、类型、配置等。
|
|
338
|
+
|
|
339
|
+
```JavaScript
|
|
340
|
+
const fs = require('fs');
|
|
341
|
+
|
|
342
|
+
// 方式一:导出所有对象(推荐,无需参数)
|
|
343
|
+
const markdown = await client.object.metadata.export2markdown();
|
|
344
|
+
fs.writeFileSync('all_objects.md', markdown, 'utf-8');
|
|
345
|
+
|
|
346
|
+
// 方式二:只导出指定的对象
|
|
347
|
+
const markdown2 = await client.object.metadata.export2markdown({
|
|
348
|
+
object_names: ['object_store', 'object_order', '_user']
|
|
349
|
+
});
|
|
350
|
+
fs.writeFileSync('specific_objects.md', markdown2, 'utf-8');
|
|
351
|
+
|
|
352
|
+
// 方式三:结合 listWithIterator 灵活筛选
|
|
353
|
+
const allObjects = await client.object.listWithIterator();
|
|
354
|
+
const customObjects = allObjects.items
|
|
355
|
+
.filter(obj => !obj.apiName.startsWith('_')) // 只要自定义对象
|
|
356
|
+
.map(obj => obj.apiName);
|
|
357
|
+
|
|
358
|
+
const markdown3 = await client.object.metadata.export2markdown({
|
|
359
|
+
object_names: customObjects
|
|
360
|
+
});
|
|
361
|
+
fs.writeFileSync('custom_objects.md', markdown3, 'utf-8');
|
|
362
|
+
|
|
363
|
+
console.log('✅ 文档导出成功!');
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
**生成的 Markdown 文档包含:**
|
|
367
|
+
- 📋 自动生成的目录(带锚点链接)
|
|
368
|
+
- 📊 每个对象的详细信息(中英文名称、创建时间、字段数量)
|
|
369
|
+
- 📝 字段列表(中文名称、API名称、类型、必填、唯一性)
|
|
370
|
+
- ⚙️ 字段配置详情:
|
|
371
|
+
- 选项字段:展示所有选项值
|
|
372
|
+
- 公式字段:显示公式表达式和返回类型
|
|
373
|
+
- 引用字段:显示引用来源和字段
|
|
374
|
+
- lookup 字段:显示关联对象
|
|
375
|
+
- 其他配置:最大长度、小数位、显示样式等
|
|
376
|
+
- 🎯 字段智能排序(系统字段、业务字段、公式字段分类展示)
|
|
377
|
+
|
|
335
378
|
***
|
|
336
379
|
|
|
337
380
|
|
package/dist/index.js
CHANGED
|
@@ -287,6 +287,242 @@ class Client {
|
|
|
287
287
|
this.log(LoggerLevel.debug, `[object.metadata.fields] All fields metadata fetched: ${object_name}, code=${res.data.code}`);
|
|
288
288
|
this.log(LoggerLevel.trace, `[object.metadata.fields] Response: ${JSON.stringify(res.data)}`);
|
|
289
289
|
return res.data;
|
|
290
|
+
},
|
|
291
|
+
/**
|
|
292
|
+
* 导出数据对象元数据为 Markdown 文档
|
|
293
|
+
* @description 将数据对象的字段信息导出为详细的 Markdown 文档,包含字段类型、配置、选项等完整信息
|
|
294
|
+
* @param options 导出配置
|
|
295
|
+
* @param options.object_names 可选,要导出的对象名称数组。如果不传,则导出所有对象
|
|
296
|
+
* @returns Markdown 文档字符串
|
|
297
|
+
* @example
|
|
298
|
+
* ```typescript
|
|
299
|
+
* // 导出所有对象
|
|
300
|
+
* const markdown = await client.object.metadata.export2markdown();
|
|
301
|
+
*
|
|
302
|
+
* // 只导出指定对象
|
|
303
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
304
|
+
* object_names: ['object_store', 'object_order', '_user']
|
|
305
|
+
* });
|
|
306
|
+
*
|
|
307
|
+
* // 结合 listWithIterator 使用
|
|
308
|
+
* const allObjects = await client.object.listWithIterator();
|
|
309
|
+
* const objectNames = allObjects.items.map(obj => obj.apiName);
|
|
310
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
311
|
+
* object_names: objectNames
|
|
312
|
+
* });
|
|
313
|
+
*
|
|
314
|
+
* // 保存到文件
|
|
315
|
+
* fs.writeFileSync('objects_doc.md', markdown, 'utf-8');
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
export2markdown: async (options) => {
|
|
319
|
+
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t, _u, _v, _w;
|
|
320
|
+
const objectNames = options === null || options === void 0 ? void 0 : options.object_names;
|
|
321
|
+
this.log(LoggerLevel.info, `[object.metadata.export2markdown] Starting markdown export${objectNames && objectNames.length > 0 ? ` for ${objectNames.length} objects` : ' for all objects'}`);
|
|
322
|
+
let items = [];
|
|
323
|
+
if (objectNames && objectNames.length > 0) {
|
|
324
|
+
// 如果指定了对象名称,只获取这些对象
|
|
325
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching specified objects: ${objectNames.join(', ')}`);
|
|
326
|
+
// 先获取所有对象列表
|
|
327
|
+
const allObjects = await this.object.listWithIterator();
|
|
328
|
+
// 过滤出指定的对象
|
|
329
|
+
items = allObjects.items.filter((obj) => objectNames.includes(obj.apiName));
|
|
330
|
+
// 检查是否有不存在的对象
|
|
331
|
+
if (items.length < objectNames.length) {
|
|
332
|
+
const foundNames = items.map((obj) => obj.apiName);
|
|
333
|
+
const notFound = objectNames.filter(name => !foundNames.includes(name));
|
|
334
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] Objects not found: ${notFound.join(', ')}`);
|
|
335
|
+
}
|
|
336
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Found ${items.length}/${objectNames.length} matching objects`);
|
|
337
|
+
if (items.length === 0) {
|
|
338
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] No matching objects found`);
|
|
339
|
+
return '# 数据对象字段文档\n\n> 未找到匹配的对象\n';
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
// 获取所有对象
|
|
344
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching all objects`);
|
|
345
|
+
const allObjects = await this.object.listWithIterator();
|
|
346
|
+
items = allObjects.items || [];
|
|
347
|
+
}
|
|
348
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetched ${items.length} objects`);
|
|
349
|
+
// 生成 Markdown 文档
|
|
350
|
+
let markdown = '# 数据对象字段文档\n\n';
|
|
351
|
+
markdown += `> 生成时间: ${dayjs().format('YYYY-MM-DD HH:mm:ss')}\n\n`;
|
|
352
|
+
markdown += `> 对象总数: ${items.length}\n\n`;
|
|
353
|
+
markdown += '---\n\n';
|
|
354
|
+
// 目录
|
|
355
|
+
markdown += '## 目录\n\n';
|
|
356
|
+
items.forEach((obj, index) => {
|
|
357
|
+
var _a, _b;
|
|
358
|
+
const chineseName = ((_a = obj.label) === null || _a === void 0 ? void 0 : _a.zh_CN) || ((_b = obj.label) === null || _b === void 0 ? void 0 : _b.en_US) || obj.apiName;
|
|
359
|
+
markdown += `${index + 1}. [${chineseName} (${obj.apiName})](#${obj.apiName.replace(/_/g, '')})\n`;
|
|
360
|
+
});
|
|
361
|
+
markdown += '\n---\n\n';
|
|
362
|
+
// 遍历每个对象
|
|
363
|
+
for (const obj of items) {
|
|
364
|
+
const chineseName = ((_a = obj.label) === null || _a === void 0 ? void 0 : _a.zh_CN) || ((_b = obj.label) === null || _b === void 0 ? void 0 : _b.en_US) || obj.apiName;
|
|
365
|
+
const englishName = ((_c = obj.label) === null || _c === void 0 ? void 0 : _c.en_US) || '';
|
|
366
|
+
markdown += `## ${chineseName} \`${obj.apiName}\`\n\n`;
|
|
367
|
+
if (englishName && englishName !== chineseName) {
|
|
368
|
+
markdown += `**英文名称:** ${englishName}\n\n`;
|
|
369
|
+
}
|
|
370
|
+
markdown += `**创建时间:** ${dayjs(obj.createdAt).format('YYYY-MM-DD HH:mm:ss')}\n\n`;
|
|
371
|
+
markdown += `**字段数量:** ${((_d = obj.fields) === null || _d === void 0 ? void 0 : _d.length) || 0}\n\n`;
|
|
372
|
+
// 字段表格
|
|
373
|
+
if (obj.fields && obj.fields.length > 0) {
|
|
374
|
+
// 对字段进行分类和排序
|
|
375
|
+
const systemFieldOrder = ['_name', '_createdBy', '_createdAt', '_updatedBy', '_updatedAt'];
|
|
376
|
+
const specialFieldTypes = ['formula', 'referenceField'];
|
|
377
|
+
let idField = null;
|
|
378
|
+
const normalFields = [];
|
|
379
|
+
const specialFields = [];
|
|
380
|
+
const systemFields = [];
|
|
381
|
+
obj.fields.forEach((field) => {
|
|
382
|
+
var _a;
|
|
383
|
+
if (field.apiName === '_id') {
|
|
384
|
+
idField = field;
|
|
385
|
+
}
|
|
386
|
+
else if (systemFieldOrder.includes(field.apiName)) {
|
|
387
|
+
systemFields.push(field);
|
|
388
|
+
}
|
|
389
|
+
else if (specialFieldTypes.includes((_a = field.type) === null || _a === void 0 ? void 0 : _a.name)) {
|
|
390
|
+
specialFields.push(field);
|
|
391
|
+
}
|
|
392
|
+
else {
|
|
393
|
+
normalFields.push(field);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
// 对系统字段按指定顺序排序
|
|
397
|
+
systemFields.sort((a, b) => {
|
|
398
|
+
return systemFieldOrder.indexOf(a.apiName) - systemFieldOrder.indexOf(b.apiName);
|
|
399
|
+
});
|
|
400
|
+
// 组合所有字段:_id + 正常字段 + 特殊字段 + 系统字段
|
|
401
|
+
const sortedFields = [];
|
|
402
|
+
if (idField)
|
|
403
|
+
sortedFields.push(idField);
|
|
404
|
+
sortedFields.push(...normalFields);
|
|
405
|
+
sortedFields.push(...specialFields);
|
|
406
|
+
sortedFields.push(...systemFields);
|
|
407
|
+
markdown += '### 字段列表\n\n';
|
|
408
|
+
markdown += '| 中文名称 | API名称 | 类型 | 必填 | 唯一 | 其他设置 |\n';
|
|
409
|
+
markdown += '|---------|---------|------|------|------|----------|\n';
|
|
410
|
+
for (const field of sortedFields) {
|
|
411
|
+
// 转义 Markdown 表格中的特殊字符
|
|
412
|
+
const escapeMarkdown = (text) => {
|
|
413
|
+
return text.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
414
|
+
};
|
|
415
|
+
const label = escapeMarkdown(((_e = field.label) === null || _e === void 0 ? void 0 : _e.zh_CN) || ((_f = field.label) === null || _f === void 0 ? void 0 : _f.en_US) || '-');
|
|
416
|
+
const apiName = field.apiName || '-';
|
|
417
|
+
const typeName = ((_g = field.type) === null || _g === void 0 ? void 0 : _g.name) || '-';
|
|
418
|
+
const required = ((_j = (_h = field.type) === null || _h === void 0 ? void 0 : _h.settings) === null || _j === void 0 ? void 0 : _j.required) ? '✓' : '';
|
|
419
|
+
const unique = ((_l = (_k = field.type) === null || _k === void 0 ? void 0 : _k.settings) === null || _l === void 0 ? void 0 : _l.unique) ? '✓' : '';
|
|
420
|
+
// 构建其他设置信息
|
|
421
|
+
const otherSettings = [];
|
|
422
|
+
const settings = ((_m = field.type) === null || _m === void 0 ? void 0 : _m.settings) || {};
|
|
423
|
+
// lookup 类型:标注关联的对象(外键)
|
|
424
|
+
if (((_o = field.type) === null || _o === void 0 ? void 0 : _o.name) === 'lookup' && settings.objectAPIName) {
|
|
425
|
+
otherSettings.push(`🔗 关联对象: \`${settings.objectAPIName}\``);
|
|
426
|
+
}
|
|
427
|
+
// referenceField 类型:引用字段
|
|
428
|
+
if (((_p = field.type) === null || _p === void 0 ? void 0 : _p.name) === 'referenceField') {
|
|
429
|
+
otherSettings.push(`⚙️ 系统自动维护,不需要写/更新`);
|
|
430
|
+
if (settings.guideFieldAPIName) {
|
|
431
|
+
otherSettings.push(`📎 引用自: \`${settings.guideFieldAPIName}\``);
|
|
432
|
+
}
|
|
433
|
+
if (settings.fieldAPIName) {
|
|
434
|
+
otherSettings.push(`📋 引用字段: \`${settings.fieldAPIName}\``);
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
// formula 类型:系统自动维护
|
|
438
|
+
if (((_q = field.type) === null || _q === void 0 ? void 0 : _q.name) === 'formula') {
|
|
439
|
+
otherSettings.push(`⚙️ 系统自动维护,不需要写/更新`);
|
|
440
|
+
if (settings.formula && Array.isArray(settings.formula)) {
|
|
441
|
+
// 优先显示中文公式,否则显示第一个
|
|
442
|
+
const zhFormula = settings.formula.find((f) => f.language_code === 2052);
|
|
443
|
+
const formulaText = (zhFormula === null || zhFormula === void 0 ? void 0 : zhFormula.text) || ((_r = settings.formula[0]) === null || _r === void 0 ? void 0 : _r.text);
|
|
444
|
+
if (formulaText) {
|
|
445
|
+
// 转义公式中的特殊字符
|
|
446
|
+
const escapedFormula = formulaText.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
447
|
+
otherSettings.push(`公式: ${escapedFormula}`);
|
|
448
|
+
}
|
|
449
|
+
}
|
|
450
|
+
if (settings.returnType) {
|
|
451
|
+
otherSettings.push(`返回类型: ${settings.returnType}`);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
// 根据不同类型展示不同的设置
|
|
455
|
+
if (settings.maxLength) {
|
|
456
|
+
otherSettings.push(`最大长度:${settings.maxLength}`);
|
|
457
|
+
}
|
|
458
|
+
if (settings.decimalPlacesNumber !== undefined) {
|
|
459
|
+
otherSettings.push(`小数位:${settings.decimalPlacesNumber}`);
|
|
460
|
+
}
|
|
461
|
+
if (settings.displayAsPercentage) {
|
|
462
|
+
otherSettings.push('百分比显示');
|
|
463
|
+
}
|
|
464
|
+
if (settings.multiline) {
|
|
465
|
+
otherSettings.push('多行');
|
|
466
|
+
}
|
|
467
|
+
if (settings.multiple) {
|
|
468
|
+
otherSettings.push('多选');
|
|
469
|
+
}
|
|
470
|
+
if (settings.hierarchy) {
|
|
471
|
+
otherSettings.push('层级');
|
|
472
|
+
}
|
|
473
|
+
if (settings.displayStyle && ((_s = field.type) === null || _s === void 0 ? void 0 : _s.name) !== 'lookup') {
|
|
474
|
+
otherSettings.push(`显示样式:${settings.displayStyle}`);
|
|
475
|
+
}
|
|
476
|
+
if (settings.referenceObjectApiName) {
|
|
477
|
+
otherSettings.push(`关联:${settings.referenceObjectApiName}`);
|
|
478
|
+
}
|
|
479
|
+
if (settings.rollUpType) {
|
|
480
|
+
otherSettings.push(`汇总:${settings.rollUpType}`);
|
|
481
|
+
}
|
|
482
|
+
// 如果是 option 类型,获取选项列表
|
|
483
|
+
if (((_t = field.type) === null || _t === void 0 ? void 0 : _t.name) === 'option') {
|
|
484
|
+
// 优先使用已有的 optionList,避免额外 API 请求
|
|
485
|
+
const options = settings.optionList;
|
|
486
|
+
if (options && options.length > 0) {
|
|
487
|
+
const optionTexts = options.map((opt) => {
|
|
488
|
+
var _a, _b;
|
|
489
|
+
const zhLabel = ((_b = (_a = opt.label) === null || _a === void 0 ? void 0 : _a.find((l) => l.language_code === 2052)) === null || _b === void 0 ? void 0 : _b.text) || '-';
|
|
490
|
+
return `${zhLabel}(\`${opt.apiName}\`)`;
|
|
491
|
+
});
|
|
492
|
+
otherSettings.push(`选项: ${optionTexts.join(', ')}`);
|
|
493
|
+
}
|
|
494
|
+
else {
|
|
495
|
+
// 如果没有 optionList,再尝试单独请求(但这可能很慢)
|
|
496
|
+
try {
|
|
497
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching option details for ${obj.apiName}.${field.apiName}`);
|
|
498
|
+
const optionsResult = await this.object.metadata.field({
|
|
499
|
+
object_name: obj.apiName,
|
|
500
|
+
field_name: field.apiName
|
|
501
|
+
});
|
|
502
|
+
const fetchedOptions = (_w = (_v = (_u = optionsResult === null || optionsResult === void 0 ? void 0 : optionsResult.data) === null || _u === void 0 ? void 0 : _u.type) === null || _v === void 0 ? void 0 : _v.settings) === null || _w === void 0 ? void 0 : _w.optionList;
|
|
503
|
+
if (fetchedOptions && fetchedOptions.length > 0) {
|
|
504
|
+
const optionTexts = fetchedOptions.map((opt) => {
|
|
505
|
+
var _a, _b;
|
|
506
|
+
const zhLabel = ((_b = (_a = opt.label) === null || _a === void 0 ? void 0 : _a.find((l) => l.language_code === 2052)) === null || _b === void 0 ? void 0 : _b.text) || '-';
|
|
507
|
+
return `${zhLabel}(\`${opt.apiName}\`)`;
|
|
508
|
+
});
|
|
509
|
+
otherSettings.push(`选项: ${optionTexts.join(', ')}`);
|
|
510
|
+
}
|
|
511
|
+
}
|
|
512
|
+
catch (error) {
|
|
513
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] Failed to fetch option field details for ${obj.apiName}.${field.apiName}:`, error);
|
|
514
|
+
}
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
const otherSettingsStr = otherSettings.length > 0 ? otherSettings.join('<br>') : '-';
|
|
518
|
+
markdown += `| ${label} | \`${apiName}\` | ${typeName} | ${required} | ${unique} | ${otherSettingsStr} |\n`;
|
|
519
|
+
}
|
|
520
|
+
markdown += '\n';
|
|
521
|
+
}
|
|
522
|
+
markdown += '---\n\n';
|
|
523
|
+
}
|
|
524
|
+
this.log(LoggerLevel.info, `[object.metadata.export2markdown] Markdown export completed`);
|
|
525
|
+
return markdown;
|
|
290
526
|
}
|
|
291
527
|
},
|
|
292
528
|
search: {
|
package/dist/src/index.d.ts
CHANGED
|
@@ -157,6 +157,36 @@ declare class Client {
|
|
|
157
157
|
fields: (params: {
|
|
158
158
|
object_name: string;
|
|
159
159
|
}) => Promise<any>;
|
|
160
|
+
/**
|
|
161
|
+
* 导出数据对象元数据为 Markdown 文档
|
|
162
|
+
* @description 将数据对象的字段信息导出为详细的 Markdown 文档,包含字段类型、配置、选项等完整信息
|
|
163
|
+
* @param options 导出配置
|
|
164
|
+
* @param options.object_names 可选,要导出的对象名称数组。如果不传,则导出所有对象
|
|
165
|
+
* @returns Markdown 文档字符串
|
|
166
|
+
* @example
|
|
167
|
+
* ```typescript
|
|
168
|
+
* // 导出所有对象
|
|
169
|
+
* const markdown = await client.object.metadata.export2markdown();
|
|
170
|
+
*
|
|
171
|
+
* // 只导出指定对象
|
|
172
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
173
|
+
* object_names: ['object_store', 'object_order', '_user']
|
|
174
|
+
* });
|
|
175
|
+
*
|
|
176
|
+
* // 结合 listWithIterator 使用
|
|
177
|
+
* const allObjects = await client.object.listWithIterator();
|
|
178
|
+
* const objectNames = allObjects.items.map(obj => obj.apiName);
|
|
179
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
180
|
+
* object_names: objectNames
|
|
181
|
+
* });
|
|
182
|
+
*
|
|
183
|
+
* // 保存到文件
|
|
184
|
+
* fs.writeFileSync('objects_doc.md', markdown, 'utf-8');
|
|
185
|
+
* ```
|
|
186
|
+
*/
|
|
187
|
+
export2markdown: (options?: {
|
|
188
|
+
object_names?: string[];
|
|
189
|
+
}) => Promise<string>;
|
|
160
190
|
};
|
|
161
191
|
search: {
|
|
162
192
|
/**
|
package/package.json
CHANGED
package/src/index.ts
CHANGED
|
@@ -493,6 +493,267 @@ class Client {
|
|
|
493
493
|
this.log(LoggerLevel.debug, `[object.metadata.fields] All fields metadata fetched: ${object_name}, code=${res.data.code}`);
|
|
494
494
|
this.log(LoggerLevel.trace, `[object.metadata.fields] Response: ${JSON.stringify(res.data)}`);
|
|
495
495
|
return res.data;
|
|
496
|
+
},
|
|
497
|
+
|
|
498
|
+
/**
|
|
499
|
+
* 导出数据对象元数据为 Markdown 文档
|
|
500
|
+
* @description 将数据对象的字段信息导出为详细的 Markdown 文档,包含字段类型、配置、选项等完整信息
|
|
501
|
+
* @param options 导出配置
|
|
502
|
+
* @param options.object_names 可选,要导出的对象名称数组。如果不传,则导出所有对象
|
|
503
|
+
* @returns Markdown 文档字符串
|
|
504
|
+
* @example
|
|
505
|
+
* ```typescript
|
|
506
|
+
* // 导出所有对象
|
|
507
|
+
* const markdown = await client.object.metadata.export2markdown();
|
|
508
|
+
*
|
|
509
|
+
* // 只导出指定对象
|
|
510
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
511
|
+
* object_names: ['object_store', 'object_order', '_user']
|
|
512
|
+
* });
|
|
513
|
+
*
|
|
514
|
+
* // 结合 listWithIterator 使用
|
|
515
|
+
* const allObjects = await client.object.listWithIterator();
|
|
516
|
+
* const objectNames = allObjects.items.map(obj => obj.apiName);
|
|
517
|
+
* const markdown = await client.object.metadata.export2markdown({
|
|
518
|
+
* object_names: objectNames
|
|
519
|
+
* });
|
|
520
|
+
*
|
|
521
|
+
* // 保存到文件
|
|
522
|
+
* fs.writeFileSync('objects_doc.md', markdown, 'utf-8');
|
|
523
|
+
* ```
|
|
524
|
+
*/
|
|
525
|
+
export2markdown: async (options?: { object_names?: string[] }): Promise<string> => {
|
|
526
|
+
const objectNames = options?.object_names;
|
|
527
|
+
|
|
528
|
+
this.log(LoggerLevel.info, `[object.metadata.export2markdown] Starting markdown export${objectNames && objectNames.length > 0 ? ` for ${objectNames.length} objects` : ' for all objects'}`);
|
|
529
|
+
|
|
530
|
+
let items: any[] = [];
|
|
531
|
+
|
|
532
|
+
if (objectNames && objectNames.length > 0) {
|
|
533
|
+
// 如果指定了对象名称,只获取这些对象
|
|
534
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching specified objects: ${objectNames.join(', ')}`);
|
|
535
|
+
|
|
536
|
+
// 先获取所有对象列表
|
|
537
|
+
const allObjects = await this.object.listWithIterator();
|
|
538
|
+
|
|
539
|
+
// 过滤出指定的对象
|
|
540
|
+
items = allObjects.items.filter((obj: any) => objectNames.includes(obj.apiName));
|
|
541
|
+
|
|
542
|
+
// 检查是否有不存在的对象
|
|
543
|
+
if (items.length < objectNames.length) {
|
|
544
|
+
const foundNames = items.map((obj: any) => obj.apiName);
|
|
545
|
+
const notFound = objectNames.filter(name => !foundNames.includes(name));
|
|
546
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] Objects not found: ${notFound.join(', ')}`);
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Found ${items.length}/${objectNames.length} matching objects`);
|
|
550
|
+
|
|
551
|
+
if (items.length === 0) {
|
|
552
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] No matching objects found`);
|
|
553
|
+
return '# 数据对象字段文档\n\n> 未找到匹配的对象\n';
|
|
554
|
+
}
|
|
555
|
+
} else {
|
|
556
|
+
// 获取所有对象
|
|
557
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching all objects`);
|
|
558
|
+
const allObjects = await this.object.listWithIterator();
|
|
559
|
+
items = allObjects.items || [];
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetched ${items.length} objects`);
|
|
563
|
+
|
|
564
|
+
// 生成 Markdown 文档
|
|
565
|
+
let markdown = '# 数据对象字段文档\n\n';
|
|
566
|
+
markdown += `> 生成时间: ${dayjs().format('YYYY-MM-DD HH:mm:ss')}\n\n`;
|
|
567
|
+
markdown += `> 对象总数: ${items.length}\n\n`;
|
|
568
|
+
markdown += '---\n\n';
|
|
569
|
+
|
|
570
|
+
// 目录
|
|
571
|
+
markdown += '## 目录\n\n';
|
|
572
|
+
items.forEach((obj: any, index: number) => {
|
|
573
|
+
const chineseName = obj.label?.zh_CN || obj.label?.en_US || obj.apiName;
|
|
574
|
+
markdown += `${index + 1}. [${chineseName} (${obj.apiName})](#${obj.apiName.replace(/_/g, '')})\n`;
|
|
575
|
+
});
|
|
576
|
+
markdown += '\n---\n\n';
|
|
577
|
+
|
|
578
|
+
// 遍历每个对象
|
|
579
|
+
for (const obj of items) {
|
|
580
|
+
const chineseName = obj.label?.zh_CN || obj.label?.en_US || obj.apiName;
|
|
581
|
+
const englishName = obj.label?.en_US || '';
|
|
582
|
+
|
|
583
|
+
markdown += `## ${chineseName} \`${obj.apiName}\`\n\n`;
|
|
584
|
+
|
|
585
|
+
if (englishName && englishName !== chineseName) {
|
|
586
|
+
markdown += `**英文名称:** ${englishName}\n\n`;
|
|
587
|
+
}
|
|
588
|
+
|
|
589
|
+
markdown += `**创建时间:** ${dayjs(obj.createdAt).format('YYYY-MM-DD HH:mm:ss')}\n\n`;
|
|
590
|
+
markdown += `**字段数量:** ${obj.fields?.length || 0}\n\n`;
|
|
591
|
+
|
|
592
|
+
// 字段表格
|
|
593
|
+
if (obj.fields && obj.fields.length > 0) {
|
|
594
|
+
// 对字段进行分类和排序
|
|
595
|
+
const systemFieldOrder = ['_name', '_createdBy', '_createdAt', '_updatedBy', '_updatedAt'];
|
|
596
|
+
const specialFieldTypes = ['formula', 'referenceField'];
|
|
597
|
+
|
|
598
|
+
let idField: any = null;
|
|
599
|
+
const normalFields: any[] = [];
|
|
600
|
+
const specialFields: any[] = [];
|
|
601
|
+
const systemFields: any[] = [];
|
|
602
|
+
|
|
603
|
+
obj.fields.forEach((field: any) => {
|
|
604
|
+
if (field.apiName === '_id') {
|
|
605
|
+
idField = field;
|
|
606
|
+
} else if (systemFieldOrder.includes(field.apiName)) {
|
|
607
|
+
systemFields.push(field);
|
|
608
|
+
} else if (specialFieldTypes.includes(field.type?.name)) {
|
|
609
|
+
specialFields.push(field);
|
|
610
|
+
} else {
|
|
611
|
+
normalFields.push(field);
|
|
612
|
+
}
|
|
613
|
+
});
|
|
614
|
+
|
|
615
|
+
// 对系统字段按指定顺序排序
|
|
616
|
+
systemFields.sort((a, b) => {
|
|
617
|
+
return systemFieldOrder.indexOf(a.apiName) - systemFieldOrder.indexOf(b.apiName);
|
|
618
|
+
});
|
|
619
|
+
|
|
620
|
+
// 组合所有字段:_id + 正常字段 + 特殊字段 + 系统字段
|
|
621
|
+
const sortedFields: any[] = [];
|
|
622
|
+
if (idField) sortedFields.push(idField);
|
|
623
|
+
sortedFields.push(...normalFields);
|
|
624
|
+
sortedFields.push(...specialFields);
|
|
625
|
+
sortedFields.push(...systemFields);
|
|
626
|
+
|
|
627
|
+
markdown += '### 字段列表\n\n';
|
|
628
|
+
markdown += '| 中文名称 | API名称 | 类型 | 必填 | 唯一 | 其他设置 |\n';
|
|
629
|
+
markdown += '|---------|---------|------|------|------|----------|\n';
|
|
630
|
+
|
|
631
|
+
for (const field of sortedFields) {
|
|
632
|
+
// 转义 Markdown 表格中的特殊字符
|
|
633
|
+
const escapeMarkdown = (text: string): string => {
|
|
634
|
+
return text.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
635
|
+
};
|
|
636
|
+
|
|
637
|
+
const label = escapeMarkdown(field.label?.zh_CN || field.label?.en_US || '-');
|
|
638
|
+
const apiName = field.apiName || '-';
|
|
639
|
+
const typeName = field.type?.name || '-';
|
|
640
|
+
const required = field.type?.settings?.required ? '✓' : '';
|
|
641
|
+
const unique = field.type?.settings?.unique ? '✓' : '';
|
|
642
|
+
|
|
643
|
+
// 构建其他设置信息
|
|
644
|
+
const otherSettings: string[] = [];
|
|
645
|
+
const settings = field.type?.settings || {};
|
|
646
|
+
|
|
647
|
+
// lookup 类型:标注关联的对象(外键)
|
|
648
|
+
if (field.type?.name === 'lookup' && settings.objectAPIName) {
|
|
649
|
+
otherSettings.push(`🔗 关联对象: \`${settings.objectAPIName}\``);
|
|
650
|
+
}
|
|
651
|
+
|
|
652
|
+
// referenceField 类型:引用字段
|
|
653
|
+
if (field.type?.name === 'referenceField') {
|
|
654
|
+
otherSettings.push(`⚙️ 系统自动维护,不需要写/更新`);
|
|
655
|
+
if (settings.guideFieldAPIName) {
|
|
656
|
+
otherSettings.push(`📎 引用自: \`${settings.guideFieldAPIName}\``);
|
|
657
|
+
}
|
|
658
|
+
if (settings.fieldAPIName) {
|
|
659
|
+
otherSettings.push(`📋 引用字段: \`${settings.fieldAPIName}\``);
|
|
660
|
+
}
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
// formula 类型:系统自动维护
|
|
664
|
+
if (field.type?.name === 'formula') {
|
|
665
|
+
otherSettings.push(`⚙️ 系统自动维护,不需要写/更新`);
|
|
666
|
+
if (settings.formula && Array.isArray(settings.formula)) {
|
|
667
|
+
// 优先显示中文公式,否则显示第一个
|
|
668
|
+
const zhFormula = settings.formula.find((f: any) => f.language_code === 2052);
|
|
669
|
+
const formulaText = zhFormula?.text || settings.formula[0]?.text;
|
|
670
|
+
if (formulaText) {
|
|
671
|
+
// 转义公式中的特殊字符
|
|
672
|
+
const escapedFormula = formulaText.replace(/\|/g, '\\|').replace(/\n/g, ' ');
|
|
673
|
+
otherSettings.push(`公式: ${escapedFormula}`);
|
|
674
|
+
}
|
|
675
|
+
}
|
|
676
|
+
if (settings.returnType) {
|
|
677
|
+
otherSettings.push(`返回类型: ${settings.returnType}`);
|
|
678
|
+
}
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
// 根据不同类型展示不同的设置
|
|
682
|
+
if (settings.maxLength) {
|
|
683
|
+
otherSettings.push(`最大长度:${settings.maxLength}`);
|
|
684
|
+
}
|
|
685
|
+
if (settings.decimalPlacesNumber !== undefined) {
|
|
686
|
+
otherSettings.push(`小数位:${settings.decimalPlacesNumber}`);
|
|
687
|
+
}
|
|
688
|
+
if (settings.displayAsPercentage) {
|
|
689
|
+
otherSettings.push('百分比显示');
|
|
690
|
+
}
|
|
691
|
+
if (settings.multiline) {
|
|
692
|
+
otherSettings.push('多行');
|
|
693
|
+
}
|
|
694
|
+
if (settings.multiple) {
|
|
695
|
+
otherSettings.push('多选');
|
|
696
|
+
}
|
|
697
|
+
if (settings.hierarchy) {
|
|
698
|
+
otherSettings.push('层级');
|
|
699
|
+
}
|
|
700
|
+
if (settings.displayStyle && field.type?.name !== 'lookup') {
|
|
701
|
+
otherSettings.push(`显示样式:${settings.displayStyle}`);
|
|
702
|
+
}
|
|
703
|
+
if (settings.referenceObjectApiName) {
|
|
704
|
+
otherSettings.push(`关联:${settings.referenceObjectApiName}`);
|
|
705
|
+
}
|
|
706
|
+
if (settings.rollUpType) {
|
|
707
|
+
otherSettings.push(`汇总:${settings.rollUpType}`);
|
|
708
|
+
}
|
|
709
|
+
|
|
710
|
+
// 如果是 option 类型,获取选项列表
|
|
711
|
+
if (field.type?.name === 'option') {
|
|
712
|
+
// 优先使用已有的 optionList,避免额外 API 请求
|
|
713
|
+
const options = settings.optionList;
|
|
714
|
+
if (options && options.length > 0) {
|
|
715
|
+
const optionTexts = options.map((opt: any) => {
|
|
716
|
+
const zhLabel = opt.label?.find((l: any) => l.language_code === 2052)?.text || '-';
|
|
717
|
+
return `${zhLabel}(\`${opt.apiName}\`)`;
|
|
718
|
+
});
|
|
719
|
+
otherSettings.push(`选项: ${optionTexts.join(', ')}`);
|
|
720
|
+
} else {
|
|
721
|
+
// 如果没有 optionList,再尝试单独请求(但这可能很慢)
|
|
722
|
+
try {
|
|
723
|
+
this.log(LoggerLevel.debug, `[object.metadata.export2markdown] Fetching option details for ${obj.apiName}.${field.apiName}`);
|
|
724
|
+
const optionsResult = await this.object.metadata.field({
|
|
725
|
+
object_name: obj.apiName,
|
|
726
|
+
field_name: field.apiName
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
const fetchedOptions = optionsResult?.data?.type?.settings?.optionList;
|
|
730
|
+
if (fetchedOptions && fetchedOptions.length > 0) {
|
|
731
|
+
const optionTexts = fetchedOptions.map((opt: any) => {
|
|
732
|
+
const zhLabel = opt.label?.find((l: any) => l.language_code === 2052)?.text || '-';
|
|
733
|
+
return `${zhLabel}(\`${opt.apiName}\`)`;
|
|
734
|
+
});
|
|
735
|
+
otherSettings.push(`选项: ${optionTexts.join(', ')}`);
|
|
736
|
+
}
|
|
737
|
+
} catch (error) {
|
|
738
|
+
this.log(LoggerLevel.warn, `[object.metadata.export2markdown] Failed to fetch option field details for ${obj.apiName}.${field.apiName}:`, error);
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
const otherSettingsStr = otherSettings.length > 0 ? otherSettings.join('<br>') : '-';
|
|
744
|
+
|
|
745
|
+
markdown += `| ${label} | \`${apiName}\` | ${typeName} | ${required} | ${unique} | ${otherSettingsStr} |\n`;
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
markdown += '\n';
|
|
749
|
+
}
|
|
750
|
+
|
|
751
|
+
markdown += '---\n\n';
|
|
752
|
+
}
|
|
753
|
+
|
|
754
|
+
this.log(LoggerLevel.info, `[object.metadata.export2markdown] Markdown export completed`);
|
|
755
|
+
|
|
756
|
+
return markdown;
|
|
496
757
|
}
|
|
497
758
|
},
|
|
498
759
|
|