verify-core-framework-neutral.mjs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103
  1. import { readdir, readFile, stat } from 'node:fs/promises'
  2. import { dirname, join, resolve } from 'node:path'
  3. import { fileURLToPath } from 'node:url'
  4. const scriptDir = dirname(fileURLToPath(import.meta.url))
  5. const sourceRoot = resolve(scriptDir, '..')
  6. const coreRoot = join(sourceRoot, 'packages', 'core')
  7. const corePackagePath = join(coreRoot, 'package.json')
  8. const coreSrcRoot = join(coreRoot, 'src')
  9. const forbiddenPackages = [
  10. 'vue',
  11. '@vue/',
  12. '@vitejs/plugin-vue',
  13. '@vitejs/plugin-vue-jsx',
  14. 'vue-tsc',
  15. '@lucide/vue',
  16. 'react',
  17. 'react-dom',
  18. 'svelte',
  19. '@file-viewer/vue3',
  20. '@file-viewer/vue2.7',
  21. '@file-viewer/vue2.6',
  22. '@file-viewer/react',
  23. '@file-viewer/react-legacy',
  24. '@file-viewer/web',
  25. '@file-viewer/jquery',
  26. '@file-viewer/svelte',
  27. '@flyfish-group/file-viewer',
  28. '@flyfish-group/file-viewer3',
  29. '@flyfish-group/file-viewer-react',
  30. '@flyfish-group/file-viewer-web',
  31. 'file-viewer3',
  32. ]
  33. function assert(condition, message) {
  34. if (!condition) {
  35. throw new Error(message)
  36. }
  37. }
  38. function matchesForbiddenPackage(name) {
  39. return forbiddenPackages.some(forbidden =>
  40. forbidden.endsWith('/')
  41. ? name.startsWith(forbidden)
  42. : name === forbidden
  43. )
  44. }
  45. function collectDependencies(packageJson) {
  46. return {
  47. ...(packageJson.dependencies || {}),
  48. ...(packageJson.peerDependencies || {}),
  49. ...(packageJson.optionalDependencies || {}),
  50. ...(packageJson.devDependencies || {}),
  51. }
  52. }
  53. async function listSourceFiles(dir) {
  54. const entries = await readdir(dir)
  55. const files = []
  56. for (const entry of entries) {
  57. const path = join(dir, entry)
  58. const entryStat = await stat(path)
  59. if (entryStat.isDirectory()) {
  60. files.push(...await listSourceFiles(path))
  61. continue
  62. }
  63. if (/\.(ts|tsx|mts|cts|js|mjs|cjs)$/.test(entry)) {
  64. files.push(path)
  65. }
  66. }
  67. return files
  68. }
  69. const corePackageJson = JSON.parse(await readFile(corePackagePath, 'utf8'))
  70. for (const depName of Object.keys(collectDependencies(corePackageJson))) {
  71. assert(
  72. !matchesForbiddenPackage(depName),
  73. `@file-viewer/core must not depend on framework or wrapper package "${depName}"`
  74. )
  75. }
  76. const importPattern = /\b(?:import|export)\s+(?:[^'"]*?\s+from\s+)?['"]([^'"]+)['"]/g
  77. const dynamicImportPattern = /\bimport\s*\(\s*['"]([^'"]+)['"]\s*\)/g
  78. const files = await listSourceFiles(coreSrcRoot)
  79. for (const file of files) {
  80. const source = await readFile(file, 'utf8')
  81. const imports = [
  82. ...source.matchAll(importPattern),
  83. ...source.matchAll(dynamicImportPattern),
  84. ].map(match => match[1])
  85. for (const importId of imports) {
  86. assert(
  87. !matchesForbiddenPackage(importId),
  88. `@file-viewer/core source must not import framework or wrapper package "${importId}" in ${file}`
  89. )
  90. }
  91. }
  92. console.log(`[core-framework-neutral] Verified @file-viewer/core has no framework/component package dependencies across ${files.length} source files.`)