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

67 lines
3.4 KiB
JavaScript

import fs from 'node:fs'
import path from 'node:path'
const root=process.cwd();const failures=[]
const read=file=>fs.readFileSync(path.join(root,file),'utf8')
const exists=file=>fs.existsSync(path.join(root,file))
const templates=[
'packages/kbx-ui/src/components/KbxListPage.vue',
'packages/kbx-ui/src/components/KbxMasterPage.vue',
'packages/kbx-ui/src/components/KbxTransactionPage.vue',
'packages/kbx-ui/src/components/KbxFastEntryPage.vue',
'packages/kbx-ui/src/components/KbxMasterDetailPage.vue',
'packages/kbx-ui/src/components/KbxQueuePage.vue',
'packages/kbx-ui/src/components/KbxReconcilePage.vue',
'packages/kbx-ui/src/components/KbxImportPage.vue',
]
for(const file of templates){
if(!exists(file)){failures.push(`missing desktop template ${file}`);continue}
if(!read(file).includes('KbxScreenFrame'))failures.push(`${file} must compose KbxScreenFrame`)
}
const mobileTemplate='packages/kbx-ui/src/wms/KbxWmsMobilePage.vue'
if(!exists(mobileTemplate))failures.push(`missing mobile template ${mobileTemplate}`)
else{
const text=read(mobileTemplate)
for(const contract of ['KbxNetworkIndicator','data-screen-type="wms-mobile"','name="actions"'])if(!text.includes(contract))failures.push(`KbxWmsMobilePage missing ${contract}`)
}
const frame='packages/kbx-ui/src/components/KbxScreenFrame.vue'
if(!exists(frame))failures.push('missing KbxScreenFrame')
else{
const text=read(frame)
for(const contract of ['KbxPageHeader','KbxCommandBar','data-screen-type','is-sticky'])if(!text.includes(contract))failures.push(`KbxScreenFrame missing ${contract}`)
}
const workQueue=read('packages/kbx-ui/src/components/KbxWorkQueuePage.vue')
if(!workQueue.includes('KbxQueuePage'))failures.push('KbxWorkQueuePage must be a compatibility wrapper over KbxQueuePage')
const index=read('packages/kbx-ui/src/index.ts')
for(const component of ['KbxCheckbox','KbxRadio','KbxTextarea','KbxTabs','KbxBadge','KbxTooltip','KbxBarcodeField','KbxSectionHeader','KbxQuickFilterBar','KbxSummaryBar','KbxHomePage','KbxAccessDenied']){
if(!index.includes(`as ${component}`))failures.push(`public API missing ${component}`)
}
const frameApp=read('apps/web/src/shell/KbxAppFrame.vue')
for(const contract of ['KbxHomePage','KbxAccessDenied','activeScreenAllowed','allowedEntries'])if(!frameApp.includes(contract))failures.push(`KbxAppFrame missing ${contract}`)
const routes=read('apps/web/src/router/appRoutes.ts')
if(!routes.includes("{path:'/',redirect:'/home'}"))failures.push('root route must redirect to /home')
if(!routes.includes("path:'/home'"))failures.push('/home route missing')
const side=read('packages/kbx-ui/src/shell/KbxSideNavigation.vue')
for(const contract of ["emit('home')",'collapsed-actions','즐겨찾기','최근메뉴'])if(!side.includes(contract))failures.push(`side navigation missing ${contract}`)
const golden=[
'apps/web/src/modules/oms/orders/search/OrderListPage.vue',
'apps/web/src/modules/oms/orders/register/OrderRegisterPage.vue',
'apps/web/src/modules/erp/items/ItemMasterPage.vue',
'apps/web/src/modules/wms/picking/WmsPickingPage.vue',
]
for(const file of golden){
const text=read(file)
if(/<button\b|<input\b|<select\b/.test(text))failures.push(`${file} bypasses KBX primitives/business components`)
}
if(failures.length){console.error(failures.join('\n'));process.exit(1)}
console.log(`Template completeness validation passed for ${templates.length} desktop templates + T09 mobile, Home, navigation, and Golden Screens.`)