tdepend 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. package/README.md +167 -0
  2. package/dist/analysis/reporter.d.ts +22 -0
  3. package/dist/analysis/reporter.js +116 -0
  4. package/dist/analysis/reporter.js.map +1 -0
  5. package/dist/api/analyze.d.ts +75 -0
  6. package/dist/api/analyze.js +121 -0
  7. package/dist/api/analyze.js.map +1 -0
  8. package/dist/api/export.d.ts +50 -0
  9. package/dist/api/export.js +53 -0
  10. package/dist/api/export.js.map +1 -0
  11. package/dist/api/serialization.d.ts +28 -0
  12. package/dist/api/serialization.js +71 -0
  13. package/dist/api/serialization.js.map +1 -0
  14. package/dist/cli/index.d.ts +2 -0
  15. package/dist/cli/index.js +134 -0
  16. package/dist/cli/index.js.map +1 -0
  17. package/dist/config/loadConfig.d.ts +10 -0
  18. package/dist/config/loadConfig.js +56 -0
  19. package/dist/config/loadConfig.js.map +1 -0
  20. package/dist/config/schema.d.ts +35 -0
  21. package/dist/config/schema.js +58 -0
  22. package/dist/config/schema.js.map +1 -0
  23. package/dist/graph/cycleDetector.d.ts +2 -0
  24. package/dist/graph/cycleDetector.js +56 -0
  25. package/dist/graph/cycleDetector.js.map +1 -0
  26. package/dist/graph/dependencyGraph.d.ts +10 -0
  27. package/dist/graph/dependencyGraph.js +41 -0
  28. package/dist/graph/dependencyGraph.js.map +1 -0
  29. package/dist/index.d.ts +26 -0
  30. package/dist/index.js +41 -0
  31. package/dist/index.js.map +1 -0
  32. package/dist/metrics/abstractness.d.ts +2 -0
  33. package/dist/metrics/abstractness.js +10 -0
  34. package/dist/metrics/abstractness.js.map +1 -0
  35. package/dist/metrics/distance.d.ts +1 -0
  36. package/dist/metrics/distance.js +7 -0
  37. package/dist/metrics/distance.js.map +1 -0
  38. package/dist/metrics/index.d.ts +4 -0
  39. package/dist/metrics/index.js +30 -0
  40. package/dist/metrics/index.js.map +1 -0
  41. package/dist/metrics/instability.d.ts +1 -0
  42. package/dist/metrics/instability.js +8 -0
  43. package/dist/metrics/instability.js.map +1 -0
  44. package/dist/parser/fileScanner.d.ts +8 -0
  45. package/dist/parser/fileScanner.js +22 -0
  46. package/dist/parser/fileScanner.js.map +1 -0
  47. package/dist/parser/tsParser.d.ts +18 -0
  48. package/dist/parser/tsParser.js +158 -0
  49. package/dist/parser/tsParser.js.map +1 -0
  50. package/dist/types/api.d.ts +74 -0
  51. package/dist/types/api.js +3 -0
  52. package/dist/types/api.js.map +1 -0
  53. package/dist/types/graph.d.ts +14 -0
  54. package/dist/types/graph.js +3 -0
  55. package/dist/types/graph.js.map +1 -0
  56. package/dist/types/parser.d.ts +26 -0
  57. package/dist/types/parser.js +3 -0
  58. package/dist/types/parser.js.map +1 -0
  59. package/dist/utils/deepMerge.d.ts +1 -0
  60. package/dist/utils/deepMerge.js +23 -0
  61. package/dist/utils/deepMerge.js.map +1 -0
  62. package/dist/utils/log.d.ts +2 -0
  63. package/dist/utils/log.js +9 -0
  64. package/dist/utils/log.js.map +1 -0
  65. package/dist/utils/pathUtils.d.ts +12 -0
  66. package/dist/utils/pathUtils.js +27 -0
  67. package/dist/utils/pathUtils.js.map +1 -0
  68. package/package.json +77 -0
