checkExports.js 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. const fs = require('fs');
  2. const path = require('path');
  3. /**
  4. * 检查 exports 是否有遗漏
  5. */
  6. function checkExports() {
  7. const libEsPath = path.join(__dirname, '../lib/es');
  8. const packageJsonPath = path.join(__dirname, '../package.json');
  9. if (!fs.existsSync(libEsPath)) {
  10. console.error('Error: lib/es directory does not exist.');
  11. process.exit(1);
  12. }
  13. const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
  14. const exports = packageJson.exports || {};
  15. // 收集所有实际存在的文件
  16. const actualFiles = {
  17. js: new Set(),
  18. css: new Set(),
  19. dts: new Set()
  20. };
  21. function scanDirectory(dir, basePath = '') {
  22. const entries = fs.readdirSync(dir, { withFileTypes: true });
  23. for (const entry of entries) {
  24. const fullPath = path.join(dir, entry.name);
  25. const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
  26. if (entry.isDirectory()) {
  27. scanDirectory(fullPath, relativePath);
  28. } else if (entry.isFile()) {
  29. if (entry.name.endsWith('.js')) {
  30. actualFiles.js.add(`./lib/es/${relativePath}`);
  31. actualFiles.js.add(`./lib/es/${relativePath.replace(/\.js$/, '')}`);
  32. } else if (entry.name.endsWith('.css')) {
  33. actualFiles.css.add(`./lib/es/${relativePath}`);
  34. } else if (entry.name.endsWith('.d.ts')) {
  35. actualFiles.dts.add(`./lib/es/${relativePath}`);
  36. }
  37. }
  38. }
  39. }
  40. scanDirectory(libEsPath, '');
  41. // 检查目录(有 index.js 的目录)
  42. function checkDirectories(dir, basePath = '') {
  43. const entries = fs.readdirSync(dir, { withFileTypes: true });
  44. for (const entry of entries) {
  45. const fullPath = path.join(dir, entry.name);
  46. const relativePath = basePath ? `${basePath}/${entry.name}` : entry.name;
  47. if (entry.isDirectory()) {
  48. const indexJsPath = path.join(fullPath, 'index.js');
  49. if (fs.existsSync(indexJsPath)) {
  50. actualFiles.js.add(`./lib/es/${relativePath}`);
  51. }
  52. checkDirectories(fullPath, relativePath);
  53. }
  54. }
  55. }
  56. checkDirectories(libEsPath, '');
  57. // 收集 exports 中已定义的键
  58. const exportedKeys = new Set(Object.keys(exports));
  59. // 找出遗漏的文件
  60. const missing = {
  61. js: [],
  62. css: [],
  63. dts: []
  64. };
  65. // 检查 JS 文件
  66. for (const file of actualFiles.js) {
  67. if (!exportedKeys.has(file)) {
  68. missing.js.push(file);
  69. }
  70. }
  71. // 检查 CSS 文件
  72. for (const file of actualFiles.css) {
  73. if (!exportedKeys.has(file)) {
  74. missing.css.push(file);
  75. }
  76. }
  77. // 检查类型文件(通过 JS 文件推断)
  78. for (const jsFile of actualFiles.js) {
  79. if (jsFile.endsWith('.js')) {
  80. const dtsFile = jsFile.replace(/\.js$/, '.d.ts');
  81. const dtsPath = path.join(__dirname, '../', dtsFile.replace('./', ''));
  82. if (fs.existsSync(dtsPath)) {
  83. actualFiles.dts.add(dtsFile);
  84. // 检查对应的导出是否有 types 字段
  85. const exportKey = jsFile.replace(/\.js$/, '');
  86. const exportWithExt = jsFile;
  87. const exportEntry = exports[exportKey] || exports[exportWithExt];
  88. if (exportEntry && !exportEntry.types) {
  89. missing.dts.push(dtsFile);
  90. }
  91. }
  92. }
  93. }
  94. // 输出结果
  95. console.log('=== 检查结果 ===\n');
  96. console.log(`实际 JS 文件数: ${actualFiles.js.size}`);
  97. console.log(`实际 CSS 文件数: ${actualFiles.css.size}`);
  98. console.log(`实际类型文件数: ${actualFiles.dts.size}`);
  99. console.log(`已导出键数: ${exportedKeys.size}\n`);
  100. if (missing.js.length > 0) {
  101. console.log(`❌ 遗漏的 JS 文件映射 (${missing.js.length}):`);
  102. missing.js.slice(0, 20).forEach(file => console.log(` - ${file}`));
  103. if (missing.js.length > 20) {
  104. console.log(` ... 还有 ${missing.js.length - 20} 个`);
  105. }
  106. console.log('');
  107. }
  108. if (missing.css.length > 0) {
  109. console.log(`❌ 遗漏的 CSS 文件映射 (${missing.css.length}):`);
  110. missing.css.slice(0, 20).forEach(file => console.log(` - ${file}`));
  111. if (missing.css.length > 20) {
  112. console.log(` ... 还有 ${missing.css.length - 20} 个`);
  113. }
  114. console.log('');
  115. }
  116. if (missing.dts.length > 0) {
  117. console.log(`⚠️ 缺少 types 字段的导出 (${missing.dts.length}):`);
  118. missing.dts.slice(0, 20).forEach(file => console.log(` - ${file}`));
  119. if (missing.dts.length > 20) {
  120. console.log(` ... 还有 ${missing.dts.length - 20} 个`);
  121. }
  122. console.log('');
  123. }
  124. if (missing.js.length === 0 && missing.css.length === 0 && missing.dts.length === 0) {
  125. console.log('✅ 所有文件都已正确导出!');
  126. }
  127. return {
  128. missing,
  129. stats: {
  130. actualJs: actualFiles.js.size,
  131. actualCss: actualFiles.css.size,
  132. actualDts: actualFiles.dts.size,
  133. exported: exportedKeys.size
  134. }
  135. };
  136. }
  137. if (require.main === module) {
  138. try {
  139. checkExports();
  140. } catch (error) {
  141. console.error('Error:', error.message);
  142. console.error(error.stack);
  143. process.exit(1);
  144. }
  145. }
  146. module.exports = { checkExports };