@lark-project/cli
Version:
飞书项目插件开发工具
145 lines (144 loc) • 6.35 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.updatePluginDescription = exports.getPluginDescriptionInfo = void 0;
const request_1 = require("../request");
const get_tool_auth_headers_1 = require("../get-tool-auth-headers");
const list_categories_1 = require("./list-categories");
/**
* 将纯文本转为富文本编辑器所需的完整 RichText 结构(doc + doc_html + doc_text + is_empty)
* doc 格式为飞书编辑器的 Delta JSON,doc_html 为对应的 HTML
*/
function plainTextToRichText(text) {
if (!text) {
return { doc: '', doc_html: '', doc_text: '', is_empty: true };
}
const lines = text.split('\n');
// 构造 doc (Delta JSON 格式)
const ops = [];
lines.forEach(line => {
if (line) {
ops.push({ insert: line });
}
ops.push({ insert: '\n' });
});
const doc = JSON.stringify({
'0': { ops, zoneId: '0', zoneType: 'Z' },
});
// 构造 doc_html
const htmlLines = lines.map(line => `<div class="ace-line" data-node="true" dir="auto"><span data-string="true" data-leaf="true">${escapeHtml(line)}</span><span data-string="true" data-enter="true" data-leaf="true"></span></div>`);
const doc_html = htmlLines.join('');
return { doc, doc_html, doc_text: text, is_empty: false };
}
function escapeHtml(str) {
return str
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"');
}
/**
* 获取插件描述信息(草稿态)。
* IDL: api_app_development.GetAppDescriptionInfoRequest / Response
* GET /goapi/v5/app/development/tool/description/info?app_key=XXX&data_status=draft
*/
async function getPluginDescriptionInfo({ siteDomain, appKey, dataStatus = 'draft', }) {
return (0, request_1.request)(`${siteDomain}/goapi/v5/app/development/tool/description/info`, {
method: 'GET',
params: {
app_key: appKey,
data_status: dataStatus,
},
headers: await (0, get_tool_auth_headers_1.getToolAuthHeaders)(siteDomain),
timeout: 15000,
});
}
exports.getPluginDescriptionInfo = getPluginDescriptionInfo;
/**
* 对齐前端 BaseInfoForm handleChange 的 update_type 分类:
* ICON = 1 — icon 单独更新,顶层字段
* I18N = 2 — name/short/description/document/carousel_list 走 i18n_info[lang]
* CATEGORY = 3 — category_ids 单独更新,顶层字段
* PROTOCOL = 4 — protocol 单独更新,顶层字段
*/
var PluginDescUpdateType;
(function (PluginDescUpdateType) {
PluginDescUpdateType[PluginDescUpdateType["ICON"] = 1] = "ICON";
PluginDescUpdateType[PluginDescUpdateType["I18N"] = 2] = "I18N";
PluginDescUpdateType[PluginDescUpdateType["CATEGORY"] = 3] = "CATEGORY";
PluginDescUpdateType[PluginDescUpdateType["PROTOCOL"] = 4] = "PROTOCOL";
})(PluginDescUpdateType || (PluginDescUpdateType = {}));
function inferUpdateType(req) {
if (req.updateType)
return req.updateType;
if (req.icon)
return PluginDescUpdateType.ICON;
if (req.categoryIds)
return PluginDescUpdateType.CATEGORY;
if (req.protocol)
return PluginDescUpdateType.PROTOCOL;
return PluginDescUpdateType.I18N;
}
async function updatePluginDescription(req) {
var _a, _b;
const { siteDomain, appKey, name, short, detailDescription, document, carouselList, icon, protocol, categoryIds, i18nLang, lang = 'zh-cn', } = req;
const updateType = inferUpdateType(req);
const langs = (i18nLang === null || i18nLang === void 0 ? void 0 : i18nLang.length) ? i18nLang : ['zh-cn'];
// 按 update_type 组装不同的请求体,对齐前端 BaseInfoTabs handleBaseInfoChange 逻辑
const data = {
app_key: appKey,
update_type: updateType,
i18n_lang: langs,
};
switch (updateType) {
case PluginDescUpdateType.ICON:
// icon 是顶层字段(isOutter=true)
data.icon = icon;
break;
case PluginDescUpdateType.CATEGORY: {
// category_ids 是顶层字段(isOutter=true)
const categoriesRes = await (0, list_categories_1.listCategories)({ siteDomain });
const validIds = new Set((_a = categoriesRes.list) === null || _a === void 0 ? void 0 : _a.filter(i => i.status === 1).map(i => i.id));
let ids = categoryIds || [];
if (ids.length === 0) {
const fallback = (_b = categoriesRes.list) === null || _b === void 0 ? void 0 : _b.find(i => { var _a; return i.status === 1 && ((_a = i.name) === null || _a === void 0 ? void 0 : _a['zh-CN']) === '其他'; });
if (fallback === null || fallback === void 0 ? void 0 : fallback.id) {
ids = [fallback.id];
}
}
const invalidIds = ids.filter(id => !validIds.has(id));
if (invalidIds.length > 0) {
throw new Error(`Invalid category ids: ${invalidIds.join(', ')}. Valid ids: ${[...validIds].join(', ')}`);
}
data.category_ids = ids;
break;
}
case PluginDescUpdateType.PROTOCOL:
// protocol 是顶层字段(isOutter=true)
data.protocol = protocol;
break;
case PluginDescUpdateType.I18N:
default: {
// I18N 类字段包在 i18n_info[lang] 里(isOutter=false)
const i18nEntry = {};
if (name !== undefined)
i18nEntry.name = name;
if (short !== undefined)
i18nEntry.short = short;
if (detailDescription) {
i18nEntry.description = plainTextToRichText(detailDescription.trim());
}
if (document !== undefined)
i18nEntry.document = document;
if (carouselList !== undefined)
i18nEntry.carousel_list = carouselList;
data.i18n_info = { [lang]: i18nEntry };
break;
}
}
return (0, request_1.request)(`${siteDomain}/goapi/v5/app/development/tool/description/info`, {
method: 'POST',
data,
headers: await (0, get_tool_auth_headers_1.getToolAuthHeaders)(siteDomain),
});
}
exports.updatePluginDescription = updatePluginDescription;