import assert from 'node:assert/strict' import { existsSync } from 'node:fs' import { readFile } from 'node:fs/promises' import { fileURLToPath } from 'node:url' import path from 'node:path' import { parse as parseSfc } from '@vue/compiler-sfc' const scriptDir = path.dirname(fileURLToPath(import.meta.url)) const viewPath = path.resolve(scriptDir, '../src/views/data-process/DataProcessCreateView.vue') const createDir = path.resolve(scriptDir, '../src/views/data-process/create') const layoutPath = path.resolve(scriptDir, '../src/layouts/MainLayout.vue') const viewSource = await readFile(viewPath, 'utf8') const layoutSource = await readFile(layoutPath, 'utf8') assert.match(viewSource, /const WIZARD_STEPS = \[/, '向导步骤尚未改为固定常量') for (const title of ['创建任务', '数据预览', '开始生成', '结果编辑与保存']) { assert.ok(viewSource.includes(`title: '${title}'`), `缺少固定步骤:${title}`) } assert.doesNotMatch(viewSource, /steps\s*=\s*computed|all\.filter/, '步骤仍根据处理类型动态增减') assert.match(viewSource, /localStorage\.setItem\(DRAFT_STORAGE_KEY/, '草稿没有持久化') assert.match(viewSource, /localStorage\.getItem\(DRAFT_STORAGE_KEY\)/, '草稿没有恢复读取') assert.match(viewSource, /restoreDraft\(\)/, '页面没有恢复草稿') const expectedComponents = [ 'TaskSetupStep.vue', 'PreviewCompareStep.vue', 'GenerationStep.vue', 'ResultEditorStep.vue', ] for (const component of expectedComponents) { assert.ok(existsSync(path.join(createDir, component)), `缺少步骤组件:${component}`) assert.ok(viewSource.includes(component.replace('.vue', '')), `父页面未使用:${component}`) } const typesPath = path.join(createDir, 'types.ts') const modelPath = path.join(createDir, 'previewModel.ts') assert.ok(existsSync(typesPath), '缺少向导类型定义') assert.ok(existsSync(modelPath), '缺少来源映射模型') const [typesSource, modelSource, previewSource] = await Promise.all([ readFile(typesPath, 'utf8'), readFile(modelPath, 'utf8'), readFile(path.join(createDir, 'PreviewCompareStep.vue'), 'utf8'), ]) for (const field of ['sourceStart', 'sourceEnd', 'originalContent', 'editedContent']) { assert.ok(typesSource.includes(field), `PreviewItem 缺少字段:${field}`) } assert.match(typesSource, /sourceFileId/, 'PreviewItem 缺少来源文件标识') assert.match(modelSource, /export function buildPreviewItems/, '缺少切片来源映射生成函数') assert.match(modelSource, /export function sourceLines/, '缺少源文件行偏移生成函数') assert.match(modelSource, /sourceFileId/, '切片生成没有写入来源文件标识') assert.match(viewSource, /selectedPreviewFileId/, '父页面缺少当前预览文件状态') assert.match( viewSource, /buildPreviewItems\(file\.content, processType\.value, String\(file\.uid\)\)/, '预览没有按文件分别生成', ) for (const marker of [ 'preview-workspace', 'source-viewer', 'source-line', 'is-highlighted', 'preview-item', 'preview-editor', 'scrollIntoView', ]) { assert.ok(previewSource.includes(marker), `第二步缺少结构或行为:${marker}`) } assert.match(previewSource, /sourceStart/, '第二步未使用来源起始偏移') assert.match(previewSource, /sourceEnd/, '第二步未使用来源结束偏移') assert.match(previewSource, /filterable/, '文件选择器必须可搜索') assert.match(previewSource, /当前文件/, '预览缺少当前文件切换器') assert.doesNotMatch(previewSource, /located-badge|sync-label|已定位到/, '源文件栏不应显示冗余定位提示') assert.match(previewSource, /const PREVIEW_PAGE_SIZE = 6/, '切片列表必须限制每页展示数量') assert.match(previewSource, /const pagedItems = computed/, '切片列表缺少分页数据') assert.match(previewSource, /v-for="item in pagedItems"/, '切片列表没有使用分页数据') assert.match(previewSource, /\(null\)/, '缺少切片编辑模式状态') assert.match(previewSource, /const editorDraft = ref\(''\)/, '缺少编辑临时草稿') assert.match(previewSource, /function openEditor\(item: PreviewItem\)/, '列表缺少打开切片编辑器的动作') assert.match(previewSource, /function closeEditor\(\)/, '编辑器缺少返回列表的动作') assert.match(previewSource, /function saveEditor\(\)/, '编辑器缺少保存动作') assert.match(previewSource, /