Files
KArtSell.Aegis/docs/Design/kbx-foundation-v60-status-canonical-contract-hardening/scripts/validate-theme-navigation-v43.mjs
T
kjh2064 3f293d8aa8
deploy / deploy (push) Successful in 1m52s
deploy / notify (push) Successful in 1s
V13-FE-006: consolidate approved UI and contract hardening
2026-08-13 02:41:00 +09:00

51 lines
4.2 KiB
JavaScript

import fs from 'node:fs'
const read=p=>fs.readFileSync(p,'utf8')
const json=p=>JSON.parse(read(p))
const failures=[]
const check=(ok,msg)=>{if(!ok)failures.push(msg)}
const tokens=json('packages/kbx-ui/src/tokens/source/kbx.tokens.json')
check(Number(tokens.version.split('.')[0])>1 || (Number(tokens.version.split('.')[0])===1 && Number(tokens.version.split('.')[1])>=9),'design token source must be v1.9.0 or newer')
check(tokens.themes?.light?.label==='KBX Business Light','light business theme missing')
check(tokens.themes?.dark?.label==='KBX Business Dark','dark business theme missing')
for(const key of ['semantic.surface.default','semantic.surface.muted','semantic.text.default','semantic.text.muted','semantic.border.default','semantic.action.primary','semantic.status.success','semantic.status.warning','semantic.status.danger','semantic.focus','semantic.state.aiSurface']){
check(Object.hasOwn(tokens.themes?.dark?.overrides??{},key),`dark semantic override missing: ${key}`)
}
const css=read('packages/kbx-ui/src/tokens/kbx.css')
check(css.includes('[data-kbx-theme="dark"]'),'generated dark selector missing')
check(css.includes('color-scheme: dark'),'dark color-scheme missing')
const main=read('apps/web/src/main.ts')
check(main.includes("darkModeSelector: '[data-kbx-theme=\\\"dark\\\"]'"),'PrimeVue dark selector must follow KBX root theme')
const theme=read('packages/kbx-ui/src/theme/kbxTheme.ts')
for(const token of ["'light' | 'dark'",'applyKbxTheme','nextKbxThemeMode'])check(theme.includes(token),`theme runtime contract missing: ${token}`)
const nav=read('packages/kbx-contracts/src/navigation.ts')
check(nav.includes("themeMode?: 'light' | 'dark'"),'theme preference contract missing')
const store=read('apps/web/src/shell/workspaceStore.ts')
check(store.includes("themeMode:'light'")&&store.includes('function toggleTheme()'),'workspace theme preference must be fail-safe and persisted')
const frame=read('apps/web/src/shell/KbxAppFrame.vue')
check(frame.includes('watch(themeMode,mode=>applyKbxTheme(mode),{immediate:true})'),'AppFrame must apply persisted theme at the document root')
check(frame.includes('@theme-toggle="store.toggleTheme"'),'AppFrame must bind header theme control to preference store')
const header=read('packages/kbx-ui/src/shell/KbxGlobalHeader.vue')
check(header.includes("themeMode?: 'light' | 'dark'")&&header.includes("@click=\"emit('themeToggle')\""),'global header theme control missing')
check(header.includes('grid-template-columns:repeat(4,1fr)'),'narrow header must accommodate theme without overflow')
const grid=read('packages/kbx-ui/src/theme/kbxGridTheme.ts')
for(const token of ['accentColor','borderColor','selectedRowBackgroundColor'])check(grid.includes(token),`AG Grid semantic theme bridge missing: ${token}`)
const home=read('packages/kbx-ui/src/shell/KbxHomePage.vue')
check(home.includes('v43 theme hierarchy'),'Home themed hierarchy hardening missing')
check(home.includes('border-left:var(--kbx-accent-border-width)'),'Home attention must encode priority without whole-row color reliance')
const side=read('packages/kbx-ui/src/shell/KbxSideNavigation.vue')
check(side.includes('box-shadow:inset var(--kbx-accent-border-width) 0 0 var(--kbx-color-primary)')||side.includes('box-shadow:inset var(--kbx-accent-border-width) 0 0 var(--kbx-color-module-accent)'),'Side nav active state must remain explicit in both themes')
const refHtml=read('apps/web/fe-reference/index.html')
const refCss=read('apps/web/fe-reference/kbx-fe.css')
const refJs=read('apps/web/fe-reference/kbx-fe.js')
check(refHtml.includes('id="themeButton"'),'FE Reference must expose theme switching')
check(refCss.includes('.kbx-app[data-theme="dark"]'),'FE Reference dark theme missing')
check(refJs.includes("theme:'light'")&&refJs.includes("state.theme=state.theme==='dark'?'light':'dark'"),'FE Reference theme state/persistence missing')
check(!/background:#fff(?![0-9a-fA-F])/i.test(refCss),'FE Reference contains hard-coded white surfaces that break dark theme')
if(failures.length){console.error('Theme/navigation v43 validation failed:');for(const f of failures)console.error(`- ${f}`);process.exit(1)}
console.log('Theme/navigation v43 validation passed: semantic Light/Dark, PrimeVue/AG Grid bridge, Home/Shell hierarchy, reference parity.')