Files
KArtSell.Aegis/docs/Design/kbx-foundation-v36/scripts/validate-template-navigation-v29.mjs
T

27 lines
4.6 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
const root=process.cwd();const fail=[];const read=p=>fs.readFileSync(path.join(root,p),'utf8')
const manifest=read('packages/kbx-ui/src/registry/templateManifest.ts')
for(const code of ['T01','T02','T03','T04','T05','T06','T07','T08','T09']){
if(!manifest.includes(`code:'${code}'`))fail.push(`template manifest missing ${code}`)
}
for(const x of ['defaultDensity','runtimeStates','utilitySurfaces','accessibility'])if((manifest.match(new RegExp(x,'g'))??[]).length<9)fail.push(`all T01-T09 manifest entries must declare ${x}`)
for(const state of ['loading','empty','error','ready'])if(!manifest.includes(`'${state}'`))fail.push(`template runtime state missing ${state}`)
const boundary=read('packages/kbx-ui/src/components/KbxTemplateStateBoundary.vue');for(const x of ['KbxDataState','refreshing','현재 화면은 유지됩니다','@action="emit(\'retry\')"'])if(!boundary.includes(x))fail.push(`Template state boundary missing ${x}`)
for(const file of ['KbxListPage.vue','KbxMasterPage.vue','KbxTransactionPage.vue','KbxFastEntryPage.vue','KbxMasterDetailPage.vue','KbxQueuePage.vue','KbxReconcilePage.vue','KbxImportPage.vue']){
const text=read(`packages/kbx-ui/src/components/${file}`);if(!text.includes('KbxTemplateStateBoundary'))fail.push(`${file} missing runtime state boundary`);if(!text.includes('suppress-default-utility'))fail.push(`${file} missing default utility override contract`)
}
const wms=read('packages/kbx-ui/src/wms/KbxWmsMobilePage.vue');for(const x of ['KbxTemplateStateBoundary','KbxScreenUtilityHostKey','helpAvailable'])if(!wms.includes(x))fail.push(`T09 missing ${x}`)
const frame=read('packages/kbx-ui/src/components/KbxScreenFrame.vue');for(const x of ['KbxScreenUtilityHostKey','defaultUtilities','도움말','suggestion'])if(!frame.includes(x))fail.push(`ScreenFrame missing global utility contract ${x}`)
const app=read('apps/web/src/shell/KbxAppFrame.vue');for(const x of ['provide(KbxScreenUtilityHostKey','KbxUtilityRail','resolveKbxSafeRecentPath','pruneTabs','previous!==undefined&&scope!==previous','runtimePanel.value=null','shellNotice'])if(!app.includes(x))fail.push(`AppFrame hardening missing ${x}`)
const store=read('apps/web/src/shell/workspaceStore.ts');for(const x of ['clearWorkspaceSession','evictForCapacity','!tab.dirty&&!tab.pinned','pruneTabs','workspaceMaxTabs','catch{shellNotice.value='])if(!store.includes(x))fail.push(`Workspace hardening missing ${x}`)
const security=read('packages/kbx-ui/src/shell/navigationSecurity.ts');for(const x of ['candidate.origin!==base.origin','candidatePath.startsWith','recentPolicy'])if(!security.includes(x))fail.push(`Navigation security missing ${x}`)
const homeLogic=read('packages/kbx-ui/src/shell/homeNavigation.ts');for(const x of ['favorites.forEach','lastActivatedAt','recents.forEach','homePriority','seen'])if(!homeLogic.includes(x))fail.push(`Home quick-start policy missing ${x}`)
const home=read('packages/kbx-ui/src/shell/KbxHomePage.vue');if(!(home.includes('주요 업무')||home.includes('바로 시작')))fail.push('Home completion missing primary work surface');if(!(home.includes('buildKbxHomeQuickStart')||home.includes('buildKbxHomeWorkbench')))fail.push('Home completion missing quick-start/workbench policy');for(const x of ['미저장 업무','homeGroup'])if(!home.includes(x))fail.push(`Home completion missing ${x}`)
const nav=read('apps/web/src/shell/navigationCatalog.ts');if((nav.match(/homePriority:/g)??[]).length<7)fail.push('navigation catalog needs business quick-start priorities')
const menu=read('packages/kbx-ui/src/shell/KbxMenuSearch.vue');for(const x of ['trapTab','role="combobox"','role="listbox"','aria-activedescendant'])if(!menu.includes(x))fail.push(`Menu search accessibility missing ${x}`)
const shell=read('packages/kbx-ui/src/shell/KbxApplicationShell.vue');for(const x of ['workspaceMaxTabs?:number','shellNotice?:string','dismissShellNotice','shell-notice'])if(!shell.includes(x))fail.push(`Application shell completion missing ${x}`)
for(const file of ['apps/web/src/modules/oms/orders/search/OrderListPage.vue','apps/web/src/modules/common/operations/OperationsQueuePage.vue','apps/web/src/modules/common/reconcile/ReconcilePage.vue','apps/web/src/modules/erp/inventory/InventoryPage.vue'])if(!read(file).includes('content-state'))fail.push(`${file} must demonstrate template runtime state contract`)
if(fail.length){console.error(fail.join('\n'));process.exit(1)}
console.log('v29 template/home navigation validation passed: T01-T09 runtime states, global utilities, quick-start IA, scoped workspace isolation, safe recents, max-tab enforcement, and search accessibility.')