fix: harden module outline normalization

This commit is contained in:
王鹏
2026-07-07 14:05:06 +08:00
parent 0e3d2f09a2
commit 27aaa13fcc
2 changed files with 46 additions and 12 deletions

View File

@@ -11,8 +11,10 @@ function textFromFields(value, fallback = '') {
return cleanText(value.title ?? value.name ?? value.code, fallback) return cleanText(value.title ?? value.name ?? value.code, fallback)
} }
function menuTitle(menu, index) { function menuToItem(menu) {
return cleanText(menu?.name ?? menu?.title ?? menu?.code, `功能${index + 1}`) if (!menu || typeof menu !== 'object') return null
const title = cleanText(menu.name ?? menu.title ?? menu.code)
return title ? { title } : null
} }
function warning(code, line) { function warning(code, line) {
@@ -30,12 +32,15 @@ export function normalizeModuleOutline(outline = {}) {
const groups = Array.isArray(outline.groups) ? outline.groups : [] const groups = Array.isArray(outline.groups) ? outline.groups : []
return { return {
title: textFromFields(outline), title: textFromFields(outline),
groups: groups.map((group) => ({ groups: groups.map((group) => {
title: textFromFields(group), const items = (Array.isArray(group?.items) ? group.items : []).map((item) => ({
items: (Array.isArray(group?.items) ? group.items : []).map((item) => ({
title: textFromFields(item) title: textFromFields(item)
})).filter((item) => item.title) })).filter((item) => item.title)
})).filter((group) => group.title || group.items.length) return {
title: textFromFields(group, items.length ? FALLBACK_GROUP_TITLE : ''),
items
}
}).filter((group) => group.title || group.items.length)
} }
} }
@@ -94,15 +99,11 @@ export function blueprintToModuleOutline(blueprint = {}, options = {}) {
const groups = [ const groups = [
{ {
title: '管理员端', title: '管理员端',
items: (Array.isArray(blueprint.adminMenus) ? blueprint.adminMenus : []).map((menu, index) => ({ items: (Array.isArray(blueprint.adminMenus) ? blueprint.adminMenus : []).map(menuToItem).filter(Boolean)
title: menuTitle(menu, index)
})).filter((item) => item.title)
}, },
{ {
title: '普通用户端', title: '普通用户端',
items: (Array.isArray(blueprint.frontendMenus) ? blueprint.frontendMenus : []).map((menu, index) => ({ items: (Array.isArray(blueprint.frontendMenus) ? blueprint.frontendMenus : []).map(menuToItem).filter(Boolean)
title: menuTitle(menu, index)
})).filter((item) => item.title)
} }
].filter((group) => group.items.length) ].filter((group) => group.items.length)

View File

@@ -95,6 +95,39 @@ test('blueprintToModuleOutline maps project menus into standard groups', () => {
assert.deepEqual(outline.groups[1].items.map((item) => item.title), ['社团浏览', 'profile']) assert.deepEqual(outline.groups[1].items.map((item) => item.title), ['社团浏览', 'profile'])
}) })
test('blueprintToModuleOutline skips invalid menus while preserving code-only menus', () => {
const outline = blueprintToModuleOutline({
adminMenus: [
null,
'菜单',
{},
{ name: ' ', title: '', code: '\t' },
{ code: 'users' }
],
frontendMenus: [
undefined,
{ title: ' ' },
{ code: 'browse' }
]
})
assert.deepEqual(outline.groups.map((group) => group.title), ['管理员端', '普通用户端'])
assert.deepEqual(outline.groups[0].items.map((item) => item.title), ['users'])
assert.deepEqual(outline.groups[1].items.map((item) => item.title), ['browse'])
})
test('normalizeModuleOutline gives untitled groups with items the fallback group title', () => {
const outline = normalizeModuleOutline({
title: '客户管理系统',
groups: [
{ title: ' ', items: [{ title: '客户列表' }] }
]
})
assert.equal(outline.groups[0].title, '未分组模块')
assert.equal(moduleOutlineToText(outline), '客户管理系统\n 未分组模块\n 客户列表')
})
test('moduleOutlineToText serializes normalized outlines with two-space levels', () => { test('moduleOutlineToText serializes normalized outlines with two-space levels', () => {
const outline = normalizeModuleOutline({ const outline = normalizeModuleOutline({
title: '学生社团管理系统', title: '学生社团管理系统',