64 lines
6.2 KiB
JavaScript
64 lines
6.2 KiB
JavaScript
import fs from 'node:fs'
|
|
import path from 'node:path'
|
|
const root=process.cwd(); const failures=[]
|
|
const read=p=>fs.readFileSync(path.join(root,p),'utf8')
|
|
const must=(text,needles,scope)=>needles.forEach(n=>{if(!text.includes(n))failures.push(`${scope} missing ${n}`)})
|
|
|
|
const ui=read('packages/kbx-contracts/src/ui.ts')
|
|
must(ui,["export type KbxAsyncState = 'idle' | 'ready' | 'loading' | 'empty' | 'error'"],'async state contract')
|
|
const screen=read('packages/kbx-contracts/src/screen.ts')
|
|
must(screen,['export type KbxTemplateStateCapability',"| 'permission'","| 'dirty'","| 'conflict'","| 'validation'","| 'job'","| 'network'",'stateCapabilities: KbxTemplateStateCapability[]'],'template state capability contract')
|
|
const manifest=read('packages/kbx-ui/src/registry/templateManifest.ts')
|
|
for(const code of ['T01','T02','T03','T04','T05','T06','T07','T08','T09']){
|
|
const line=manifest.split('\n').find(value=>value.includes(`code:'${code}'`))??''
|
|
must(line,['stateCapabilities:','\'permission\''],`${code} state capability matrix`)
|
|
}
|
|
must(manifest,["const commonStates=['idle','loading','empty','error','ready']", "stateCapabilities:['idle','loading','refreshing','empty','error','permission']", "stateCapabilities:['loading','refreshing','error','permission','dirty','conflict','validation']", "stateCapabilities:['loading','refreshing','error','permission','validation','job']", "stateCapabilities:['loading','refreshing','error','permission','network']"],'state matrix applicability')
|
|
|
|
const dataState=read('packages/kbx-ui/src/components/KbxDataState.vue')
|
|
must(dataState,["idle: { title:'조회 전입니다.'", "state==='idle' ? '○'"],'idle data state')
|
|
const boundary=read('packages/kbx-ui/src/components/KbxTemplateStateBoundary.vue')
|
|
must(boundary,['idleActionLabel?: string','idleAction:[]','data-template-state','state===\'idle\'','@action="emit(\'idleAction\')"'],'template idle boundary')
|
|
for(const file of ['KbxListPage.vue','KbxMasterPage.vue','KbxMasterDetailPage.vue','KbxQueuePage.vue','KbxReconcilePage.vue']){
|
|
const text=read(`packages/kbx-ui/src/components/${file}`)
|
|
must(text,['idle-action-label','@idle-action'],`${file} idle recovery wiring`)
|
|
}
|
|
|
|
const host=read('packages/kbx-ui/src/permission/host.ts')
|
|
must(host,['export interface KbxPermissionHost','export const KbxPermissionHostKey'],'permission host')
|
|
const appFrame=read('apps/web/src/shell/KbxAppFrame.vue')
|
|
must(appFrame,['KbxPermissionHostKey','provide(KbxPermissionHostKey,{has:','props.grantedPermissions.includes(permission)'],'permission provider')
|
|
for(const [file,needles] of [
|
|
['packages/kbx-ui/src/components/KbxScreenFrame.vue',['KbxPermissionHostKey','permissionHost=inject','canPermission(permission:string)','data-access','permissionDenied','이 화면을 사용할 권한이 없습니다.',':can="canPermission"']],
|
|
['packages/kbx-ui/src/components/KbxCommandBar.vue',['KbxPermissionHostKey','permissionHost=inject','canPermission(permission:string)','!permission||canPermission(permission)']],
|
|
['packages/kbx-ui/src/components/KbxWorkflowBar.vue',['KbxPermissionHostKey','permissionHost=inject','canPermission(permission:string)','!x.permission||canPermission(x.permission)']],
|
|
['packages/kbx-ui/src/components/KbxBulkActionBar.vue',['KbxPermissionHostKey','permissionHost=inject','canPermission(permission:string)','!a.permission||canPermission(a.permission)']],
|
|
['packages/kbx-ui/src/wms/KbxWmsMobilePage.vue',['KbxPermissionHostKey','permissionHost=inject','permissionDenied','data-access','이 현장 업무를 사용할 권한이 없습니다.']],
|
|
]) must(read(file),needles,`${file} injected permission enforcement`)
|
|
|
|
for(const file of [
|
|
'apps/web/src/modules/oms/orders/search/OrderListPage.vue',
|
|
'apps/web/src/modules/oms/claims/ClaimsPage.vue',
|
|
'apps/web/src/modules/erp/items/ItemMasterPage.vue',
|
|
'apps/web/src/modules/erp/inventory/InventoryPage.vue',
|
|
'apps/web/src/modules/common/ux-metrics/UxMetricsPage.vue',
|
|
'apps/web/src/modules/wms/work/WmsWorkPage.vue',
|
|
]) must(read(file),["?'idle'"],`${file} initial-state adoption`)
|
|
|
|
const home=read('packages/kbx-ui/src/shell/KbxHomePage.vue')
|
|
must(home,['operationFailureCount?:number','urgentNotificationCount?:number','실패·부분완료 작업','중요 알림','regularNotificationCount','button.critical'],'Home attention workbench')
|
|
must(appFrame,['failedOperationCount','partially-completed','urgentUnreadCount','urgent-notification-count'],'runtime attention wiring')
|
|
|
|
const store=read('apps/web/src/shell/workspaceStore.ts')
|
|
must(store,["STORAGE_PREFIX='kbx.navigation.preference.v3'","LEGACY_STORAGE_PREFIX='kbx.navigation.preference.v2'",'MAX_STORED_PREFERENCE_BYTES=64_000','MAX_SCOPE_LENGTH=160','MAX_RECENT_PATH_LENGTH=1024','parseStoredPreference','Date.parse(visitedAt)','localStorage.getItem(storageKey(scope,LEGACY_STORAGE_PREFIX))','normalizePreference({...preference.value,recents:'],'persisted preference hardening/migration')
|
|
const navSecurity=read('packages/kbx-ui/src/shell/navigationSecurity.ts')
|
|
must(navSecurity,['MAX_WORKSPACE_URL_LENGTH=2048','[\\u0000-\\u001f\\u007f]'],'workspace URL size/control-character hardening')
|
|
|
|
const componentManifest=read('packages/kbx-ui/src/registry/componentManifest.ts')
|
|
must(componentManifest,["KbxDataState', category: 'business', purpose: 'Idle·Loading·Empty·Error", "version:'1.1.0'", "KbxHomePage', category: 'shell', purpose: '미저장·실패 작업·중요 알림", "KbxListPage', category: 'template'", "version: '1.6.0'", "KbxWmsMobilePage', category: 'wms'", "version: '1.5.0'", "KbxCommandBar', category: 'business', purpose: 'Permission Host", "version: '1.3.0'", "KbxWorkflowBar', category: 'business', purpose: 'Permission Host", "KbxBulkActionBar', category: 'business', purpose: 'Permission Host"],'v33 component versions')
|
|
const catalog=read('packages/kbx-ui/src/catalog/componentCatalog.ts')
|
|
must(catalog,["id:'idle',label:'조회 전',state:'idle'","id:'attention',label:'실패 작업·중요 알림 우선',state:'error'"],'catalog state scenarios')
|
|
|
|
if(failures.length){console.error(failures.join('\n'));process.exit(1)}
|
|
console.log('v33 template/component/home navigation validation passed: explicit idle state, template state-capability matrix, injected permission enforcement, actionable Home attention, hardened preference migration/storage, and workspace URL bounds.')
|