audit-renderer-dependencies.mjs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899
  1. import { readFileSync } from 'node:fs';
  2. import { resolve } from 'node:path';
  3. import { fileURLToPath } from 'node:url';
  4. import {
  5. dependencyToRendererLine,
  6. dependencyToRendererLines,
  7. rendererDependencyGroups,
  8. rendererModularizationLines,
  9. } from './renderer-dependency-plan.mjs';
  10. const root = resolve(fileURLToPath(new URL('..', import.meta.url)));
  11. const readJson = path => JSON.parse(readFileSync(resolve(root, path), 'utf8'));
  12. const corePackage = readJson('packages/core/package.json');
  13. const dependencies = Object.keys(corePackage.dependencies || {}).sort();
  14. const rows = dependencies.map(name => ({
  15. dependency: name,
  16. group: dependencyToRendererLine.get(name)?.group || 'unclassified',
  17. rendererLine: dependencyToRendererLine.get(name)?.id || 'unclassified',
  18. targetPackage: dependencyToRendererLines.get(name)?.map(line => line.targetPackage).join(', ') || 'unclassified',
  19. phase: dependencyToRendererLine.get(name)?.phase || null,
  20. status: dependencyToRendererLine.get(name)?.status || 'unclassified',
  21. sharedBy: dependencyToRendererLines.get(name)?.map(line => line.id) || [],
  22. version: corePackage.dependencies[name],
  23. }));
  24. const byGroup = rows.reduce((result, row) => {
  25. result[row.group] ||= [];
  26. result[row.group].push(row);
  27. return result;
  28. }, {});
  29. const plannedDependencies = new Set(Object.values(rendererDependencyGroups).flat());
  30. const missingPlannedDependencies = Array.from(plannedDependencies)
  31. .filter(name => !dependencies.includes(name))
  32. .sort();
  33. const phaseSummary = rendererModularizationLines.reduce((result, line) => {
  34. if (line.status === 'retained' || line.status === 'extracted') {
  35. return result;
  36. }
  37. result[line.phase] ||= { totalLines: 0, directDependencies: new Set() };
  38. result[line.phase].totalLines += 1;
  39. line.dependencies
  40. .filter(name => dependencies.includes(name))
  41. .forEach(name => result[line.phase].directDependencies.add(name));
  42. return result;
  43. }, {});
  44. const printablePhaseSummary = Object.fromEntries(
  45. Object.entries(phaseSummary).map(([phase, summary]) => [
  46. phase,
  47. {
  48. totalLines: summary.totalLines,
  49. directDependencies: summary.directDependencies.size,
  50. },
  51. ])
  52. );
  53. if (process.argv.includes('--json')) {
  54. console.log(JSON.stringify({
  55. total: rows.length,
  56. groups: byGroup,
  57. rows,
  58. rendererLines: rendererModularizationLines,
  59. missingPlannedDependencies,
  60. phaseSummary: printablePhaseSummary,
  61. retainedCoreLines: rendererModularizationLines.filter(line => line.status === 'retained'),
  62. }, null, 2));
  63. } else {
  64. console.log(`@file-viewer/core direct dependencies: ${rows.length}`);
  65. Object.entries(byGroup).forEach(([group, items]) => {
  66. console.log(`\n[${group}] ${items.length}`);
  67. items.forEach(item => {
  68. const sharedLabel = item.sharedBy.length > 1 ? `, shared: ${item.sharedBy.join(' + ')}` : '';
  69. console.log(` - ${item.dependency}@${item.version} -> ${item.rendererLine} -> ${item.targetPackage} (phase ${item.phase ?? 'n/a'}, ${item.status}${sharedLabel})`);
  70. });
  71. });
  72. console.log('\n[phase summary]');
  73. Object.entries(printablePhaseSummary)
  74. .sort(([a], [b]) => Number(a) - Number(b))
  75. .forEach(([phase, summary]) => {
  76. console.log(` - phase ${phase}: ${summary.totalLines} renderer lines, ${summary.directDependencies} dependencies still declared by core`);
  77. });
  78. const retainedRows = rows.filter(row => row.status === 'retained');
  79. if (retainedRows.length) {
  80. console.log('\n[retained core-native dependencies]');
  81. retainedRows.forEach(item => {
  82. console.log(` - ${item.dependency}@${item.version} -> ${item.rendererLine}`);
  83. });
  84. }
  85. if (byGroup.unclassified?.length) {
  86. console.log('\nUnclassified dependencies must be reviewed before renderer modularization gates become blocking.');
  87. }
  88. if (missingPlannedDependencies.length) {
  89. console.log('\nPlanned dependencies already absent from core direct dependencies:');
  90. missingPlannedDependencies.forEach(name => {
  91. console.log(` - ${name}`);
  92. });
  93. }
  94. }