@@ -0,0 +1,71 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.serializeGraph = serializeGraph;
4
+ exports.normalizeCycle = normalizeCycle;
5
+ exports.toSerializable = toSerializable;
6
+ const crypto_1 = require("crypto");
7
+ /**
8
+ * Converts a DependencyGraph with Sets to a serializable format with Arrays.
9
+ * @param graph - The dependency graph to serialize
10
+ * @returns Serializable graph with array-based relationships
11
+ */
12
+ function serializeGraph(graph) {
13
+ const nodes = graph.getAllNodes().map((node) => ({
14
+ filePath: node.filePath,
15
+ dependencies: Array.from(node.dependencies).sort(),
16
+ dependents: Array.from(node.dependents).sort(),
17
+ }));
18
+ return { nodes };
19
+ }
20
+ /**
21
+ * Normalizes a cycle for consistent identification across runs.
22
+ * Creates a unique ID based on the cycle's contents and rotates the cycle
23
+ * to start with the lexicographically smallest file path.
24
+ *
25
+ * @param cycle - Array of file paths forming a cycle
26
+ * @returns Normalized cycle with unique ID
27
+ */
28
+ function normalizeCycle(cycle) {
29
+ if (cycle.length === 0) {
30
+ return {
31
+ id: '',
32
+ nodes: [],
33
+ length: 0,
34
+ };
35
+ }
36
+ // Create stable ID by hashing sorted paths
37
+ const sorted = [...cycle].sort();
38
+ const id = (0, crypto_1.createHash)('sha256').update(sorted.join('|')).digest('hex').slice(0, 16);
39
+ // Rotate cycle to start with lexicographically smallest element
40
+ const minPath = sorted[0];
41
+ const minIndex = cycle.indexOf(minPath);
42
+ const normalized = [...cycle.slice(minIndex), ...cycle.slice(0, minIndex)];
43
+ return {
44
+ id,
45
+ nodes: normalized,
46
+ length: cycle.length,
47
+ };
48
+ }
49
+ /**
50
+ * Converts an AnalysisResult with rich objects to a fully serializable format.
51
+ * This includes:
52
+ * - Converting Sets to Arrays in the dependency graph
53
+ * - Normalizing cycles with unique IDs
54
+ * - Adding version and timestamp metadata
55
+ *
56
+ * @param result - The analysis result to serialize
57
+ * @returns Fully serializable result ready for JSON.stringify
58
+ */
59
+ function toSerializable(result) {
60
+ return {
61
+ version: '1.0.0',
62
+ timestamp: new Date().toISOString(),
63
+ config: result.config,
64
+ modules: result.modules,
65
+ graph: serializeGraph(result.graph),
66
+ cycles: result.cycles.map(normalizeCycle),
67
+ metrics: result.metrics,
68
+ report: result.report,
69
+ };
70
+ }
71
+ //# sourceMappingURL=serialization.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"serialization.js","sourceRoot":"","sources":["../../src/api/serialization.ts"],"names":[],"mappings":";;AAeA,wCAQC;AAUD,wCAuBC;AAYD,wCAWC;AA/ED,mCAAoC;AAUpC;;;;GAIG;AACH,SAAgB,cAAc,CAAC,KAAsB;IACnD,MAAM,KAAK,GAAiC,KAAK,CAAC,WAAW,EAAE,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC7E,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,YAAY,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC,IAAI,EAAE;QAClD,UAAU,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE;KAC/C,CAAC,CAAC,CAAC;IAEJ,OAAO,EAAE,KAAK,EAAE,CAAC;AACnB,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,cAAc,CAAC,KAAe;IAC5C,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,OAAO;YACL,EAAE,EAAE,EAAE;YACN,KAAK,EAAE,EAAE;YACT,MAAM,EAAE,CAAC;SACV,CAAC;IACJ,CAAC;IAED,2CAA2C;IAC3C,MAAM,MAAM,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC;IACjC,MAAM,EAAE,GAAG,IAAA,mBAAU,EAAC,QAAQ,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;IAEpF,gEAAgE;IAChE,MAAM,OAAO,GAAG,MAAM,CAAC,CAAC,CAAC,CAAC;IAC1B,MAAM,QAAQ,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACxC,MAAM,UAAU,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC,EAAE,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC;IAE3E,OAAO;QACL,EAAE;QACF,KAAK,EAAE,UAAU;QACjB,MAAM,EAAE,KAAK,CAAC,MAAM;KACrB,CAAC;AACJ,CAAC;AAED;;;;;;;;;GASG;AACH,SAAgB,cAAc,CAAC,MAAsB;IACnD,OAAO;QACL,OAAO,EAAE,OAAO;QAChB,SAAS,EAAE,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM;QACrB,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,KAAK,EAAE,cAAc,CAAC,MAAM,CAAC,KAAK,CAAC;QACnC,MAAM,EAAE,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,cAAc,CAAC;QACzC,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,MAAM,CAAC,MAAM;KACtB,CAAC;AACJ,CAAC"}
@@ -0,0 +1,2 @@
1
+ #!/usr/bin/env node
2
+ export {};
@@ -0,0 +1,134 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ const commander_1 = require("commander");
5
+ const loadConfig_1 = require("../config/loadConfig");
6
+ const reporter_1 = require("../analysis/reporter");
7
+ const dependencyGraph_1 = require("../graph/dependencyGraph");
8
+ const cycleDetector_1 = require("../graph/cycleDetector");
9
+ const metrics_1 = require("../metrics");
10
+ const fileScanner_1 = require("../parser/fileScanner");
11
+ const tsParser_1 = require("../parser/tsParser");
12
+ const log_1 = require("../utils/log");
13
+ const export_1 = require("../api/export");
14
+ async function runAnalysis(config) {
15
+ (0, log_1.log)(config, '✓ Configuration loaded successfully');
16
+ (0, log_1.log)(config, ` Root directory: ${config.rootDir}`);
17
+ (0, log_1.log)(config, ` Enabled metrics: ${config.metrics.enabled.join(', ')}`);
18
+ if (config.analysis.target) {
19
+ (0, log_1.log)(config, ` Analysis scope: ${config.analysis.target} = ${config.analysis.value}`);
20
+ }
21
+ (0, log_1.log)(config, '\n📁 Scanning files...');
22
+ const files = await (0, fileScanner_1.scanFiles)(config);
23
+ (0, log_1.log)(config, `✓ Found ${files.length} TypeScript files`);
24
+ if (files.length === 0) {
25
+ (0, log_1.log)(config, '\n⚠ No files found matching the configured patterns.');
26
+ process.exitCode = 0;
27
+ return null;
28
+ }
29
+ (0, log_1.log)(config, '\n📝 Parsing modules...');
30
+ const modules = (0, tsParser_1.parseProject)(files);
31
+ (0, log_1.log)(config, `✓ Parsed ${modules.length} modules`);
32
+ (0, log_1.log)(config, '\n🔗 Building dependency graph...');
33
+ const graph = new dependencyGraph_1.DependencyGraph(modules);
34
+ (0, log_1.log)(config, '✓ Dependency graph built');
35
+ (0, log_1.log)(config, '\n🔄 Detecting cycles...');
36
+ const cycles = (0, cycleDetector_1.detectCycles)(graph);
37
+ (0, log_1.log)(config, `✓ Found ${cycles.length} cycle(s)`);
38
+ if (checkCyclesAndFail(cycles, config.ci.failOnCycle)) {
39
+ if (config.ci.outputFormat !== 'json') {
40
+ process.exitCode = 1;
41
+ return null;
42
+ }
43
+ }
44
+ (0, log_1.log)(config, '\n📐 Computing metrics...');
45
+ const metrics = (0, metrics_1.computeAllMetrics)(graph, modules, cycles);
46
+ (0, log_1.log)(config, '✓ Metrics computed');
47
+ const report = (0, reporter_1.generateReport)(modules, metrics, cycles, config);
48
+ // Create AnalysisResult for potential export
49
+ const result = {
50
+ modules,
51
+ graph,
52
+ cycles,
53
+ metrics,
54
+ report,
55
+ config,
56
+ };
57
+ if (config.ci.outputFormat === 'json') {
58
+ console.log((0, reporter_1.formatJsonOutput)(report));
59
+ }
60
+ else {
61
+ (0, reporter_1.formatConsoleOutput)(report, config);
62
+ }
63
+ if (!report.success) {
64
+ if (config.ci.outputFormat !== 'json') {
65
+ console.error(report.violations.cycles.length > 0 && config.ci.failOnCycle
66
+ ? '\n❌ Error: Cycles detected in dependency graph'
67
+ : '\n❌ Error: Modules exceed distance threshold');
68
+ }
69
+ process.exitCode = 1;
70
+ }
71
+ else {
72
+ process.exitCode = 0;
73
+ }
74
+ return result;
75
+ }
76
+ function checkCyclesAndFail(cycles, failOnCycle) {
77
+ if (cycles.length > 0 && failOnCycle) {
78
+ console.error('\n❌ Error: Cycles detected in dependency graph');
79
+ for (const cycle of cycles) {
80
+ const fileNames = cycle.map((p) => p.split('/').pop()).join(' → ');
81
+ console.error(` - ${fileNames}`);
82
+ }
83
+ return true;
84
+ }
85
+ return false;
86
+ }
87
+ const program = new commander_1.Command();
88
+ program
89
+ .name('tdepend')
90
+ .description('TDepend: TypeScript dependency analysis tool')
91
+ .version('0.1.0');
92
+ program
93
+ .command('analyze')
94
+ .description('Analyze a TypeScript project for dependencies and metrics')
95
+ .option('-c, --config <path>', 'Path to config file (tdepend.config.json)')
96
+ .option('--class <name>', 'Analyze a specific class by name')
97
+ .option('--namespace <name>', 'Analyze a specific namespace by name')
98
+ .option('--ci', 'Run in CI mode with JSON output and strict exit codes')
99
+ .option('-e, --export <path>', 'Export full analysis to JSON file')
100
+ .option('-o, --output <path>', 'Alias for --export')
101
+ .argument('[target]', 'Optional module/file path to analyze')
102
+ .action(async (target, options) => {
103
+ try {
104
+ const config = (0, loadConfig_1.loadConfig)(options.config);
105
+ if (options.ci) {
106
+ config.ci.outputFormat = 'json';
107
+ }
108
+ if (target) {
109
+ config.analysis.target = 'module';
110
+ config.analysis.value = target;
111
+ }
112
+ if (options.class) {
113
+ config.analysis.target = 'class';
114
+ config.analysis.value = options.class;
115
+ }
116
+ if (options.namespace) {
117
+ config.analysis.target = 'namespace';
118
+ config.analysis.value = options.namespace;
119
+ }
120
+ const result = await runAnalysis(config);
121
+ // Handle export if requested
122
+ if (result && (options.export || options.output)) {
123
+ const exportPath = options.export || options.output;
124
+ await (0, export_1.exportToFile)(result, exportPath);
125
+ (0, log_1.log)(config, `\n✓ Analysis exported to ${exportPath}`);
126
+ }
127
+ }
128
+ catch (error) {
129
+ console.error('Error:', error instanceof Error ? error.message : String(error));
130
+ process.exitCode = 1;
131
+ }
132
+ });
133
+ program.parse();
134
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cli/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { type TDependConfig } from './schema';
2
+ /**
3
+ * Load and validate TDepend configuration
4
+ *
5
+ * @param configPath - Optional path to config file. If not provided, searches for
6
+ * tdepend.config.json in current directory
7
+ * @returns Validated and merged configuration
8
+ * @throws Error if config file is not found, invalid JSON, or fails validation
9
+ */
10
+ export declare function loadConfig(configPath?: string): TDependConfig;
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.loadConfig = loadConfig;
4
+ const node_fs_1 = require("node:fs");
5
+ const node_path_1 = require("node:path");
6
+ const schema_1 = require("./schema");
7
+ const deepMerge_1 = require("../utils/deepMerge");
8
+ function resolveConfigPath(configPath) {
9
+ if (configPath) {
10
+ const resolvedPath = (0, node_path_1.resolve)(configPath);
11
+ if (!(0, node_fs_1.existsSync)(resolvedPath)) {
12
+ throw new Error(`Config file not found: ${resolvedPath}`);
13
+ }
14
+ return resolvedPath;
15
+ }
16
+ const defaultPath = (0, node_path_1.resolve)('tdepend.config.json');
17
+ if ((0, node_fs_1.existsSync)(defaultPath)) {
18
+ return defaultPath;
19
+ }
20
+ return null;
21
+ }
22
+ function readConfigFile(filePath) {
23
+ try {
24
+ const fileContent = (0, node_fs_1.readFileSync)(filePath, 'utf-8');
25
+ return JSON.parse(fileContent);
26
+ }
27
+ catch (error) {
28
+ if (error instanceof SyntaxError) {
29
+ throw new Error(`Invalid JSON in config file: ${filePath}`);
30
+ }
31
+ throw error;
32
+ }
33
+ }
34
+ function validateConfig(config) {
35
+ try {
36
+ return schema_1.configSchema.parse(config);
37
+ }
38
+ catch (error) {
39
+ throw new Error(`Config validation failed: ${error}`);
40
+ }
41
+ }
42
+ /**
43
+ * Load and validate TDepend configuration
44
+ *
45
+ * @param configPath - Optional path to config file. If not provided, searches for
46
+ * tdepend.config.json in current directory
47
+ * @returns Validated and merged configuration
48
+ * @throws Error if config file is not found, invalid JSON, or fails validation
49
+ */
50
+ function loadConfig(configPath) {
51
+ const resolvedPath = resolveConfigPath(configPath);
52
+ const loadedConfig = resolvedPath ? readConfigFile(resolvedPath) : {};
53
+ const mergedConfig = (0, deepMerge_1.deepMerge)(schema_1.defaultConfig, loadedConfig);
54
+ return validateConfig(mergedConfig);
55
+ }
56
+ //# sourceMappingURL=loadConfig.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loadConfig.js","sourceRoot":"","sources":["../../src/config/loadConfig.ts"],"names":[],"mappings":";;AAmDA,gCAKC;AAxDD,qCAAmD;AACnD,yCAAoC;AAEpC,qCAA2E;AAC3E,kDAA+C;AAE/C,SAAS,iBAAiB,CAAC,UAAmB;IAC5C,IAAI,UAAU,EAAE,CAAC;QACf,MAAM,YAAY,GAAG,IAAA,mBAAO,EAAC,UAAU,CAAC,CAAC;QACzC,IAAI,CAAC,IAAA,oBAAU,EAAC,YAAY,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CAAC,0BAA0B,YAAY,EAAE,CAAC,CAAC;QAC5D,CAAC;QACD,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,MAAM,WAAW,GAAG,IAAA,mBAAO,EAAC,qBAAqB,CAAC,CAAC;IACnD,IAAI,IAAA,oBAAU,EAAC,WAAW,CAAC,EAAE,CAAC;QAC5B,OAAO,WAAW,CAAC;IACrB,CAAC;IAED,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,cAAc,CAAC,QAAgB;IACtC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,IAAA,sBAAY,EAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;QACpD,OAAO,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAC;IACjC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,WAAW,EAAE,CAAC;YACjC,MAAM,IAAI,KAAK,CAAC,gCAAgC,QAAQ,EAAE,CAAC,CAAC;QAC9D,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,cAAc,CAAC,MAA8B;IACpD,IAAI,CAAC;QACH,OAAO,qBAAY,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC;IACpC,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,6BAA6B,KAAK,EAAE,CAAC,CAAC;IACxD,CAAC;AACH,CAAC;AAED;;;;;;;GAOG;AACH,SAAgB,UAAU,CAAC,UAAmB;IAC5C,MAAM,YAAY,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IACnD,MAAM,YAAY,GAAG,YAAY,CAAC,CAAC,CAAC,cAAc,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACtE,MAAM,YAAY,GAAG,IAAA,qBAAS,EAAC,sBAAa,EAAE,YAAY,CAAC,CAAC;IAC5D,OAAO,cAAc,CAAC,YAAY,CAAC,CAAC;AACtC,CAAC"}
@@ -0,0 +1,35 @@
1
+ import { z } from 'zod';
2
+ export declare const configSchema: z.ZodObject<{
3
+ rootDir: z.ZodDefault<z.ZodString>;
4
+ include: z.ZodDefault<z.ZodArray<z.ZodString>>;
5
+ exclude: z.ZodDefault<z.ZodArray<z.ZodString>>;
6
+ metrics: z.ZodDefault<z.ZodObject<{
7
+ enabled: z.ZodDefault<z.ZodArray<z.ZodEnum<{
8
+ coupling: "coupling";
9
+ abstractness: "abstractness";
10
+ distance: "distance";
11
+ cycles: "cycles";
12
+ }>>>;
13
+ thresholds: z.ZodDefault<z.ZodObject<{
14
+ distance: z.ZodDefault<z.ZodNumber>;
15
+ }, z.core.$strip>>;
16
+ }, z.core.$strip>>;
17
+ analysis: z.ZodDefault<z.ZodObject<{
18
+ target: z.ZodDefault<z.ZodNullable<z.ZodEnum<{
19
+ module: "module";
20
+ class: "class";
21
+ namespace: "namespace";
22
+ }>>>;
23
+ value: z.ZodDefault<z.ZodNullable<z.ZodString>>;
24
+ }, z.core.$strip>>;
25
+ ci: z.ZodDefault<z.ZodObject<{
26
+ failOnThreshold: z.ZodDefault<z.ZodBoolean>;
27
+ failOnCycle: z.ZodDefault<z.ZodBoolean>;
28
+ outputFormat: z.ZodDefault<z.ZodEnum<{
29
+ console: "console";
30
+ json: "json";
31
+ }>>;
32
+ }, z.core.$strip>>;
33
+ }, z.core.$strip>;
34
+ export type TDependConfig = z.infer<typeof configSchema>;
35
+ export declare const defaultConfig: TDependConfig;
@@ -0,0 +1,58 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.defaultConfig = exports.configSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ exports.configSchema = zod_1.z.object({
6
+ rootDir: zod_1.z.string().default('src'),
7
+ include: zod_1.z.array(zod_1.z.string()).default(['src/**/*.ts', 'src/**/*.tsx']),
8
+ exclude: zod_1.z.array(zod_1.z.string()).default(['**/*.test.ts', '**/*.spec.ts', 'dist']),
9
+ metrics: zod_1.z
10
+ .object({
11
+ enabled: zod_1.z
12
+ .array(zod_1.z.enum(['coupling', 'abstractness', 'distance', 'cycles']))
13
+ .default(['coupling', 'abstractness', 'distance', 'cycles']),
14
+ thresholds: zod_1.z
15
+ .object({
16
+ distance: zod_1.z.number().min(0).max(1).default(0.6),
17
+ })
18
+ .default({ distance: 0.6 }),
19
+ })
20
+ .default({
21
+ enabled: ['coupling', 'abstractness', 'distance', 'cycles'],
22
+ thresholds: { distance: 0.6 },
23
+ }),
24
+ analysis: zod_1.z
25
+ .object({
26
+ target: zod_1.z.enum(['module', 'class', 'namespace']).nullable().default(null),
27
+ value: zod_1.z.string().nullable().default(null),
28
+ })
29
+ .default({ target: null, value: null }),
30
+ ci: zod_1.z
31
+ .object({
32
+ failOnThreshold: zod_1.z.boolean().default(true),
33
+ failOnCycle: zod_1.z.boolean().default(false),
34
+ outputFormat: zod_1.z.enum(['console', 'json']).default('console'),
35
+ })
36
+ .default({ failOnThreshold: true, failOnCycle: false, outputFormat: 'console' }),
37
+ });
38
+ exports.defaultConfig = {
39
+ rootDir: 'src',
40
+ include: ['src/**/*.ts', 'src/**/*.tsx'],
41
+ exclude: ['**/*.test.ts', '**/*.spec.ts', 'dist'],
42
+ metrics: {
43
+ enabled: ['coupling', 'abstractness', 'distance', 'cycles'],
44
+ thresholds: {
45
+ distance: 0.6,
46
+ },
47
+ },
48
+ analysis: {
49
+ target: null,
50
+ value: null,
51
+ },
52
+ ci: {
53
+ failOnThreshold: true,
54
+ failOnCycle: false,
55
+ outputFormat: 'console',
56
+ },
57
+ };
58
+ //# sourceMappingURL=schema.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/config/schema.ts"],"names":[],"mappings":";;;AAAA,6BAAwB;AAEX,QAAA,YAAY,GAAG,OAAC,CAAC,MAAM,CAAC;IACnC,OAAO,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;IAClC,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,aAAa,EAAE,cAAc,CAAC,CAAC;IACrE,OAAO,EAAE,OAAC,CAAC,KAAK,CAAC,OAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,cAAc,EAAE,cAAc,EAAE,MAAM,CAAC,CAAC;IAC9E,OAAO,EAAE,OAAC;SACP,MAAM,CAAC;QACN,OAAO,EAAE,OAAC;aACP,KAAK,CAAC,OAAC,CAAC,IAAI,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC,CAAC;aACjE,OAAO,CAAC,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC,CAAC;QAC9D,UAAU,EAAE,OAAC;aACV,MAAM,CAAC;YACN,QAAQ,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC;SAChD,CAAC;aACD,OAAO,CAAC,EAAE,QAAQ,EAAE,GAAG,EAAE,CAAC;KAC9B,CAAC;SACD,OAAO,CAAC;QACP,OAAO,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC;QAC3D,UAAU,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE;KAC9B,CAAC;IACJ,QAAQ,EAAE,OAAC;SACR,MAAM,CAAC;QACN,MAAM,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QACzE,KAAK,EAAE,OAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;KAC3C,CAAC;SACD,OAAO,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IACzC,EAAE,EAAE,OAAC;SACF,MAAM,CAAC;QACN,eAAe,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;QAC1C,WAAW,EAAE,OAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;QACvC,YAAY,EAAE,OAAC,CAAC,IAAI,CAAC,CAAC,SAAS,EAAE,MAAM,CAAC,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;KAC7D,CAAC;SACD,OAAO,CAAC,EAAE,eAAe,EAAE,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,CAAC;CACnF,CAAC,CAAC;AAIU,QAAA,aAAa,GAAkB;IAC1C,OAAO,EAAE,KAAK;IACd,OAAO,EAAE,CAAC,aAAa,EAAE,cAAc,CAAC;IACxC,OAAO,EAAE,CAAC,cAAc,EAAE,cAAc,EAAE,MAAM,CAAC;IACjD,OAAO,EAAE;QACP,OAAO,EAAE,CAAC,UAAU,EAAE,cAAc,EAAE,UAAU,EAAE,QAAQ,CAAC;QAC3D,UAAU,EAAE;YACV,QAAQ,EAAE,GAAG;SACd;KACF;IACD,QAAQ,EAAE;QACR,MAAM,EAAE,IAAI;QACZ,KAAK,EAAE,IAAI;KACZ;IACD,EAAE,EAAE;QACF,eAAe,EAAE,IAAI;QACrB,WAAW,EAAE,KAAK;QAClB,YAAY,EAAE,SAAS;KACxB;CACF,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { DependencyGraph } from './dependencyGraph';
2
+ export declare function detectCycles(graph: DependencyGraph): string[][];
@@ -0,0 +1,56 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.detectCycles = detectCycles;
4
+ function strongConnect(node, graph, state) {
5
+ state.indices.set(node, state.index);
6
+ state.lowLinks.set(node, state.index);
7
+ state.index++;
8
+ state.stack.push(node);
9
+ state.onStack.add(node);
10
+ const graphNode = graph.getNode(node);
11
+ if (graphNode) {
12
+ for (const dependency of graphNode.dependencies) {
13
+ if (!state.indices.has(dependency)) {
14
+ strongConnect(dependency, graph, state);
15
+ const currentLow = state.lowLinks.get(node);
16
+ const depLow = state.lowLinks.get(dependency);
17
+ state.lowLinks.set(node, Math.min(currentLow, depLow));
18
+ }
19
+ else if (state.onStack.has(dependency)) {
20
+ const currentLow = state.lowLinks.get(node);
21
+ const depIndex = state.indices.get(dependency);
22
+ state.lowLinks.set(node, Math.min(currentLow, depIndex));
23
+ }
24
+ }
25
+ }
26
+ if (state.lowLinks.get(node) === state.indices.get(node)) {
27
+ const component = [];
28
+ let w;
29
+ do {
30
+ w = state.stack.pop();
31
+ state.onStack.delete(w);
32
+ component.push(w);
33
+ } while (w !== node);
34
+ if (component.length > 1) {
35
+ state.components.push(component);
36
+ }
37
+ }
38
+ }
39
+ function detectCycles(graph) {
40
+ const state = {
41
+ index: 0,
42
+ stack: [],
43
+ indices: new Map(),
44
+ lowLinks: new Map(),
45
+ onStack: new Set(),
46
+ components: [],
47
+ };
48
+ const allNodes = graph.getAllNodes();
49
+ for (const node of allNodes) {
50
+ if (!state.indices.has(node.filePath)) {
51
+ strongConnect(node.filePath, graph, state);
52
+ }
53
+ }
54
+ return state.components;
55
+ }
56
+ //# sourceMappingURL=cycleDetector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cycleDetector.js","sourceRoot":"","sources":["../../src/graph/cycleDetector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import type { ParsedModule } from '../types/parser';
2
+ import type { DependencyNode } from '../types/graph';
3
+ export declare class DependencyGraph {
4
+ private readonly nodes;
5
+ constructor(modules: ParsedModule[]);
6
+ private addNode;
7
+ private addEdge;
8
+ getNode(filePath: string): DependencyNode | undefined;
9
+ getAllNodes(): DependencyNode[];
10
+ }
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.DependencyGraph = void 0;
4
+ class DependencyGraph {
5
+ constructor(modules) {
6
+ this.nodes = new Map();
7
+ for (const module of modules) {
8
+ this.addNode(module.filePath);
9
+ }
10
+ for (const module of modules) {
11
+ for (const importPath of module.imports) {
12
+ this.addEdge(module.filePath, importPath);
13
+ }
14
+ }
15
+ }
16
+ addNode(filePath) {
17
+ if (!this.nodes.has(filePath)) {
18
+ this.nodes.set(filePath, {
19
+ filePath,
20
+ dependencies: new Set(),
21
+ dependents: new Set(),
22
+ });
23
+ }
24
+ }
25
+ addEdge(from, to) {
26
+ this.addNode(from);
27
+ this.addNode(to);
28
+ const fromNode = this.nodes.get(from);
29
+ const toNode = this.nodes.get(to);
30
+ fromNode.dependencies.add(to);
31
+ toNode.dependents.add(from);
32
+ }
33
+ getNode(filePath) {
34
+ return this.nodes.get(filePath);
35
+ }
36
+ getAllNodes() {
37
+ return Array.from(this.nodes.values());
38
+ }
39
+ }
40
+ exports.DependencyGraph = DependencyGraph;
41
+ //# sourceMappingURL=dependencyGraph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dependencyGraph.js","sourceRoot":"","sources":["../../src/graph/dependencyGraph.ts"],"names":[],"mappings":";;;AAGA,MAAa,eAAe;IAG1B,YAAY,OAAuB;QAFlB,UAAK,GAAgC,IAAI,GAAG,EAAE,CAAC;QAG9D,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;QAChC,CAAC;QAED,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;YAC7B,KAAK,MAAM,UAAU,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;gBACxC,IAAI,CAAC,OAAO,CAAC,MAAM,CAAC,QAAQ,EAAE,UAAU,CAAC,CAAC;YAC5C,CAAC;QACH,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,QAAgB;QAC9B,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,EAAE,CAAC;YAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE;gBACvB,QAAQ;gBACR,YAAY,EAAE,IAAI,GAAG,EAAE;gBACvB,UAAU,EAAE,IAAI,GAAG,EAAE;aACtB,CAAC,CAAC;QACL,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,IAAY,EAAE,EAAU;QACtC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACnB,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAEjB,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,CAAE,CAAC;QACvC,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,CAAE,CAAC;QAEnC,QAAQ,CAAC,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC9B,MAAM,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC9B,CAAC;IAED,OAAO,CAAC,QAAgB;QACtB,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,WAAW;QACT,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC,CAAC;IACzC,CAAC;CACF;AA3CD,0CA2CC"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * TDepend - TypeScript Dependency Analysis Library
3
+ *
4
+ * A JDepend-inspired dependency analysis tool for TypeScript projects.
5
+ * Computes architectural metrics and detects dependency issues.
6
+ *
7
+ * @packageDocumentation
8
+ */
9
+ export { analyze, analyzeWithConfig } from './api/analyze';
10
+ export type { AnalyzeOptions } from './api/analyze';
11
+ export { exportToFile, exportToJson } from './api/export';
12
+ export type { ExportOptions } from './api/export';
13
+ export { toSerializable } from './api/serialization';
14
+ export { DependencyGraph } from './graph/dependencyGraph';
15
+ export { detectCycles } from './graph/cycleDetector';
16
+ export { computeAllMetrics } from './metrics';
17
+ export { parseProject, parseFile } from './parser/tsParser';
18
+ export { scanFiles } from './parser/fileScanner';
19
+ export { loadConfig } from './config/loadConfig';
20
+ export { generateReport, formatJsonOutput } from './analysis/reporter';
21
+ export type { ParsedModule, ParsedClass, ParsedNamespace } from './types/parser';
22
+ export type { DependencyNode, ModuleMetrics } from './types/graph';
23
+ export type { AnalysisReport } from './analysis/reporter';
24
+ export type { TDependConfig } from './config/schema';
25
+ export type { AnalysisResult, SerializableAnalysisResult, SerializableDependencyGraph, SerializableDependencyNode, SerializableCycle, } from './types/api';
26
+ export { defaultConfig } from './config/schema';
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
1
+ "use strict";
2
+ /**
3
+ * TDepend - TypeScript Dependency Analysis Library
4
+ *
5
+ * A JDepend-inspired dependency analysis tool for TypeScript projects.
6
+ * Computes architectural metrics and detects dependency issues.
7
+ *
8
+ * @packageDocumentation
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.defaultConfig = exports.formatJsonOutput = exports.generateReport = exports.loadConfig = exports.scanFiles = exports.parseFile = exports.parseProject = exports.computeAllMetrics = exports.detectCycles = exports.DependencyGraph = exports.toSerializable = exports.exportToJson = exports.exportToFile = exports.analyzeWithConfig = exports.analyze = void 0;
12
+ // High-level API - Primary interface for library users
13
+ var analyze_1 = require("./api/analyze");
14
+ Object.defineProperty(exports, "analyze", { enumerable: true, get: function () { return analyze_1.analyze; } });
15
+ Object.defineProperty(exports, "analyzeWithConfig", { enumerable: true, get: function () { return analyze_1.analyzeWithConfig; } });
16
+ var export_1 = require("./api/export");
17
+ Object.defineProperty(exports, "exportToFile", { enumerable: true, get: function () { return export_1.exportToFile; } });
18
+ Object.defineProperty(exports, "exportToJson", { enumerable: true, get: function () { return export_1.exportToJson; } });
19
+ var serialization_1 = require("./api/serialization");
20
+ Object.defineProperty(exports, "toSerializable", { enumerable: true, get: function () { return serialization_1.toSerializable; } });
21
+ // Core building blocks - For advanced users who want fine-grained control
22
+ var dependencyGraph_1 = require("./graph/dependencyGraph");
23
+ Object.defineProperty(exports, "DependencyGraph", { enumerable: true, get: function () { return dependencyGraph_1.DependencyGraph; } });
24
+ var cycleDetector_1 = require("./graph/cycleDetector");
25
+ Object.defineProperty(exports, "detectCycles", { enumerable: true, get: function () { return cycleDetector_1.detectCycles; } });
26
+ var metrics_1 = require("./metrics");
27
+ Object.defineProperty(exports, "computeAllMetrics", { enumerable: true, get: function () { return metrics_1.computeAllMetrics; } });
28
+ var tsParser_1 = require("./parser/tsParser");
29
+ Object.defineProperty(exports, "parseProject", { enumerable: true, get: function () { return tsParser_1.parseProject; } });
30
+ Object.defineProperty(exports, "parseFile", { enumerable: true, get: function () { return tsParser_1.parseFile; } });
31
+ var fileScanner_1 = require("./parser/fileScanner");
32
+ Object.defineProperty(exports, "scanFiles", { enumerable: true, get: function () { return fileScanner_1.scanFiles; } });
33
+ var loadConfig_1 = require("./config/loadConfig");
34
+ Object.defineProperty(exports, "loadConfig", { enumerable: true, get: function () { return loadConfig_1.loadConfig; } });
35
+ var reporter_1 = require("./analysis/reporter");
36
+ Object.defineProperty(exports, "generateReport", { enumerable: true, get: function () { return reporter_1.generateReport; } });
37
+ Object.defineProperty(exports, "formatJsonOutput", { enumerable: true, get: function () { return reporter_1.formatJsonOutput; } });
38
+ // Configuration - Useful for customization
39
+ var schema_1 = require("./config/schema");
40
+ Object.defineProperty(exports, "defaultConfig", { enumerable: true, get: function () { return schema_1.defaultConfig; } });
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;GAOG;;;AAEH,uDAAuD;AACvD,yCAA2D;AAAlD,kGAAA,OAAO,OAAA;AAAE,4GAAA,iBAAiB,OAAA;AAGnC,uCAA0D;AAAjD,sGAAA,YAAY,OAAA;AAAE,sGAAA,YAAY,OAAA;AAGnC,qDAAqD;AAA5C,+GAAA,cAAc,OAAA;AAEvB,0EAA0E;AAC1E,2DAA0D;AAAjD,kHAAA,eAAe,OAAA;AACxB,uDAAqD;AAA5C,6GAAA,YAAY,OAAA;AACrB,qCAA8C;AAArC,4GAAA,iBAAiB,OAAA;AAC1B,8CAA4D;AAAnD,wGAAA,YAAY,OAAA;AAAE,qGAAA,SAAS,OAAA;AAChC,oDAAiD;AAAxC,wGAAA,SAAS,OAAA;AAClB,kDAAiD;AAAxC,wGAAA,UAAU,OAAA;AACnB,gDAAuE;AAA9D,0GAAA,cAAc,OAAA;AAAE,4GAAA,gBAAgB,OAAA;AAezC,2CAA2C;AAC3C,0CAAgD;AAAvC,uGAAA,aAAa,OAAA"}
@@ -0,0 +1,2 @@
1
+ import type { ParsedModule } from '../types/parser';
2
+ export declare function computeAbstractness(module: ParsedModule): number;
@@ -0,0 +1,10 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeAbstractness = computeAbstractness;
4
+ function computeAbstractness(module) {
5
+ const abstractClasses = module.classes.filter((c) => c.isAbstract).length;
6
+ const abstractTypes = module.interfaces + abstractClasses;
7
+ const totalTypes = module.totalTypes;
8
+ return totalTypes === 0 ? 0 : abstractTypes / totalTypes;
9
+ }
10
+ //# sourceMappingURL=abstractness.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"abstractness.js","sourceRoot":"","sources":["../../src/metrics/abstractness.ts"],"names":[],"mappings":";;AAEA,kDAMC;AAND,SAAgB,mBAAmB,CAAC,MAAoB;IACtD,MAAM,eAAe,GAAG,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,MAAM,CAAC;IAC1E,MAAM,aAAa,GAAG,MAAM,CAAC,UAAU,GAAG,eAAe,CAAC;IAC1D,MAAM,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IAErC,OAAO,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,GAAG,UAAU,CAAC;AAC3D,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function computeDistance(abstractness: number, instability: number): number;
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeDistance = computeDistance;
4
+ function computeDistance(abstractness, instability) {
5
+ return Math.abs(abstractness + instability - 1);
6
+ }
7
+ //# sourceMappingURL=distance.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"distance.js","sourceRoot":"","sources":["../../src/metrics/distance.ts"],"names":[],"mappings":";;AAAA,0CAEC;AAFD,SAAgB,eAAe,CAAC,YAAoB,EAAE,WAAmB;IACvE,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,GAAG,WAAW,GAAG,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { DependencyGraph } from '../graph/dependencyGraph';
2
+ import type { ParsedModule } from '../types/parser';
3
+ import type { ModuleMetrics } from '../types/graph';
4
+ export declare function computeAllMetrics(graph: DependencyGraph, modules: ParsedModule[], cycles: string[][]): ModuleMetrics[];