import fs from 'node:fs' import path from 'node:path' import { fileURLToPath } from 'node:url' const currentDir = path.dirname(fileURLToPath(import.meta.url)) const pageFile = path.resolve(currentDir, '../index.vue') const chartPanelFile = path.resolve(currentDir, '../components/SteadyTrendChartPanel.vue') const trendOptionsFile = path.resolve(currentDir, '../utils/trendOptions.ts') const payloadFile = path.resolve(currentDir, '../utils/trendPayload.ts') const interfaceFile = path.resolve(currentDir, '../../../../api/steady/steadyDataView/interface/index.ts') const read = file => fs.readFileSync(file, 'utf8') const pageSource = read(pageFile) const chartPanelSource = read(chartPanelFile) const trendOptionsSource = read(trendOptionsFile) const payloadSource = read(payloadFile) const interfaceSource = read(interfaceFile) const checks = [ [ 'steadyDataView imports the day query endpoint for chunked loading', /import\s*\{[^}]*querySteadyTrendDay[^}]*\}\s*from\s*'@\/api\/steady\/steadyDataView'/, pageSource ], [ 'steadyDataView routes long ranges through chunked trend loading', /isSteadyTrendRangeOverChunkLimit\(payload\.timeStart,\s*payload\.timeEnd\)[\s\S]*querySteadyTrendInChunks/, pageSource ], [ 'steadyDataView prevents stale chunk responses from overwriting newer queries', /trendQuerySerial[\s\S]*currentQuerySerial[\s\S]*currentQuerySerial\s*!==\s*trendQuerySerial/, pageSource ], ['chunk helper uses a three day maximum window', /STEADY_TREND_CHUNK_DAYS\s*=\s*3/, payloadSource], [ 'long range chunk query initializes a full time range result before data arrives', /buildEmptySteadyTrendQueryResult\(payload\.timeStart,\s*payload\.timeEnd\)/, pageSource ], [ 'long range chunk query avoids trend loading overlay', /loading\.trend\s*=\s*!isSteadyTrendRangeOverChunkLimit\(payload\.timeStart,\s*payload\.timeEnd\)/, pageSource ], ['chunk helper exports a long range predicate', /export\s+const\s+isSteadyTrendRangeOverChunkLimit/, payloadSource], ['chunk helper exports query chunk builder', /export\s+const\s+buildSteadyTrendQueryChunks/, payloadSource], ['chunk helper exports incremental result merger', /export\s+const\s+mergeSteadyTrendQueryResult/, payloadSource], [ 'chunk helper exports empty range result builder', /export\s+const\s+buildEmptySteadyTrendQueryResult/, payloadSource ], ['chunk helper exports no data predicate', /export\s+const\s+hasSteadyTrendResultData/, payloadSource], [ 'trend result carries full query time range metadata', /queryTimeStart\?:\s*string[\s\S]*queryTimeEnd\?:\s*string/, interfaceSource ], ['chart panel enables missing data by default', /const\s+missingDataEnabled\s*=\s*ref\(true\)/, chartPanelSource], [ 'chart panel shows no data state after completed empty query', /hasQueriedWithoutData[\s\S]*description="暂无数据"/, chartPanelSource ], [ 'chart options use full query time range for x axis min and max', /queryTimeStart[\s\S]*queryTimeEnd[\s\S]*xAxis[\s\S]*min:[\s\S]*max:/, trendOptionsSource ] ] const failures = checks.filter(([_name, pattern, source]) => !pattern.test(source)) if (failures.length) { console.error('steadyDataView chunked query contract failed:') failures.forEach(([name]) => console.error(`- ${name}`)) process.exit(1) } console.log('steadyDataView chunked query contract passed')