# 最小验证（Validation）

在本仓库验证：

```powershell
pnpm i
pnpm run serve
```

迁移到新仓库后，至少验证：

- 首页可渲染（Layout 正常）
- 路由跳转正常
- Pinia 与 i18n 可注入
- Mock 请求可命中（开发环境）

建议附加：

```powershell
pnpm run lint
pnpm run test:unit
pnpm run build
```

## 文档/清单对账（防止漏登记模块）

对账 `library/components/*` 是否都已登记到 `AI-Coding/openspec-lite/manifest.yaml`：

```powershell
$repo = (Get-Location).Path;
$componentDirs = Get-ChildItem -LiteralPath "$repo\library\components" -Directory | Select-Object -ExpandProperty Name | Sort-Object;
$manifest = Get-Content -LiteralPath "$repo\AI-Coding\openspec-lite\manifest.yaml" -Raw;
$manifestComponents = [regex]::Matches($manifest,'library/components/(?<name>Vab[^/]+)/') | ForEach-Object { $_.Groups['name'].Value } | Sort-Object -Unique;
Compare-Object -ReferenceObject $componentDirs -DifferenceObject $manifestComponents
```

对账 `library/layouts/*` 子目录是否都被 `AI-Coding/openspec-lite/modules/layouts.yaml` 覆盖：

```powershell
$repo = (Get-Location).Path;
$layoutDirs = Get-ChildItem -LiteralPath "$repo\library\layouts" -Directory | Select-Object -ExpandProperty Name | Sort-Object;
$layoutsSpec = Get-Content -LiteralPath "$repo\AI-Coding\openspec-lite\modules\layouts.yaml" -Raw;
$specDirs = [regex]::Matches($layoutsSpec,'library/layouts/(?<name>VabLayout[^/]+)/') | ForEach-Object { $_.Groups['name'].Value } | Sort-Object -Unique;
Compare-Object -ReferenceObject $layoutDirs -DifferenceObject $specDirs
```

对账 `components.d.ts` 里自动导入的 `Vab*` 组件是否都被任一 module spec 覆盖（按源文件路径精确匹配）：

```powershell
$repo = (Get-Location).Path;
$dtsPath = "$repo\library\build\vuePlugins\components.d.ts";
$specDir = "$repo\AI-Coding\openspec-lite\modules";

$dts = Get-Content -LiteralPath $dtsPath -Raw;
$specText = (Get-ChildItem -LiteralPath $specDir -Filter '*.yaml' | ForEach-Object { Get-Content -LiteralPath $_.FullName -Raw }) -join "`n---`n";

$imports = [regex]::Matches(
	$dts,
	"Vab[A-Za-z0-9_]+:\\s*typeof\\s+import\\('(?<p>[^']+)'\\)\\['default'\\]",
	[System.Text.RegularExpressions.RegexOptions]::Multiline
) | ForEach-Object { $_.Groups['p'].Value } | Where-Object { $_ -like '*components*' } | ForEach-Object {
	$p = $_;
	$p = $p -replace "^\\./\\.\\./\\.\\./","";
	$p = $p -replace "^\\./\\.\\./","";
	$p = $p -replace "^\\./","";
	if ($p -like 'components/*') { $p = "library/" + $p }
	$p
} | Sort-Object -Unique;

$missing = foreach ($p in $imports) { if ($specText -notmatch [regex]::Escape($p)) { $p } };
if ($missing) { $missing } else { '(none)' }
```

对账 `src/router/index.ts` 引用的 `@/views/*.vue` 是否都存在，并列出未被路由引用的 views：

```powershell
$repo = (Get-Location).Path;
$routerPath = "$repo\src\router\index.ts";
$viewsRoot = "$repo\src\views";

$router = Get-Content -LiteralPath $routerPath -Raw;
# 只提取“非注释行”中的 views 引用，避免把 // 注释的 demo 路由当成缺失文件
$routeViewRefs = [regex]::Matches(
	$router,
	"(?m)^(?!\\s*//).*@/views/(?<p>[^'\\\"\\)]+\\.vue)",
	[System.Text.RegularExpressions.RegexOptions]::Multiline
) | ForEach-Object { $_.Groups['p'].Value } | Sort-Object -Unique;

$missingFiles = foreach ($p in $routeViewRefs) {
	$abs = Join-Path $viewsRoot ($p -replace '/', '\\');
	if (-not (Test-Path -LiteralPath $abs)) { "src/views/$p" }
};

$allViews = Get-ChildItem -LiteralPath $viewsRoot -Recurse -File -Filter '*.vue' | ForEach-Object {
	$_.FullName.Substring($viewsRoot.Length + 1).Replace('\\','/')
} | Sort-Object -Unique;

$unreferenced = Compare-Object -ReferenceObject $allViews -DifferenceObject $routeViewRefs -PassThru | Where-Object { $_ -in $allViews } | Sort-Object;

'--- router references missing files ---';
if ($missingFiles) { $missingFiles } else { '(none)' };
'--- views not referenced by router ---';
if ($unreferenced) { $unreferenced | ForEach-Object { "src/views/$_" } } else { '(none)' };
```
