openxiangda 1.0.230 → 1.0.231
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/lib/cli.js +234 -39
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -16309,7 +16309,12 @@ function removeDirectStateResource(target, resourceType, code) {
|
|
|
16309
16309
|
function normalizeMenuDirectBody(bound, menuItem) {
|
|
16310
16310
|
const formUuid = resolveManifestFormUuid(bound, menuItem);
|
|
16311
16311
|
const pageId = resolveManifestPageId(bound, menuItem);
|
|
16312
|
-
const parentId =
|
|
16312
|
+
const parentId = requireResolvedMenuParentId(
|
|
16313
|
+
bound,
|
|
16314
|
+
menuItem,
|
|
16315
|
+
new Map(),
|
|
16316
|
+
'direct menu mutation'
|
|
16317
|
+
);
|
|
16313
16318
|
return stripUndefinedValues({
|
|
16314
16319
|
resourceCode: menuItem.code || menuItem.resourceCode,
|
|
16315
16320
|
name: menuItem.name || menuItem.code,
|
|
@@ -19087,7 +19092,19 @@ async function buildResourcePlan(
|
|
|
19087
19092
|
]);
|
|
19088
19093
|
const actions = [];
|
|
19089
19094
|
addPlanActions(actions, 'role', manifest.roles, existing.roles, roleEquals);
|
|
19090
|
-
|
|
19095
|
+
const orderedMenus = orderMenuResourcesForPublish(
|
|
19096
|
+
manifest.menus,
|
|
19097
|
+
target.bound,
|
|
19098
|
+
existing.menus
|
|
19099
|
+
);
|
|
19100
|
+
addPlanActions(
|
|
19101
|
+
actions,
|
|
19102
|
+
'menu',
|
|
19103
|
+
orderedMenus,
|
|
19104
|
+
existing.menus,
|
|
19105
|
+
(item, current) =>
|
|
19106
|
+
menuEquals(target.bound, item, current, existing.menus)
|
|
19107
|
+
);
|
|
19091
19108
|
addPlanActions(actions, 'connector', manifest.connectors, existing.connectors, connectorEquals);
|
|
19092
19109
|
addNotificationPlanActions(target, actions, manifest.notifications || [], existing);
|
|
19093
19110
|
await addWorkflowPlanActions(config, target, actions, manifest.workflows, existing.workflows);
|
|
@@ -22594,21 +22611,61 @@ async function publishFormSettingsResources(
|
|
|
22594
22611
|
}
|
|
22595
22612
|
|
|
22596
22613
|
async function publishMenuResources(config, target, menus, result, options = {}) {
|
|
22597
|
-
|
|
22598
|
-
|
|
22599
|
-
|
|
22614
|
+
if (menus.length === 0) return;
|
|
22615
|
+
const existingMenus = await fetchExistingMenusByCode(config, target);
|
|
22616
|
+
const orderedMenus = orderMenuResourcesForPublish(
|
|
22617
|
+
menus,
|
|
22618
|
+
target.bound,
|
|
22619
|
+
existingMenus
|
|
22620
|
+
);
|
|
22621
|
+
for (const menuItem of orderedMenus) {
|
|
22622
|
+
const code = menuResourceCode(menuItem);
|
|
22623
|
+
const plannedAction = getPlannedResourceAction(options, 'menu', code);
|
|
22624
|
+
const existing = existingMenus.get(code);
|
|
22625
|
+
if (existing && !menuPlatformId(existing)) {
|
|
22626
|
+
const error = new Error(
|
|
22627
|
+
`MENU_ONLINE_ID_REQUIRED: 在线 menu ${code} 缺少 menuId,禁止执行恢复发布`
|
|
22628
|
+
);
|
|
22629
|
+
error.code = 'MENU_ONLINE_ID_REQUIRED';
|
|
22630
|
+
throw error;
|
|
22631
|
+
}
|
|
22632
|
+
if (
|
|
22633
|
+
['noop', 'update'].includes(plannedAction?.action) &&
|
|
22634
|
+
!menuPlatformId(existing)
|
|
22635
|
+
) {
|
|
22636
|
+
const error = new Error(
|
|
22637
|
+
`MENU_PLAN_TARGET_MISSING: menu ${code} 的冻结计划为 ${plannedAction.action},但写入前在线菜单已不存在`
|
|
22638
|
+
);
|
|
22639
|
+
error.code = 'MENU_PLAN_TARGET_MISSING';
|
|
22640
|
+
throw error;
|
|
22641
|
+
}
|
|
22642
|
+
}
|
|
22643
|
+
for (const menuItem of orderedMenus) {
|
|
22644
|
+
const code = menuResourceCode(menuItem);
|
|
22645
|
+
const existing = existingMenus.get(code);
|
|
22646
|
+
if (shouldSkipNoopResource(options, 'menu', code)) {
|
|
22647
|
+
const existingId = menuPlatformId(existing);
|
|
22648
|
+
saveMenuResource(target, code, existingId, {
|
|
22649
|
+
formUuid: existing.formUuid,
|
|
22650
|
+
pageId: existing.pageId,
|
|
22651
|
+
parentId: existing.parentId,
|
|
22652
|
+
routeCode: existing.routeCode,
|
|
22653
|
+
path: existing.path,
|
|
22654
|
+
});
|
|
22655
|
+
recordNoopResource(result, 'menu', code, options);
|
|
22600
22656
|
continue;
|
|
22601
22657
|
}
|
|
22602
|
-
const existing = await findExistingMenu(config, target, menuItem.code);
|
|
22603
22658
|
const formUuid = resolveManifestFormUuid(target.bound, menuItem);
|
|
22604
22659
|
const pageId = resolveManifestPageId(target.bound, menuItem);
|
|
22605
|
-
const parentId =
|
|
22606
|
-
|
|
22607
|
-
menuItem
|
|
22608
|
-
|
|
22660
|
+
const parentId = requireResolvedMenuParentId(
|
|
22661
|
+
target.bound,
|
|
22662
|
+
menuItem,
|
|
22663
|
+
existingMenus,
|
|
22664
|
+
`resource publish menu ${code}`
|
|
22665
|
+
);
|
|
22609
22666
|
const body = {
|
|
22610
|
-
resourceCode:
|
|
22611
|
-
name: menuItem.name ||
|
|
22667
|
+
resourceCode: code,
|
|
22668
|
+
name: menuItem.name || code,
|
|
22612
22669
|
type: menuItem.type || 'nav',
|
|
22613
22670
|
formUuid,
|
|
22614
22671
|
pageId,
|
|
@@ -22619,11 +22676,12 @@ async function publishMenuResources(config, target, menus, result, options = {})
|
|
|
22619
22676
|
routeCode: menuItem.routeCode || null,
|
|
22620
22677
|
path: menuItem.path || null,
|
|
22621
22678
|
};
|
|
22679
|
+
const existingId = menuPlatformId(existing);
|
|
22622
22680
|
let data = existing
|
|
22623
22681
|
? await requestWithAuth(
|
|
22624
22682
|
config,
|
|
22625
22683
|
target.profileName,
|
|
22626
|
-
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus/${encodeURIComponent(
|
|
22684
|
+
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus/${encodeURIComponent(existingId)}`,
|
|
22627
22685
|
{ method: 'POST', body }
|
|
22628
22686
|
)
|
|
22629
22687
|
: await requestWithAuth(
|
|
@@ -22632,37 +22690,54 @@ async function publishMenuResources(config, target, menus, result, options = {})
|
|
|
22632
22690
|
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus`,
|
|
22633
22691
|
{ method: 'POST', body }
|
|
22634
22692
|
);
|
|
22635
|
-
if (data?.id) {
|
|
22636
|
-
|
|
22637
|
-
|
|
22638
|
-
|
|
22639
|
-
|
|
22640
|
-
|
|
22641
|
-
...(pageId ? { pageId } : {}),
|
|
22642
|
-
...(menuItem.pageCode ? { pageCode: menuItem.pageCode } : {}),
|
|
22643
|
-
...(menuItem.routeCode || data.routeCode
|
|
22644
|
-
? { routeCode: data.routeCode || menuItem.routeCode }
|
|
22645
|
-
: {}),
|
|
22646
|
-
...(menuItem.path || data.path ? { path: data.path || menuItem.path } : {}),
|
|
22647
|
-
});
|
|
22693
|
+
if (!data?.id) {
|
|
22694
|
+
const error = new Error(
|
|
22695
|
+
`MENU_WRITE_ID_REQUIRED: menu ${code} 写入成功响应缺少 menuId,禁止继续发布子菜单`
|
|
22696
|
+
);
|
|
22697
|
+
error.code = 'MENU_WRITE_ID_REQUIRED';
|
|
22698
|
+
throw error;
|
|
22648
22699
|
}
|
|
22649
|
-
|
|
22700
|
+
saveMenuResource(target, code, data.id, {
|
|
22701
|
+
resourceCode: code,
|
|
22702
|
+
name: data.name,
|
|
22703
|
+
type: data.type,
|
|
22704
|
+
...(formUuid ? { formUuid } : {}),
|
|
22705
|
+
...(pageId ? { pageId } : {}),
|
|
22706
|
+
...(menuItem.pageCode ? { pageCode: menuItem.pageCode } : {}),
|
|
22707
|
+
...(menuItem.routeCode || data.routeCode
|
|
22708
|
+
? { routeCode: data.routeCode || menuItem.routeCode }
|
|
22709
|
+
: {}),
|
|
22710
|
+
...(menuItem.path || data.path ? { path: data.path || menuItem.path } : {}),
|
|
22711
|
+
parentId: data.parentId || parentId,
|
|
22712
|
+
});
|
|
22713
|
+
existingMenus.set(code, {
|
|
22714
|
+
...(existing || {}),
|
|
22715
|
+
...body,
|
|
22716
|
+
...data,
|
|
22717
|
+
id: data.id,
|
|
22718
|
+
});
|
|
22719
|
+
result.published.push({
|
|
22720
|
+
kind: 'menu',
|
|
22721
|
+
code,
|
|
22722
|
+
action: existing ? 'update' : 'create',
|
|
22723
|
+
id: data?.id,
|
|
22724
|
+
});
|
|
22650
22725
|
}
|
|
22651
22726
|
}
|
|
22652
22727
|
|
|
22653
|
-
async function
|
|
22728
|
+
async function fetchExistingMenusByCode(config, target) {
|
|
22654
22729
|
const data = await requestWithAuth(
|
|
22655
22730
|
config,
|
|
22656
22731
|
target.profileName,
|
|
22657
22732
|
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus`
|
|
22658
22733
|
);
|
|
22659
|
-
const
|
|
22660
|
-
|
|
22661
|
-
|
|
22662
|
-
|
|
22663
|
-
|
|
22664
|
-
|
|
22665
|
-
return
|
|
22734
|
+
const menus = new Map();
|
|
22735
|
+
indexByCode(
|
|
22736
|
+
menus,
|
|
22737
|
+
flattenItems(normalizeItems(data)),
|
|
22738
|
+
item => item.resourceCode
|
|
22739
|
+
);
|
|
22740
|
+
return menus;
|
|
22666
22741
|
}
|
|
22667
22742
|
|
|
22668
22743
|
async function publishConnectorResources(config, target, connectors, result, options = {}) {
|
|
@@ -26026,7 +26101,123 @@ function resolveManifestPageId(bound, item) {
|
|
|
26026
26101
|
|
|
26027
26102
|
function resolveManifestMenuId(bound, menuCode) {
|
|
26028
26103
|
if (!menuCode) return undefined;
|
|
26029
|
-
return bound.resources?.menus?.[menuCode]?.menuId
|
|
26104
|
+
return bound.resources?.menus?.[menuCode]?.menuId;
|
|
26105
|
+
}
|
|
26106
|
+
|
|
26107
|
+
function menuResourceCode(menuItem) {
|
|
26108
|
+
return String(menuItem?.code || menuItem?.resourceCode || '').trim();
|
|
26109
|
+
}
|
|
26110
|
+
|
|
26111
|
+
function menuPlatformId(menuItem) {
|
|
26112
|
+
const value = menuItem?.id || menuItem?.menuId;
|
|
26113
|
+
return value ? String(value) : undefined;
|
|
26114
|
+
}
|
|
26115
|
+
|
|
26116
|
+
function resolveMenuParentId(bound, menuItem, existingMenus = new Map()) {
|
|
26117
|
+
const parentCode = String(menuItem?.parentCode || '').trim();
|
|
26118
|
+
if (!parentCode) return menuItem?.parentId || null;
|
|
26119
|
+
const boundId = resolveManifestMenuId(bound, parentCode);
|
|
26120
|
+
const onlineId = menuPlatformId(existingMenus.get(parentCode));
|
|
26121
|
+
return onlineId || boundId || menuItem?.parentId;
|
|
26122
|
+
}
|
|
26123
|
+
|
|
26124
|
+
function menuParentResolutionError(code, parentCode, label) {
|
|
26125
|
+
const error = new Error(
|
|
26126
|
+
`MENU_PARENT_UNRESOLVED: ${label || `menu ${code}`} 无法将 parentCode ${parentCode} 解析为在线 menuId`
|
|
26127
|
+
);
|
|
26128
|
+
error.code = 'MENU_PARENT_UNRESOLVED';
|
|
26129
|
+
return error;
|
|
26130
|
+
}
|
|
26131
|
+
|
|
26132
|
+
function requireResolvedMenuParentId(
|
|
26133
|
+
bound,
|
|
26134
|
+
menuItem,
|
|
26135
|
+
existingMenus = new Map(),
|
|
26136
|
+
label
|
|
26137
|
+
) {
|
|
26138
|
+
const parentId = resolveMenuParentId(bound, menuItem, existingMenus);
|
|
26139
|
+
if (menuItem?.parentCode && !parentId) {
|
|
26140
|
+
throw menuParentResolutionError(
|
|
26141
|
+
menuResourceCode(menuItem),
|
|
26142
|
+
menuItem.parentCode,
|
|
26143
|
+
label
|
|
26144
|
+
);
|
|
26145
|
+
}
|
|
26146
|
+
return parentId || null;
|
|
26147
|
+
}
|
|
26148
|
+
|
|
26149
|
+
function orderMenuResourcesForPublish(
|
|
26150
|
+
menus = [],
|
|
26151
|
+
bound = {},
|
|
26152
|
+
existingMenus = new Map()
|
|
26153
|
+
) {
|
|
26154
|
+
const items = Array.isArray(menus) ? menus : [];
|
|
26155
|
+
const byCode = new Map();
|
|
26156
|
+
const sourceIndex = new Map();
|
|
26157
|
+
for (const [index, menuItem] of items.entries()) {
|
|
26158
|
+
const code = menuResourceCode(menuItem);
|
|
26159
|
+
if (!code) {
|
|
26160
|
+
const error = new Error('MENU_CODE_REQUIRED: menu resource 缺少 code');
|
|
26161
|
+
error.code = 'MENU_CODE_REQUIRED';
|
|
26162
|
+
throw error;
|
|
26163
|
+
}
|
|
26164
|
+
if (byCode.has(code)) {
|
|
26165
|
+
const error = new Error(`MENU_CODE_DUPLICATE: menu code ${code} 重复`);
|
|
26166
|
+
error.code = 'MENU_CODE_DUPLICATE';
|
|
26167
|
+
throw error;
|
|
26168
|
+
}
|
|
26169
|
+
byCode.set(code, menuItem);
|
|
26170
|
+
sourceIndex.set(code, index);
|
|
26171
|
+
}
|
|
26172
|
+
|
|
26173
|
+
const children = new Map();
|
|
26174
|
+
const indegree = new Map([...byCode.keys()].map(code => [code, 0]));
|
|
26175
|
+
for (const [code, menuItem] of byCode) {
|
|
26176
|
+
const parentCode = String(menuItem.parentCode || '').trim();
|
|
26177
|
+
if (!parentCode) continue;
|
|
26178
|
+
if (!byCode.has(parentCode)) {
|
|
26179
|
+
if (!resolveMenuParentId(bound, menuItem, existingMenus)) {
|
|
26180
|
+
throw menuParentResolutionError(code, parentCode, `menu ${code}`);
|
|
26181
|
+
}
|
|
26182
|
+
continue;
|
|
26183
|
+
}
|
|
26184
|
+
indegree.set(code, indegree.get(code) + 1);
|
|
26185
|
+
const siblings = children.get(parentCode) || [];
|
|
26186
|
+
siblings.push(code);
|
|
26187
|
+
children.set(parentCode, siblings);
|
|
26188
|
+
}
|
|
26189
|
+
|
|
26190
|
+
const bySourceOrder = (left, right) =>
|
|
26191
|
+
sourceIndex.get(left) - sourceIndex.get(right);
|
|
26192
|
+
const ready = [...indegree.entries()]
|
|
26193
|
+
.filter(([, count]) => count === 0)
|
|
26194
|
+
.map(([code]) => code)
|
|
26195
|
+
.sort(bySourceOrder);
|
|
26196
|
+
const ordered = [];
|
|
26197
|
+
while (ready.length > 0) {
|
|
26198
|
+
const code = ready.shift();
|
|
26199
|
+
ordered.push(byCode.get(code));
|
|
26200
|
+
for (const childCode of (children.get(code) || []).sort(bySourceOrder)) {
|
|
26201
|
+
const next = indegree.get(childCode) - 1;
|
|
26202
|
+
indegree.set(childCode, next);
|
|
26203
|
+
if (next === 0) {
|
|
26204
|
+
ready.push(childCode);
|
|
26205
|
+
ready.sort(bySourceOrder);
|
|
26206
|
+
}
|
|
26207
|
+
}
|
|
26208
|
+
}
|
|
26209
|
+
if (ordered.length !== items.length) {
|
|
26210
|
+
const cycleCodes = [...indegree.entries()]
|
|
26211
|
+
.filter(([, count]) => count > 0)
|
|
26212
|
+
.map(([code]) => code)
|
|
26213
|
+
.sort(bySourceOrder);
|
|
26214
|
+
const error = new Error(
|
|
26215
|
+
`MENU_PARENT_CYCLE: menu parentCode 存在循环依赖: ${cycleCodes.join(' -> ')}`
|
|
26216
|
+
);
|
|
26217
|
+
error.code = 'MENU_PARENT_CYCLE';
|
|
26218
|
+
throw error;
|
|
26219
|
+
}
|
|
26220
|
+
return ordered;
|
|
26030
26221
|
}
|
|
26031
26222
|
|
|
26032
26223
|
function resolveAutomationManifestPayload(target, automationItem) {
|
|
@@ -26178,12 +26369,16 @@ function unwrapFormSettingPlanValue(value, key) {
|
|
|
26178
26369
|
return value;
|
|
26179
26370
|
}
|
|
26180
26371
|
|
|
26181
|
-
function menuEquals(bound, desired, existing) {
|
|
26372
|
+
function menuEquals(bound, desired, existing, existingMenus = new Map()) {
|
|
26182
26373
|
if (!existing) return false;
|
|
26183
26374
|
const desiredFormUuid = resolveManifestFormUuid(bound, desired);
|
|
26184
26375
|
const desiredPageId = resolveManifestPageId(bound, desired);
|
|
26185
|
-
const desiredParentId =
|
|
26186
|
-
|
|
26376
|
+
const desiredParentId = resolveMenuParentId(
|
|
26377
|
+
bound,
|
|
26378
|
+
desired,
|
|
26379
|
+
existingMenus
|
|
26380
|
+
);
|
|
26381
|
+
if (desired.parentCode && !desiredParentId) return false;
|
|
26187
26382
|
return (
|
|
26188
26383
|
String(existing.name || '') === String(desired.name || desired.code || '') &&
|
|
26189
26384
|
String(existing.type || '') === String(desired.type || 'nav') &&
|