Files
crawler-plugin/admin-frontend-vue/src/config/workspace.ts
T
huangzd1997 7ffae78919 task-17(壳层/路由): 桌面端壳层响应式验收 + 浏览器验收基建
引入 @playwright/test(mdEdge 通道),playwright.config 起 mock admin API + vite dev;
e2e 覆盖宽/窄屏自动折叠、折叠持久化、无横向溢出等 8 用例;workspace 边界扫描
排除测试专用 e2e/scripts/playwright.config。
2026-09-05 14:43:54 +08:00

114 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { existsSync, readFileSync, readdirSync } from 'node:fs'
import { join, resolve } from 'node:path'
export const STANDALONE_PACKAGE_NAME = 'crawler-plugin-admin-frontend-vue'
/** 后台壳层允许存在的源码目录(任务 1 冻结的工作区边界,供验收脚本复用)。 */
export const ADMIN_SOURCE_DIRS = [
'src/layout',
'src/router',
'src/styles',
'src/types',
'src/config',
'src/pages',
] as const
export const REQUIRED_MANIFEST_FILES = [
'package.json',
'index.html',
'vite.config.ts',
'tsconfig.json',
'src/main.ts',
'src/App.vue',
] as const
// 客户端工程耦合标记:后台工程内出现即代表越界。用带路径/产物语义的标记,
// 避免与本工程自身包名后缀(…admin-frontend-vue)误匹配。扫描时排除本文件自身。
export const FORBIDDEN_COUPLING_TOKENS = [
'new_web_source',
'frontend-vue/',
'app_client',
] as const
const SELF_SCAN_EXCLUSIONS = new Set(['src/config/workspace.ts', 'playwright.config.ts'])
const SCAN_EXTENSIONS = /\.(ts|tsx|vue|css|html|json|js)$/
export function walk(rootDir: string, base = ''): string[] {
const found: string[] = []
for (const entry of readdirSync(join(rootDir, base), { withFileTypes: true })) {
if (['node_modules', 'dist', '.git', 'tests', 'e2e', 'scripts', 'deploy'].includes(entry.name)) continue
const rel = base ? `${base}/${entry.name}` : entry.name
if (entry.isDirectory()) found.push(...walk(rootDir, rel))
else if (SCAN_EXTENSIONS.test(entry.name)) found.push(rel)
}
return found
}
function fileExists(rootDir: string, path: string): boolean {
return existsSync(join(rootDir, path))
}
/** 从当前目录向上定位独立后台工程根目录,找不到时给出可操作错误。 */
export function resolveWorkspaceRoot(cwd = process.cwd()): string {
let dir = resolve(cwd)
for (let i = 0; i < 6; i += 1) {
if (fileExists(dir, 'package.json')) return dir
const parent = resolve(dir, '..')
if (parent === dir) break
dir = parent
}
throw new Error(`在 ${cwd} 向上 6 层内找不到 package.json,请在 admin-frontend-vue 工程目录内执行`)
}
export interface WorkspacePackage {
name: string
private: boolean
scripts: Record<string, string>
dependencies: Record<string, string>
devDependencies: Record<string, string>
}
export function readWorkspacePackage(rootDir = resolveWorkspaceRoot()): WorkspacePackage {
const raw = JSON.parse(readFileSync(join(rootDir, 'package.json'), 'utf8')) as Partial<WorkspacePackage> & { private?: boolean }
return {
name: raw.name || '',
private: raw.private !== false,
scripts: raw.scripts || {},
dependencies: raw.dependencies || {},
devDependencies: raw.devDependencies || {},
}
}
/** 校验独立工程边界,返回违规清单(空数组 = 边界成立)。 */
export function collectBoundaryViolations(rootDir = resolveWorkspaceRoot()): string[] {
const violations: string[] = []
const pkgPath = join(rootDir, 'package.json')
const pkg: WorkspacePackage = fileExists(rootDir, 'package.json')
? readWorkspacePackage(rootDir)
: { name: '', private: false, scripts: {}, dependencies: {}, devDependencies: {} }
if (!fileExists(rootDir, 'package.json')) violations.push(`缺少必需清单文件 package.json(在 ${pkgPath}`)
if (pkg.name !== STANDALONE_PACKAGE_NAME) {
violations.push(`package.name 应为 ${STANDALONE_PACKAGE_NAME},实际为 ${pkg.name || '(空)'}`)
}
if (!pkg.private) violations.push('package.private 应为 true(后台工程不允许被外部发布依赖)')
for (const file of REQUIRED_MANIFEST_FILES) {
if (!fileExists(rootDir, file)) violations.push(`缺少必需清单文件 ${file}`)
}
for (const dir of ADMIN_SOURCE_DIRS) {
if (!fileExists(rootDir, dir)) violations.push(`缺少允许源码目录 ${dir}`)
}
for (const file of walk(rootDir)) {
if (SELF_SCAN_EXCLUSIONS.has(file)) continue
const content = readFileSync(join(rootDir, file), 'utf8')
for (const token of FORBIDDEN_COUPLING_TOKENS) {
if (content.includes(token)) {
violations.push(`${file} 引用了客户端耦合 token "${token}",超出后台工程边界`)
}
}
}
return violations
}