import fs from 'node:fs' import path from 'node:path' const read=file=>fs.readFileSync(file,'utf8') const expect=(condition,message)=>{if(!condition){console.error(`FAIL: ${message}`);process.exit(1)}console.log(`PASS: ${message}`)} const app=read('apps/web/src/App.vue') expect(/app-version="v(?:59|6[0-9])-/.test(app),'Runtime metadata identifies v59 or a later grid-status-compatible build') const statusContract=read('packages/kbx-contracts/src/status.ts') expect(statusContract.includes("| 'ready'")&&statusContract.includes("| 'info'"),'Status semantic contract covers ready/info without overloading pending') const gridContract=read('packages/kbx-contracts/src/grid.ts') expect(gridContract.includes('export interface KbxGridStatusMap')&&gridContract.includes('statusMap?: KbxGridStatusMap'),'Grid status columns require an explicit raw-value mapping contract') const resolver=read('packages/kbx-ui/src/grid/status.ts') expect(resolver.includes('resolveKbxGridStatus')&&resolver.includes("semantic:'warning'")&&resolver.includes("unknown:true"),'Unknown domain states fail visibly through the pure status resolver') const status=read('packages/kbx-ui/src/components/KbxStatus.vue') expect(status.includes('data-unknown')&&status.includes('정의되지 않은 상태값')&&status.includes('info-surface'),'KbxStatus renders semantic surfaces and a color-independent unknown-state signal') const grid=read('packages/kbx-ui/src/components/KbxDataGrid.vue') for(const marker of ["cellRenderer:c.type==='status'?KbxStatus",'filterValueGetter:c.type===\'status\'','statusDisplay(column,params.value)','resolveKbxGridStatus(column.statusMap,value)'])expect(grid.includes(marker),`KbxDataGrid status renderer contract: ${marker}`) expect(grid.includes("processCellCallback")&&grid.includes("column?.type==='status'?statusDisplay(column,params.value):params.value"),'CSV exports user labels for statuses while non-status values remain raw') const catalog=read('apps/web/src/registry/statusCatalog.ts') for(const marker of ['orderLifecycle','orderShipment','claim','workSeverity','workItem','reconcile','wmsWork','experiment','externalData'])expect(catalog.includes(marker),`Product status dictionary includes ${marker}`) expect(catalog.includes("{ value:'READY', label:'출고대기', semantic:'ready' }")&&catalog.includes("{ value:'BLOCKED', label:'예외', semantic:'error' }"),'Canonical OMS/WMS values map to familiar Korean labels') const sourceFiles=[] function walk(dir){for(const entry of fs.readdirSync(dir,{withFileTypes:true})){const full=path.join(dir,entry.name);if(entry.isDirectory())walk(full);else if(entry.isFile()&&(entry.name.endsWith('.ts')||entry.name.endsWith('.vue')))sourceFiles.push(full)}} walk('apps/web/src') const missing=[] for(const file of sourceFiles){const source=read(file);for(const match of source.matchAll(/\{[^{}]*type\s*:\s*['"]status['"][^{}]*\}/gs)){if(!match[0].includes('statusMap'))missing.push(`${file}: ${match[0].slice(0,90).replace(/\s+/g,' ')}`)}} expect(missing.length===0,`Every application Grid status column has a statusMap; missing: ${missing.join(' | ')||'none'}`) const demo=read('apps/web/src/http/demo/installFrontendDemoApi.ts') expect(demo.includes("shipmentStatus:'READY'")&&demo.includes("shipmentStatus:'NEW'")&&demo.includes("shipmentStatus:'SHIPPED'")&&!demo.includes("shipmentStatus:'출고대기'"),'Demo order projection uses canonical shipment values instead of pre-translated labels') const orderDrawer=read('apps/web/src/modules/oms/orders/search/OrderDetailDrawer.vue') expect(orderDrawer.includes('resolveKbxGridStatus')&&orderDrawer.includes('kbxStatusCatalog.orderLifecycle')&&!orderDrawer.includes('function statusSemantic'),'Order detail removes page-local status semantics and reuses the product dictionary') const unit=read('tests/unit/kbx-grid-status.contract.spec.ts') expect(unit.includes("rawValue:'READY'")&&unit.includes('NEW_VENDOR_STATE')&&unit.includes('unknown:true'),'Unit contract covers canonical preservation and unknown-state visibility') const reference=read('apps/web/fe-reference/kbx-fe.js') const referenceCss=read('apps/web/fe-reference/kbx-fe.css') expect(reference.includes('function statusSemantic')&&reference.includes('function statusChip')&&reference.includes('정의되지 않음 ·'),'Static HTML/JS reference mirrors semantic status and unknown-state behavior') expect(referenceCss.includes('.business-status[data-semantic="completed"]')&&referenceCss.includes('.business-status[data-unknown="true"]'),'Static reference uses text-plus-semantic status styling') const referenceHtml=read('apps/web/fe-reference/index.html') expect(/KBX FE Reference Lab v(?:59|6[0-9]) ·/.test(referenceHtml),'Static HTML reference identifies v59 or a later status-compatible build') const manifest=read('packages/kbx-ui/src/registry/componentManifest.ts') expect(manifest.includes("name: 'KbxDataGrid'")&&manifest.includes("version: '1.6.0'")&&manifest.includes("name: 'KbxStatus'")&&manifest.includes("version: '1.1.0'"),'Component versions identify the strengthened Grid/Status contracts') console.log('PASS: FE grid status dictionary + unknown-state hardening v59 contract')