import { readdirSync, readFileSync, statSync } from 'fs' import { join } from 'path' import { describe, expect, it } from 'vitest' const SRC_ROOT = 'packages/client/src' const listFiles = (dir: string): string[] => readdirSync(dir).flatMap((name) => { const full = join(dir, name) return statSync(full).isDirectory() ? listFiles(full) : [full] }) const sourceFiles = listFiles(SRC_ROOT).filter((file) => /\.(vue|ts|js)$/.test(file), ) /** * naive-ui 的类名在迁移时最容易漏:`grep naive-ui` 只匹配 import, * 匹配不到样式块里的 `:deep(.n-button__content)` 这种写法,也不匹配 * JS 里的字符串字面量(`document.querySelector('.n-modal-mask')`)。 * 这两种都会在 Arco 下静默失效,不报错、测试也测不出来。 */ const NAIVE_CLASS_PATTERN = /\.n-[a-z][\w-]*/i const findOffenders = (pattern: RegExp) => sourceFiles .filter((file) => pattern.test(readFileSync(file, 'utf8'))) .map((file) => file.replace(`${SRC_ROOT}/`, '')) describe('naive-ui removal', () => { it('has source files to scan', () => { expect(sourceFiles.length).toBeGreaterThan(100) }) it('never imports from naive-ui', () => { expect(findOffenders(/from\s+['"]naive-ui['"]/)).toEqual([]) }) it('never imports naive-ui types or helpers by deep path', () => { // packages/client/src 下没有深层导入,但防止将来有人从 @css-render 绕进来 expect( findOffenders(/from\s+['"](vueuc|@css-render\/vue3-ssr|vdirs|seemly)['"]/), ).toEqual([]) }) it('never references naive-ui CSS class names', () => { // 覆盖样式块里的 :deep(.n-*) 与 JS 字符串字面量两种写法 expect(findOffenders(NAIVE_CLASS_PATTERN)).toEqual([]) }) it('never registers naive-ui components globally', () => { const main = readFileSync(join(SRC_ROOT, 'main.ts'), 'utf8') expect(main).toContain('ArcoVue') expect(main).not.toMatch(/N[A-Z][A-Za-z]*Provider/) }) it('does not depend on naive-ui in package.json', () => { const pkg = JSON.parse(readFileSync('package.json', 'utf8')) const all = { ...pkg.dependencies, ...pkg.devDependencies } expect(Object.keys(all)).not.toContain('naive-ui') for (const dep of Object.keys(all)) { expect(dep).not.toBe('vueuc') expect(dep).not.toBe('vdirs') } }) it('does not chunk naive-ui in the vite config', () => { const config = readFileSync('vite.config.ts', 'utf8') expect(config).not.toMatch(/['"]naive-ui['"]/) // Arco 的 scope 名含 "vue" 子串,判断必须排在 vue-vendor 之前, // 否则整个 UI 库会被打进 vue chunk。见 vite.config.ts 的注释。 const arcoIndex = config.indexOf('@arco-design') const vueIndex = config.indexOf('vue-vendor') expect(arcoIndex).toBeGreaterThan(-1) expect(arcoIndex).toBeLessThan(vueIndex) }) })