openxiangda 1.0.229 → 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 +410 -47
- package/package.json +1 -1
package/lib/cli.js
CHANGED
|
@@ -14212,18 +14212,36 @@ async function resource(args) {
|
|
|
14212
14212
|
.map(item => item.formCode || item.form)
|
|
14213
14213
|
.filter(Boolean)
|
|
14214
14214
|
);
|
|
14215
|
+
const scopeGrantSourceNeedsInitialSync = (
|
|
14216
|
+
manifest.scopeGrantSources || []
|
|
14217
|
+
).some(item => item.sync === true);
|
|
14215
14218
|
const stagedChangeId =
|
|
14216
14219
|
readStringFlag(flags, 'change') ||
|
|
14217
14220
|
getStoredChangeBaseline(target, { access: 'reconciliation-read' })
|
|
14218
14221
|
?.changeId ||
|
|
14219
14222
|
'';
|
|
14220
|
-
|
|
14223
|
+
const scopeGrantSourceFormCodes =
|
|
14224
|
+
scopeGrantSourceNeedsInitialSync && stagedChangeId
|
|
14225
|
+
? await resolveScopeGrantSourceFormCodes(
|
|
14226
|
+
config,
|
|
14227
|
+
target,
|
|
14228
|
+
manifest.scopeGrantSources || []
|
|
14229
|
+
)
|
|
14230
|
+
: [];
|
|
14231
|
+
const stagedContractFormCodes = unique([
|
|
14232
|
+
...workflowFormCodes,
|
|
14233
|
+
...scopeGrantSourceFormCodes,
|
|
14234
|
+
]).sort();
|
|
14235
|
+
if (
|
|
14236
|
+
stagedContractFormCodes.length > 0 &&
|
|
14237
|
+
stagedChangeId
|
|
14238
|
+
) {
|
|
14221
14239
|
stagedFormBindingOverlays =
|
|
14222
14240
|
await resolveReusableStagedFormReleaseOverlays(
|
|
14223
14241
|
config,
|
|
14224
14242
|
target,
|
|
14225
14243
|
stagedChangeId,
|
|
14226
|
-
{ formCodes:
|
|
14244
|
+
{ formCodes: stagedContractFormCodes }
|
|
14227
14245
|
);
|
|
14228
14246
|
}
|
|
14229
14247
|
validateWorkspaceResourceBindings(
|
|
@@ -14381,6 +14399,7 @@ async function resource(args) {
|
|
|
14381
14399
|
replaceManifest: Boolean(flags['replace-manifest']),
|
|
14382
14400
|
changeId:
|
|
14383
14401
|
flags.change || getStoredChangeBaseline(target)?.changeId || null,
|
|
14402
|
+
stagedFormBindingOverlays,
|
|
14384
14403
|
activateFormBundles: Boolean(flags.activate),
|
|
14385
14404
|
stageBackendReleaseOnly:
|
|
14386
14405
|
Boolean(flags['stage-only']) &&
|
|
@@ -16290,7 +16309,12 @@ function removeDirectStateResource(target, resourceType, code) {
|
|
|
16290
16309
|
function normalizeMenuDirectBody(bound, menuItem) {
|
|
16291
16310
|
const formUuid = resolveManifestFormUuid(bound, menuItem);
|
|
16292
16311
|
const pageId = resolveManifestPageId(bound, menuItem);
|
|
16293
|
-
const parentId =
|
|
16312
|
+
const parentId = requireResolvedMenuParentId(
|
|
16313
|
+
bound,
|
|
16314
|
+
menuItem,
|
|
16315
|
+
new Map(),
|
|
16316
|
+
'direct menu mutation'
|
|
16317
|
+
);
|
|
16294
16318
|
return stripUndefinedValues({
|
|
16295
16319
|
resourceCode: menuItem.code || menuItem.resourceCode,
|
|
16296
16320
|
name: menuItem.name || menuItem.code,
|
|
@@ -19068,7 +19092,19 @@ async function buildResourcePlan(
|
|
|
19068
19092
|
]);
|
|
19069
19093
|
const actions = [];
|
|
19070
19094
|
addPlanActions(actions, 'role', manifest.roles, existing.roles, roleEquals);
|
|
19071
|
-
|
|
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
|
+
);
|
|
19072
19108
|
addPlanActions(actions, 'connector', manifest.connectors, existing.connectors, connectorEquals);
|
|
19073
19109
|
addNotificationPlanActions(target, actions, manifest.notifications || [], existing);
|
|
19074
19110
|
await addWorkflowPlanActions(config, target, actions, manifest.workflows, existing.workflows);
|
|
@@ -22575,21 +22611,61 @@ async function publishFormSettingsResources(
|
|
|
22575
22611
|
}
|
|
22576
22612
|
|
|
22577
22613
|
async function publishMenuResources(config, target, menus, result, options = {}) {
|
|
22578
|
-
|
|
22579
|
-
|
|
22580
|
-
|
|
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);
|
|
22581
22656
|
continue;
|
|
22582
22657
|
}
|
|
22583
|
-
const existing = await findExistingMenu(config, target, menuItem.code);
|
|
22584
22658
|
const formUuid = resolveManifestFormUuid(target.bound, menuItem);
|
|
22585
22659
|
const pageId = resolveManifestPageId(target.bound, menuItem);
|
|
22586
|
-
const parentId =
|
|
22587
|
-
|
|
22588
|
-
menuItem
|
|
22589
|
-
|
|
22660
|
+
const parentId = requireResolvedMenuParentId(
|
|
22661
|
+
target.bound,
|
|
22662
|
+
menuItem,
|
|
22663
|
+
existingMenus,
|
|
22664
|
+
`resource publish menu ${code}`
|
|
22665
|
+
);
|
|
22590
22666
|
const body = {
|
|
22591
|
-
resourceCode:
|
|
22592
|
-
name: menuItem.name ||
|
|
22667
|
+
resourceCode: code,
|
|
22668
|
+
name: menuItem.name || code,
|
|
22593
22669
|
type: menuItem.type || 'nav',
|
|
22594
22670
|
formUuid,
|
|
22595
22671
|
pageId,
|
|
@@ -22600,11 +22676,12 @@ async function publishMenuResources(config, target, menus, result, options = {})
|
|
|
22600
22676
|
routeCode: menuItem.routeCode || null,
|
|
22601
22677
|
path: menuItem.path || null,
|
|
22602
22678
|
};
|
|
22679
|
+
const existingId = menuPlatformId(existing);
|
|
22603
22680
|
let data = existing
|
|
22604
22681
|
? await requestWithAuth(
|
|
22605
22682
|
config,
|
|
22606
22683
|
target.profileName,
|
|
22607
|
-
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus/${encodeURIComponent(
|
|
22684
|
+
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus/${encodeURIComponent(existingId)}`,
|
|
22608
22685
|
{ method: 'POST', body }
|
|
22609
22686
|
)
|
|
22610
22687
|
: await requestWithAuth(
|
|
@@ -22613,37 +22690,54 @@ async function publishMenuResources(config, target, menus, result, options = {})
|
|
|
22613
22690
|
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus`,
|
|
22614
22691
|
{ method: 'POST', body }
|
|
22615
22692
|
);
|
|
22616
|
-
if (data?.id) {
|
|
22617
|
-
|
|
22618
|
-
|
|
22619
|
-
|
|
22620
|
-
|
|
22621
|
-
|
|
22622
|
-
...(pageId ? { pageId } : {}),
|
|
22623
|
-
...(menuItem.pageCode ? { pageCode: menuItem.pageCode } : {}),
|
|
22624
|
-
...(menuItem.routeCode || data.routeCode
|
|
22625
|
-
? { routeCode: data.routeCode || menuItem.routeCode }
|
|
22626
|
-
: {}),
|
|
22627
|
-
...(menuItem.path || data.path ? { path: data.path || menuItem.path } : {}),
|
|
22628
|
-
});
|
|
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;
|
|
22629
22699
|
}
|
|
22630
|
-
|
|
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
|
+
});
|
|
22631
22725
|
}
|
|
22632
22726
|
}
|
|
22633
22727
|
|
|
22634
|
-
async function
|
|
22728
|
+
async function fetchExistingMenusByCode(config, target) {
|
|
22635
22729
|
const data = await requestWithAuth(
|
|
22636
22730
|
config,
|
|
22637
22731
|
target.profileName,
|
|
22638
22732
|
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/menus`
|
|
22639
22733
|
);
|
|
22640
|
-
const
|
|
22641
|
-
|
|
22642
|
-
|
|
22643
|
-
|
|
22644
|
-
|
|
22645
|
-
|
|
22646
|
-
return
|
|
22734
|
+
const menus = new Map();
|
|
22735
|
+
indexByCode(
|
|
22736
|
+
menus,
|
|
22737
|
+
flattenItems(normalizeItems(data)),
|
|
22738
|
+
item => item.resourceCode
|
|
22739
|
+
);
|
|
22740
|
+
return menus;
|
|
22647
22741
|
}
|
|
22648
22742
|
|
|
22649
22743
|
async function publishConnectorResources(config, target, connectors, result, options = {}) {
|
|
@@ -23293,7 +23387,84 @@ async function publishScopeDimensionResources(config, target, dimensions, result
|
|
|
23293
23387
|
}
|
|
23294
23388
|
}
|
|
23295
23389
|
|
|
23390
|
+
async function resolveScopeGrantSourceFormCodes(
|
|
23391
|
+
config,
|
|
23392
|
+
target,
|
|
23393
|
+
sources = []
|
|
23394
|
+
) {
|
|
23395
|
+
const formCodes = [];
|
|
23396
|
+
const appendFormCode = value => {
|
|
23397
|
+
const candidate = String(value || '').trim();
|
|
23398
|
+
if (!candidate) return;
|
|
23399
|
+
if (target.bound.resources?.forms?.[candidate]?.formUuid) {
|
|
23400
|
+
formCodes.push(candidate);
|
|
23401
|
+
return;
|
|
23402
|
+
}
|
|
23403
|
+
for (const [code, entry] of Object.entries(
|
|
23404
|
+
target.bound.resources?.forms || {}
|
|
23405
|
+
)) {
|
|
23406
|
+
if (String(entry?.formUuid || '').trim() === candidate) {
|
|
23407
|
+
formCodes.push(code);
|
|
23408
|
+
return;
|
|
23409
|
+
}
|
|
23410
|
+
}
|
|
23411
|
+
};
|
|
23412
|
+
const dimensionCodes = new Set();
|
|
23413
|
+
for (const source of sources || []) {
|
|
23414
|
+
appendFormCode(
|
|
23415
|
+
source.sourceFormCode ||
|
|
23416
|
+
source.formCode ||
|
|
23417
|
+
source.sourceFormUuid ||
|
|
23418
|
+
source.formUuid
|
|
23419
|
+
);
|
|
23420
|
+
for (const mapping of source.dimensionMappings || source.dimensions || []) {
|
|
23421
|
+
const code = String(
|
|
23422
|
+
mapping?.dimensionCode || mapping?.dimension || ''
|
|
23423
|
+
).trim();
|
|
23424
|
+
if (code) dimensionCodes.add(code);
|
|
23425
|
+
}
|
|
23426
|
+
}
|
|
23427
|
+
if (dimensionCodes.size > 0) {
|
|
23428
|
+
const dimensions = await requestWithAuth(
|
|
23429
|
+
config,
|
|
23430
|
+
target.profileName,
|
|
23431
|
+
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/scope/dimensions`
|
|
23432
|
+
);
|
|
23433
|
+
for (const dimension of normalizeItems(dimensions)) {
|
|
23434
|
+
const code = String(
|
|
23435
|
+
dimension?.code || dimension?.resourceCode || ''
|
|
23436
|
+
).trim();
|
|
23437
|
+
if (!dimensionCodes.has(code)) continue;
|
|
23438
|
+
appendFormCode(dimension.sourceFormUuid || dimension.formUuid);
|
|
23439
|
+
}
|
|
23440
|
+
}
|
|
23441
|
+
return unique(formCodes).sort();
|
|
23442
|
+
}
|
|
23443
|
+
|
|
23296
23444
|
async function publishScopeGrantSourceResources(config, target, sources, result, options = {}) {
|
|
23445
|
+
const stagedFormBindingOverlays =
|
|
23446
|
+
options.stagedFormBindingOverlays instanceof Map
|
|
23447
|
+
? options.stagedFormBindingOverlays
|
|
23448
|
+
: new Map();
|
|
23449
|
+
let dimensionMap = new Map();
|
|
23450
|
+
if (
|
|
23451
|
+
stagedFormBindingOverlays.size > 0 &&
|
|
23452
|
+
(sources || []).some(item => item.sync === true)
|
|
23453
|
+
) {
|
|
23454
|
+
const dimensions = await requestWithAuth(
|
|
23455
|
+
config,
|
|
23456
|
+
target.profileName,
|
|
23457
|
+
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/scope/dimensions`
|
|
23458
|
+
);
|
|
23459
|
+
dimensionMap = new Map(
|
|
23460
|
+
normalizeItems(dimensions)
|
|
23461
|
+
.map(item => [
|
|
23462
|
+
String(item.code || item.resourceCode || '').trim(),
|
|
23463
|
+
item,
|
|
23464
|
+
])
|
|
23465
|
+
.filter(([code]) => Boolean(code))
|
|
23466
|
+
);
|
|
23467
|
+
}
|
|
23297
23468
|
for (const item of sources) {
|
|
23298
23469
|
const code = item.code || item.resourceCode;
|
|
23299
23470
|
if (shouldSkipNoopResource(options, 'scopeGrantSource', code)) {
|
|
@@ -23316,17 +23487,88 @@ async function publishScopeGrantSourceResources(config, target, sources, result,
|
|
|
23316
23487
|
id: data?.id,
|
|
23317
23488
|
};
|
|
23318
23489
|
if (item.sync === true) {
|
|
23319
|
-
|
|
23320
|
-
|
|
23321
|
-
|
|
23322
|
-
|
|
23323
|
-
|
|
23324
|
-
)
|
|
23490
|
+
const syncDecision = buildScopeGrantSourceSyncDecision({
|
|
23491
|
+
source: body,
|
|
23492
|
+
dimensionMap,
|
|
23493
|
+
stagedFormBindingOverlays,
|
|
23494
|
+
});
|
|
23495
|
+
if (syncDecision.defer) {
|
|
23496
|
+
published.sync = {
|
|
23497
|
+
status: 'deferred-until-form-activation',
|
|
23498
|
+
reason: syncDecision.reason,
|
|
23499
|
+
formUuids: syncDecision.formUuids,
|
|
23500
|
+
formCodes: syncDecision.formCodes,
|
|
23501
|
+
resumeTrigger: 'on_write_after_app_finalize',
|
|
23502
|
+
};
|
|
23503
|
+
result.warnings.push(
|
|
23504
|
+
`scopeGrantSource:${code}: 初始同步依赖同一 deployment 的新 staged FormRelease,当前尚无 active 数据表;已保存 on_write 配置,App finalize 后首次表单写入会自动物化`
|
|
23505
|
+
);
|
|
23506
|
+
} else {
|
|
23507
|
+
published.sync = await requestWithAuth(
|
|
23508
|
+
config,
|
|
23509
|
+
target.profileName,
|
|
23510
|
+
`/openxiangda-api/v1/apps/${encodeURIComponent(target.appType)}/scope/grant-sources/${encodeURIComponent(code)}/sync`,
|
|
23511
|
+
{ method: 'POST', body: { dryRun: false } }
|
|
23512
|
+
);
|
|
23513
|
+
}
|
|
23325
23514
|
}
|
|
23326
23515
|
result.published.push(published);
|
|
23327
23516
|
}
|
|
23328
23517
|
}
|
|
23329
23518
|
|
|
23519
|
+
function buildScopeGrantSourceSyncDecision({
|
|
23520
|
+
source,
|
|
23521
|
+
dimensionMap = new Map(),
|
|
23522
|
+
stagedFormBindingOverlays = new Map(),
|
|
23523
|
+
} = {}) {
|
|
23524
|
+
const stagedNewForms = new Map(
|
|
23525
|
+
Array.from(stagedFormBindingOverlays.values())
|
|
23526
|
+
.filter(item => item?.parentReleaseId === null && item?.formUuid)
|
|
23527
|
+
.map(item => [
|
|
23528
|
+
String(item.formUuid).trim(),
|
|
23529
|
+
String(item.formCode || '').trim(),
|
|
23530
|
+
])
|
|
23531
|
+
);
|
|
23532
|
+
if (stagedNewForms.size === 0) {
|
|
23533
|
+
return {
|
|
23534
|
+
defer: false,
|
|
23535
|
+
reason: null,
|
|
23536
|
+
formUuids: [],
|
|
23537
|
+
formCodes: [],
|
|
23538
|
+
};
|
|
23539
|
+
}
|
|
23540
|
+
const referencedFormUuids = [
|
|
23541
|
+
source?.sourceFormUuid,
|
|
23542
|
+
...(source?.dimensionMappings || []).map(mapping => {
|
|
23543
|
+
const code = String(
|
|
23544
|
+
mapping?.dimensionCode || mapping?.dimension || ''
|
|
23545
|
+
).trim();
|
|
23546
|
+
const dimension = dimensionMap.get(code);
|
|
23547
|
+
return dimension?.sourceFormUuid || dimension?.formUuid;
|
|
23548
|
+
}),
|
|
23549
|
+
]
|
|
23550
|
+
.map(value => String(value || '').trim())
|
|
23551
|
+
.filter(Boolean);
|
|
23552
|
+
const formUuids = unique(
|
|
23553
|
+
referencedFormUuids.filter(formUuid =>
|
|
23554
|
+
stagedNewForms.has(formUuid)
|
|
23555
|
+
)
|
|
23556
|
+
).sort();
|
|
23557
|
+
return {
|
|
23558
|
+
defer: formUuids.length > 0,
|
|
23559
|
+
reason:
|
|
23560
|
+
formUuids.length > 0
|
|
23561
|
+
? 'staged_new_form_has_no_active_data_table'
|
|
23562
|
+
: null,
|
|
23563
|
+
formUuids,
|
|
23564
|
+
formCodes: unique(
|
|
23565
|
+
formUuids
|
|
23566
|
+
.map(formUuid => stagedNewForms.get(formUuid))
|
|
23567
|
+
.filter(Boolean)
|
|
23568
|
+
).sort(),
|
|
23569
|
+
};
|
|
23570
|
+
}
|
|
23571
|
+
|
|
23330
23572
|
async function publishDataScopePolicyResources(config, target, policies, result, options = {}) {
|
|
23331
23573
|
for (const item of policies) {
|
|
23332
23574
|
const code = item.code || item.resourceCode;
|
|
@@ -25859,7 +26101,123 @@ function resolveManifestPageId(bound, item) {
|
|
|
25859
26101
|
|
|
25860
26102
|
function resolveManifestMenuId(bound, menuCode) {
|
|
25861
26103
|
if (!menuCode) return undefined;
|
|
25862
|
-
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;
|
|
25863
26221
|
}
|
|
25864
26222
|
|
|
25865
26223
|
function resolveAutomationManifestPayload(target, automationItem) {
|
|
@@ -26011,12 +26369,16 @@ function unwrapFormSettingPlanValue(value, key) {
|
|
|
26011
26369
|
return value;
|
|
26012
26370
|
}
|
|
26013
26371
|
|
|
26014
|
-
function menuEquals(bound, desired, existing) {
|
|
26372
|
+
function menuEquals(bound, desired, existing, existingMenus = new Map()) {
|
|
26015
26373
|
if (!existing) return false;
|
|
26016
26374
|
const desiredFormUuid = resolveManifestFormUuid(bound, desired);
|
|
26017
26375
|
const desiredPageId = resolveManifestPageId(bound, desired);
|
|
26018
|
-
const desiredParentId =
|
|
26019
|
-
|
|
26376
|
+
const desiredParentId = resolveMenuParentId(
|
|
26377
|
+
bound,
|
|
26378
|
+
desired,
|
|
26379
|
+
existingMenus
|
|
26380
|
+
);
|
|
26381
|
+
if (desired.parentCode && !desiredParentId) return false;
|
|
26020
26382
|
return (
|
|
26021
26383
|
String(existing.name || '') === String(desired.name || desired.code || '') &&
|
|
26022
26384
|
String(existing.type || '') === String(desired.type || 'nav') &&
|
|
@@ -29263,6 +29625,7 @@ function buildWorkspacePublishEnv(
|
|
|
29263
29625
|
|
|
29264
29626
|
module.exports = {
|
|
29265
29627
|
buildResourceManifestSddTargets,
|
|
29628
|
+
buildScopeGrantSourceSyncDecision,
|
|
29266
29629
|
main,
|
|
29267
29630
|
satisfiedFormCodesFromContext,
|
|
29268
29631
|
};
|