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,30 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeAllMetrics = computeAllMetrics;
4
+ const abstractness_1 = require("./abstractness");
5
+ const distance_1 = require("./distance");
6
+ const instability_1 = require("./instability");
7
+ function computeAllMetrics(graph, modules, cycles) {
8
+ const moduleMap = new Map(modules.map((m) => [m.filePath, m]));
9
+ const metrics = [];
10
+ for (const node of graph.getAllNodes()) {
11
+ const module = moduleMap.get(node.filePath);
12
+ const moduleCycles = cycles.filter((cycle) => cycle.includes(node.filePath));
13
+ const Ca = node.dependents.size;
14
+ const Ce = node.dependencies.size;
15
+ const abstractness = module ? (0, abstractness_1.computeAbstractness)(module) : 0;
16
+ const instability = (0, instability_1.computeInstability)(Ca, Ce);
17
+ const distance = (0, distance_1.computeDistance)(abstractness, instability);
18
+ metrics.push({
19
+ filePath: node.filePath,
20
+ Ca,
21
+ Ce,
22
+ cycles: moduleCycles,
23
+ abstractness,
24
+ instability,
25
+ distance,
26
+ });
27
+ }
28
+ return metrics;
29
+ }
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/metrics/index.ts"],"names":[],"mappings":";;AAOA,8CA8BC;AAlCD,iDAAqD;AACrD,yCAA6C;AAC7C,+CAAmD;AAEnD,SAAgB,iBAAiB,CAC/B,KAAsB,EACtB,OAAuB,EACvB,MAAkB;IAElB,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAoB,EAAE,CAAC;IAEpC,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,SAAS,CAAC,GAAG,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAC;QAE7E,MAAM,EAAE,GAAG,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC;QAChC,MAAM,EAAE,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC;QAClC,MAAM,YAAY,GAAG,MAAM,CAAC,CAAC,CAAC,IAAA,kCAAmB,EAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,IAAA,gCAAkB,EAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QAC/C,MAAM,QAAQ,GAAG,IAAA,0BAAe,EAAC,YAAY,EAAE,WAAW,CAAC,CAAC;QAE5D,OAAO,CAAC,IAAI,CAAC;YACX,QAAQ,EAAE,IAAI,CAAC,QAAQ;YACvB,EAAE;YACF,EAAE;YACF,MAAM,EAAE,YAAY;YACpB,YAAY;YACZ,WAAW;YACX,QAAQ;SACT,CAAC,CAAC;IACL,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC"}
@@ -0,0 +1 @@
1
+ export declare function computeInstability(Ca: number, Ce: number): number;
@@ -0,0 +1,8 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.computeInstability = computeInstability;
4
+ function computeInstability(Ca, Ce) {
5
+ const total = Ca + Ce;
6
+ return total === 0 ? 0 : Ce / total;
7
+ }
8
+ //# sourceMappingURL=instability.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"instability.js","sourceRoot":"","sources":["../../src/metrics/instability.ts"],"names":[],"mappings":";;AAAA,gDAGC;AAHD,SAAgB,kBAAkB,CAAC,EAAU,EAAE,EAAU;IACvD,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,CAAC;IACtB,OAAO,KAAK,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC;AACtC,CAAC"}
@@ -0,0 +1,8 @@
1
+ import type { TDependConfig } from '../config/schema';
2
+ /**
3
+ * Scan files based on include/exclude patterns from config
4
+ *
5
+ * @param config - TDepend configuration with include/exclude patterns
6
+ * @returns Array of normalized absolute file paths
7
+ */
8
+ export declare function scanFiles(config: TDependConfig): Promise<string[]>;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.scanFiles = scanFiles;
4
+ const glob_1 = require("glob");
5
+ const pathUtils_1 = require("../utils/pathUtils");
6
+ /**
7
+ * Scan files based on include/exclude patterns from config
8
+ *
9
+ * @param config - TDepend configuration with include/exclude patterns
10
+ * @returns Array of normalized absolute file paths
11
+ */
12
+ async function scanFiles(config) {
13
+ const { include, exclude } = config;
14
+ // Scan files matching include patterns
15
+ const files = await (0, glob_1.glob)(include, {
16
+ ignore: exclude,
17
+ absolute: true,
18
+ nodir: true,
19
+ });
20
+ return files.map((file) => (0, pathUtils_1.normalizePath)(file));
21
+ }
22
+ //# sourceMappingURL=fileScanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fileScanner.js","sourceRoot":"","sources":["../../src/parser/fileScanner.ts"],"names":[],"mappings":";;AAWA,8BAWC;AAtBD,+BAA4B;AAG5B,kDAAmD;AAEnD;;;;;GAKG;AACI,KAAK,UAAU,SAAS,CAAC,MAAqB;IACnD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,GAAG,MAAM,CAAC;IAEpC,uCAAuC;IACvC,MAAM,KAAK,GAAG,MAAM,IAAA,WAAI,EAAC,OAAO,EAAE;QAChC,MAAM,EAAE,OAAO;QACf,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,IAAI;KACZ,CAAC,CAAC;IAEH,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAA,yBAAa,EAAC,IAAI,CAAC,CAAC,CAAC;AAClD,CAAC"}
@@ -0,0 +1,18 @@
1
+ import { Project } from 'ts-morph';
2
+ import type { ParsedModule } from '../types/parser';
3
+ /**
4
+ * Parse multiple TypeScript files in a project
5
+ *
6
+ * @param filePaths - Array of file paths to parse
7
+ * @param tsConfigPath - Optional path to tsconfig.json
8
+ * @returns Array of ParsedModule objects
9
+ */
10
+ export declare function parseProject(filePaths: string[], tsConfigPath?: string): ParsedModule[];
11
+ /**
12
+ * Parse a single TypeScript file
13
+ *
14
+ * @param filePath - Path to the file to parse
15
+ * @param project - Optional ts-morph Project instance
16
+ * @returns ParsedModule with extracted information
17
+ */
18
+ export declare function parseFile(filePath: string, project?: Project): ParsedModule;
@@ -0,0 +1,158 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.parseProject = parseProject;
4
+ exports.parseFile = parseFile;
5
+ const node_path_1 = require("node:path");
6
+ const ts_morph_1 = require("ts-morph");
7
+ const pathUtils_1 = require("../utils/pathUtils");
8
+ function extractImports(sourceFile, filePath) {
9
+ const imports = [];
10
+ const importDeclarations = sourceFile.getImportDeclarations();
11
+ for (const importDecl of importDeclarations) {
12
+ const moduleSpecifier = importDecl.getModuleSpecifierValue();
13
+ if ((0, pathUtils_1.isRelativeImport)(moduleSpecifier)) {
14
+ const resolvedPath = resolveImportPath(moduleSpecifier, filePath);
15
+ if (resolvedPath) {
16
+ imports.push(resolvedPath);
17
+ }
18
+ }
19
+ else if (!(0, pathUtils_1.isExternalModule)(moduleSpecifier)) {
20
+ // Handle absolute imports (potential path aliases)
21
+ // For now, we'll skip these - full path alias resolution needs tsconfig
22
+ // This will be enhanced if needed
23
+ }
24
+ }
25
+ return imports;
26
+ }
27
+ function extractClasses(sourceFile, filePath) {
28
+ const classes = [];
29
+ const exports = [];
30
+ const classDeclarations = sourceFile.getClasses();
31
+ for (const classDecl of classDeclarations) {
32
+ const name = classDecl.getName();
33
+ if (name) {
34
+ const isAbstract = classDecl.isAbstract();
35
+ const isExported = classDecl.isExported();
36
+ classes.push({
37
+ name,
38
+ isAbstract,
39
+ isExported,
40
+ filePath,
41
+ });
42
+ if (isExported) {
43
+ exports.push(name);
44
+ }
45
+ }
46
+ }
47
+ return { classes, exports };
48
+ }
49
+ function extractInterfaces(sourceFile) {
50
+ const exports = [];
51
+ let interfaces = 0;
52
+ const interfaceDeclarations = sourceFile.getInterfaces();
53
+ for (const interfaceDecl of interfaceDeclarations) {
54
+ const name = interfaceDecl.getName();
55
+ if (interfaceDecl.isExported()) {
56
+ exports.push(name);
57
+ interfaces++;
58
+ }
59
+ else {
60
+ interfaces++;
61
+ }
62
+ }
63
+ return { interfaces, exports };
64
+ }
65
+ function extractNamespaces(sourceFile, filePath) {
66
+ const namespaces = [];
67
+ const exports = [];
68
+ const namespaceDeclarations = sourceFile.getModules();
69
+ for (const namespaceDecl of namespaceDeclarations) {
70
+ const name = namespaceDecl.getName();
71
+ namespaces.push({
72
+ name,
73
+ filePath,
74
+ });
75
+ if (namespaceDecl.isExported()) {
76
+ exports.push(name);
77
+ }
78
+ }
79
+ return { namespaces, exports };
80
+ }
81
+ function extractOtherExports(sourceFile, existingExports) {
82
+ const otherExports = [];
83
+ const exportedDeclarations = sourceFile.getExportedDeclarations();
84
+ for (const [name, declarations] of exportedDeclarations) {
85
+ if (existingExports.includes(name)) {
86
+ continue;
87
+ }
88
+ if (declarations.length > 0) {
89
+ otherExports.push(name);
90
+ }
91
+ }
92
+ return otherExports;
93
+ }
94
+ function parseSourceFile(sourceFile) {
95
+ const filePath = (0, pathUtils_1.normalizePath)(sourceFile.getFilePath());
96
+ const imports = extractImports(sourceFile, filePath);
97
+ const { classes, exports: classExports } = extractClasses(sourceFile, filePath);
98
+ const { interfaces, exports: interfaceExports } = extractInterfaces(sourceFile);
99
+ const { namespaces, exports: namespaceExports } = extractNamespaces(sourceFile, filePath);
100
+ const allExports = [...classExports, ...interfaceExports, ...namespaceExports];
101
+ const otherExports = extractOtherExports(sourceFile, allExports);
102
+ const exports = [...allExports, ...otherExports];
103
+ const totalTypes = classes.length + interfaces;
104
+ return {
105
+ filePath,
106
+ imports,
107
+ exports,
108
+ classes,
109
+ namespaces,
110
+ interfaces,
111
+ totalTypes,
112
+ };
113
+ }
114
+ function resolveImportPath(importSpecifier, fromFile) {
115
+ const dir = (0, node_path_1.dirname)(fromFile);
116
+ // Resolve relative to the importing file
117
+ const resolvedPath = (0, node_path_1.resolve)(dir, importSpecifier);
118
+ // Try .ts as default extension for TypeScript projects
119
+ const pathWithTs = resolvedPath + '.ts';
120
+ return (0, pathUtils_1.normalizePath)(pathWithTs);
121
+ }
122
+ /**
123
+ * Parse multiple TypeScript files in a project
124
+ *
125
+ * @param filePaths - Array of file paths to parse
126
+ * @param tsConfigPath - Optional path to tsconfig.json
127
+ * @returns Array of ParsedModule objects
128
+ */
129
+ function parseProject(filePaths, tsConfigPath) {
130
+ const project = new ts_morph_1.Project({
131
+ tsConfigFilePath: tsConfigPath,
132
+ skipAddingFilesFromTsConfig: true,
133
+ });
134
+ // Add all files to the project
135
+ for (const filePath of filePaths) {
136
+ project.addSourceFileAtPath(filePath);
137
+ }
138
+ const modules = [];
139
+ const sourceFiles = project.getSourceFiles();
140
+ for (const sourceFile of sourceFiles) {
141
+ const parsedModule = parseSourceFile(sourceFile);
142
+ modules.push(parsedModule);
143
+ }
144
+ return modules;
145
+ }
146
+ /**
147
+ * Parse a single TypeScript file
148
+ *
149
+ * @param filePath - Path to the file to parse
150
+ * @param project - Optional ts-morph Project instance
151
+ * @returns ParsedModule with extracted information
152
+ */
153
+ function parseFile(filePath, project) {
154
+ const proj = project || new ts_morph_1.Project();
155
+ const sourceFile = proj.addSourceFileAtPath(filePath);
156
+ return parseSourceFile(sourceFile);
157
+ }
158
+ //# sourceMappingURL=tsParser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tsParser.js","sourceRoot":"","sources":["../../src/parser/tsParser.ts"],"names":[],"mappings":";;AAkKA,oCAoBC;AASD,8BAIC;AAnMD,yCAA6C;AAC7C,uCAAoD;AAGpD,kDAAuF;AAEvF,SAAS,cAAc,CAAC,UAAsB,EAAE,QAAgB;IAC9D,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,kBAAkB,GAAG,UAAU,CAAC,qBAAqB,EAAE,CAAC;IAE9D,KAAK,MAAM,UAAU,IAAI,kBAAkB,EAAE,CAAC;QAC5C,MAAM,eAAe,GAAG,UAAU,CAAC,uBAAuB,EAAE,CAAC;QAE7D,IAAI,IAAA,4BAAgB,EAAC,eAAe,CAAC,EAAE,CAAC;YACtC,MAAM,YAAY,GAAG,iBAAiB,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC;YAClE,IAAI,YAAY,EAAE,CAAC;gBACjB,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;YAC7B,CAAC;QACH,CAAC;aAAM,IAAI,CAAC,IAAA,4BAAgB,EAAC,eAAe,CAAC,EAAE,CAAC;YAC9C,mDAAmD;YACnD,wEAAwE;YACxE,kCAAkC;QACpC,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,cAAc,CAAC,UAAsB,EAAE,QAAgB;IAI9D,MAAM,OAAO,GAAkB,EAAE,CAAC;IAClC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,iBAAiB,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAElD,KAAK,MAAM,SAAS,IAAI,iBAAiB,EAAE,CAAC;QAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,OAAO,EAAE,CAAC;QACjC,IAAI,IAAI,EAAE,CAAC;YACT,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;YAC1C,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,EAAE,CAAC;YAE1C,OAAO,CAAC,IAAI,CAAC;gBACX,IAAI;gBACJ,UAAU;gBACV,UAAU;gBACV,QAAQ;aACT,CAAC,CAAC;YAEH,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACrB,CAAC;QACH,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,CAAC;AAC9B,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAsB;IAI/C,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,IAAI,UAAU,GAAG,CAAC,CAAC;IACnB,MAAM,qBAAqB,GAAG,UAAU,CAAC,aAAa,EAAE,CAAC;IAEzD,KAAK,MAAM,aAAa,IAAI,qBAAqB,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;QACrC,IAAI,aAAa,CAAC,UAAU,EAAE,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YACnB,UAAU,EAAE,CAAC;QACf,CAAC;aAAM,CAAC;YACN,UAAU,EAAE,CAAC;QACf,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAsB,EAAE,QAAgB;IAIjE,MAAM,UAAU,GAAsB,EAAE,CAAC;IACzC,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,qBAAqB,GAAG,UAAU,CAAC,UAAU,EAAE,CAAC;IAEtD,KAAK,MAAM,aAAa,IAAI,qBAAqB,EAAE,CAAC;QAClD,MAAM,IAAI,GAAG,aAAa,CAAC,OAAO,EAAE,CAAC;QACrC,UAAU,CAAC,IAAI,CAAC;YACd,IAAI;YACJ,QAAQ;SACT,CAAC,CAAC;QAEH,IAAI,aAAa,CAAC,UAAU,EAAE,EAAE,CAAC;YAC/B,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,CAAC;IACH,CAAC;IAED,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,CAAC;AACjC,CAAC;AAED,SAAS,mBAAmB,CAAC,UAAsB,EAAE,eAAyB;IAC5E,MAAM,YAAY,GAAa,EAAE,CAAC;IAClC,MAAM,oBAAoB,GAAG,UAAU,CAAC,uBAAuB,EAAE,CAAC;IAElE,KAAK,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,IAAI,oBAAoB,EAAE,CAAC;QACxD,IAAI,eAAe,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,SAAS;QACX,CAAC;QAED,IAAI,YAAY,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1B,CAAC;IACH,CAAC;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED,SAAS,eAAe,CAAC,UAAsB;IAC7C,MAAM,QAAQ,GAAG,IAAA,yBAAa,EAAC,UAAU,CAAC,WAAW,EAAE,CAAC,CAAC;IAEzD,MAAM,OAAO,GAAG,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IACrD,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,cAAc,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAChF,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,iBAAiB,CAAC,UAAU,CAAC,CAAC;IAChF,MAAM,EAAE,UAAU,EAAE,OAAO,EAAE,gBAAgB,EAAE,GAAG,iBAAiB,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC;IAE1F,MAAM,UAAU,GAAG,CAAC,GAAG,YAAY,EAAE,GAAG,gBAAgB,EAAE,GAAG,gBAAgB,CAAC,CAAC;IAC/E,MAAM,YAAY,GAAG,mBAAmB,CAAC,UAAU,EAAE,UAAU,CAAC,CAAC;IACjE,MAAM,OAAO,GAAG,CAAC,GAAG,UAAU,EAAE,GAAG,YAAY,CAAC,CAAC;IAEjD,MAAM,UAAU,GAAG,OAAO,CAAC,MAAM,GAAG,UAAU,CAAC;IAE/C,OAAO;QACL,QAAQ;QACR,OAAO;QACP,OAAO;QACP,OAAO;QACP,UAAU;QACV,UAAU;QACV,UAAU;KACX,CAAC;AACJ,CAAC;AAED,SAAS,iBAAiB,CAAC,eAAuB,EAAE,QAAgB;IAClE,MAAM,GAAG,GAAG,IAAA,mBAAO,EAAC,QAAQ,CAAC,CAAC;IAE9B,yCAAyC;IACzC,MAAM,YAAY,GAAG,IAAA,mBAAO,EAAC,GAAG,EAAE,eAAe,CAAC,CAAC;IAEnD,uDAAuD;IACvD,MAAM,UAAU,GAAG,YAAY,GAAG,KAAK,CAAC;IACxC,OAAO,IAAA,yBAAa,EAAC,UAAU,CAAC,CAAC;AACnC,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,YAAY,CAAC,SAAmB,EAAE,YAAqB;IACrE,MAAM,OAAO,GAAG,IAAI,kBAAO,CAAC;QAC1B,gBAAgB,EAAE,YAAY;QAC9B,2BAA2B,EAAE,IAAI;KAClC,CAAC,CAAC;IAEH,+BAA+B;IAC/B,KAAK,MAAM,QAAQ,IAAI,SAAS,EAAE,CAAC;QACjC,OAAO,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACxC,CAAC;IAED,MAAM,OAAO,GAAmB,EAAE,CAAC;IACnC,MAAM,WAAW,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC;IAE7C,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;QACrC,MAAM,YAAY,GAAG,eAAe,CAAC,UAAU,CAAC,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC7B,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,SAAgB,SAAS,CAAC,QAAgB,EAAE,OAAiB;IAC3D,MAAM,IAAI,GAAG,OAAO,IAAI,IAAI,kBAAO,EAAE,CAAC;IACtC,MAAM,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,QAAQ,CAAC,CAAC;IACtD,OAAO,eAAe,CAAC,UAAU,CAAC,CAAC;AACrC,CAAC"}
@@ -0,0 +1,74 @@
1
+ import type { DependencyGraph } from '../graph/dependencyGraph';
2
+ import type { ParsedModule } from './parser';
3
+ import type { ModuleMetrics } from './graph';
4
+ import type { AnalysisReport } from '../analysis/reporter';
5
+ import type { TDependConfig } from '../config/schema';
6
+ /**
7
+ * Main result returned by the analyze() function.
8
+ * Contains rich objects (DependencyGraph with Sets) suitable for programmatic use.
9
+ */
10
+ export interface AnalysisResult {
11
+ /** Parsed modules with imports, exports, classes, etc. */
12
+ modules: ParsedModule[];
13
+ /** Dependency graph with Set-based relationships */
14
+ graph: DependencyGraph;
15
+ /** Detected dependency cycles */
16
+ cycles: string[][];
17
+ /** Computed metrics for each module */
18
+ metrics: ModuleMetrics[];
19
+ /** Generated analysis report with summary and violations */
20
+ report: AnalysisReport;
21
+ /** Configuration used for this analysis */
22
+ config: TDependConfig;
23
+ }
24
+ /**
25
+ * Serializable version of DependencyNode with Arrays instead of Sets.
26
+ */
27
+ export interface SerializableDependencyNode {
28
+ /** File path of this module */
29
+ filePath: string;
30
+ /** Modules that this module depends on (outgoing dependencies) */
31
+ dependencies: string[];
32
+ /** Modules that depend on this module (incoming dependencies) */
33
+ dependents: string[];
34
+ }
35
+ /**
36
+ * Serializable dependency graph with array-based relationships.
37
+ */
38
+ export interface SerializableDependencyGraph {
39
+ /** All nodes in the dependency graph */
40
+ nodes: SerializableDependencyNode[];
41
+ }
42
+ /**
43
+ * Normalized cycle with stable identification.
44
+ */
45
+ export interface SerializableCycle {
46
+ /** Unique identifier (hash of sorted file paths) */
47
+ id: string;
48
+ /** File paths forming the cycle (normalized to start with lexicographically smallest) */
49
+ nodes: string[];
50
+ /** Number of nodes in the cycle */
51
+ length: number;
52
+ }
53
+ /**
54
+ * Complete serializable analysis result suitable for JSON export.
55
+ * All Sets are converted to Arrays for proper JSON serialization.
56
+ */
57
+ export interface SerializableAnalysisResult {
58
+ /** Format version for compatibility checking */
59
+ version: string;
60
+ /** ISO 8601 timestamp of when this analysis was generated */
61
+ timestamp: string;
62
+ /** Configuration used for this analysis */
63
+ config: TDependConfig;
64
+ /** Parsed modules with imports, exports, classes, etc. */
65
+ modules: ParsedModule[];
66
+ /** Serializable dependency graph */
67
+ graph: SerializableDependencyGraph;
68
+ /** Normalized cycles with unique IDs */
69
+ cycles: SerializableCycle[];
70
+ /** Computed metrics for each module */
71
+ metrics: ModuleMetrics[];
72
+ /** Generated analysis report with summary and violations */
73
+ report: AnalysisReport;
74
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api.js","sourceRoot":"","sources":["../../src/types/api.ts"],"names":[],"mappings":""}
@@ -0,0 +1,14 @@
1
+ export interface DependencyNode {
2
+ filePath: string;
3
+ dependencies: Set<string>;
4
+ dependents: Set<string>;
5
+ }
6
+ export interface ModuleMetrics {
7
+ filePath: string;
8
+ Ca: number;
9
+ Ce: number;
10
+ cycles: string[][];
11
+ abstractness: number;
12
+ instability: number;
13
+ distance: number;
14
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph.js","sourceRoot":"","sources":["../../src/types/graph.ts"],"names":[],"mappings":""}
@@ -0,0 +1,26 @@
1
+ export interface ParsedClass {
2
+ name: string;
3
+ isAbstract: boolean;
4
+ isExported: boolean;
5
+ filePath: string;
6
+ }
7
+ export interface ParsedNamespace {
8
+ name: string;
9
+ filePath: string;
10
+ }
11
+ export interface ParsedModule {
12
+ /** Normalized absolute path to the module file */
13
+ filePath: string;
14
+ /** Resolved import paths (normalized file paths) */
15
+ imports: string[];
16
+ /** Names of exported symbols */
17
+ exports: string[];
18
+ /** Parsed classes in this module */
19
+ classes: ParsedClass[];
20
+ /** Parsed namespaces in this module */
21
+ namespaces: ParsedNamespace[];
22
+ /** Count of interfaces (for abstractness calculation) */
23
+ interfaces: number;
24
+ /** Total count of types (classes + interfaces) */
25
+ totalTypes: number;
26
+ }
@@ -0,0 +1,3 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ //# sourceMappingURL=parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parser.js","sourceRoot":"","sources":["../../src/types/parser.ts"],"names":[],"mappings":""}
@@ -0,0 +1 @@
1
+ export declare function deepMerge<T extends Record<string, unknown>>(target: T, source: Partial<T>): T;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepMerge = deepMerge;
4
+ function deepMerge(target, source) {
5
+ const result = { ...target };
6
+ for (const key in source) {
7
+ const sourceValue = source[key];
8
+ const targetValue = result[key];
9
+ if (sourceValue &&
10
+ typeof sourceValue === 'object' &&
11
+ !Array.isArray(sourceValue) &&
12
+ targetValue &&
13
+ typeof targetValue === 'object' &&
14
+ !Array.isArray(targetValue)) {
15
+ result[key] = deepMerge(targetValue, sourceValue);
16
+ }
17
+ else if (sourceValue !== undefined) {
18
+ result[key] = sourceValue;
19
+ }
20
+ }
21
+ return result;
22
+ }
23
+ //# sourceMappingURL=deepMerge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deepMerge.js","sourceRoot":"","sources":["../../src/utils/deepMerge.ts"],"names":[],"mappings":";;AAAA,8BAyBC;AAzBD,SAAgB,SAAS,CAAoC,MAAS,EAAE,MAAkB;IACxF,MAAM,MAAM,GAAG,EAAE,GAAG,MAAM,EAAE,CAAC;IAE7B,KAAK,MAAM,GAAG,IAAI,MAAM,EAAE,CAAC;QACzB,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAChC,MAAM,WAAW,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAEhC,IACE,WAAW;YACX,OAAO,WAAW,KAAK,QAAQ;YAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC;YAC3B,WAAW;YACX,OAAO,WAAW,KAAK,QAAQ;YAC/B,CAAC,KAAK,CAAC,OAAO,CAAC,WAAW,CAAC,EAC3B,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,SAAS,CACrB,WAAsC,EACtC,WAAsC,CACR,CAAC;QACnC,CAAC;aAAM,IAAI,WAAW,KAAK,SAAS,EAAE,CAAC;YACrC,MAAM,CAAC,GAAG,CAAC,GAAG,WAA0C,CAAC;QAC3D,CAAC;IACH,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,2 @@
1
+ import { TDependConfig } from "../config/schema";
2
+ export declare function log(config: TDependConfig, message: string): void;
@@ -0,0 +1,9 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.log = log;
4
+ function log(config, message) {
5
+ if (config.ci.outputFormat !== 'json') {
6
+ console.log(message);
7
+ }
8
+ }
9
+ //# sourceMappingURL=log.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/utils/log.ts"],"names":[],"mappings":";;AAEA,kBAIC;AAJD,SAAgB,GAAG,CAAC,MAAqB,EAAE,OAAe;IACxD,IAAI,MAAM,CAAC,EAAE,CAAC,YAAY,KAAK,MAAM,EAAE,CAAC;QACtC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
@@ -0,0 +1,12 @@
1
+ /**
2
+ * Normalize a file path to an absolute, cross-platform path
3
+ */
4
+ export declare function normalizePath(filePath: string): string;
5
+ /**
6
+ * Check if an import specifier is a relative import
7
+ */
8
+ export declare function isRelativeImport(importSpecifier: string): boolean;
9
+ /**
10
+ * Check if an import specifier is an external module
11
+ */
12
+ export declare function isExternalModule(importSpecifier: string): boolean;
@@ -0,0 +1,27 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.normalizePath = normalizePath;
4
+ exports.isRelativeImport = isRelativeImport;
5
+ exports.isExternalModule = isExternalModule;
6
+ const node_path_1 = require("node:path");
7
+ /**
8
+ * Normalize a file path to an absolute, cross-platform path
9
+ */
10
+ function normalizePath(filePath) {
11
+ const absolutePath = (0, node_path_1.isAbsolute)(filePath) ? filePath : (0, node_path_1.resolve)(filePath);
12
+ return (0, node_path_1.normalize)(absolutePath);
13
+ }
14
+ /**
15
+ * Check if an import specifier is a relative import
16
+ */
17
+ function isRelativeImport(importSpecifier) {
18
+ return importSpecifier.startsWith('./') || importSpecifier.startsWith('../');
19
+ }
20
+ /**
21
+ * Check if an import specifier is an external module
22
+ */
23
+ function isExternalModule(importSpecifier) {
24
+ // External if it doesn't start with . or /
25
+ return !importSpecifier.startsWith('.') && !importSpecifier.startsWith('/');
26
+ }
27
+ //# sourceMappingURL=pathUtils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pathUtils.js","sourceRoot":"","sources":["../../src/utils/pathUtils.ts"],"names":[],"mappings":";;AAKA,sCAGC;AAKD,4CAEC;AAKD,4CAGC;AAvBD,yCAA2D;AAE3D;;GAEG;AACH,SAAgB,aAAa,CAAC,QAAgB;IAC5C,MAAM,YAAY,GAAG,IAAA,sBAAU,EAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAA,mBAAO,EAAC,QAAQ,CAAC,CAAC;IACzE,OAAO,IAAA,qBAAS,EAAC,YAAY,CAAC,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,eAAuB;IACtD,OAAO,eAAe,CAAC,UAAU,CAAC,IAAI,CAAC,IAAI,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC;AAC/E,CAAC;AAED;;GAEG;AACH,SAAgB,gBAAgB,CAAC,eAAuB;IACtD,2CAA2C;IAC3C,OAAO,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,CAAC,eAAe,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;AAC9E,CAAC"}
package/package.json ADDED
@@ -0,0 +1,77 @@
1
+ {
2
+ "name": "tdepend",
3
+ "version": "0.2.0",
4
+ "description": "JDepend-inspired dependency analysis tool for TypeScript",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "bin": {
8
+ "tdepend": "dist/cli/index.js"
9
+ },
10
+ "exports": {
11
+ ".": {
12
+ "import": "./dist/index.js",
13
+ "require": "./dist/index.js",
14
+ "types": "./dist/index.d.ts"
15
+ },
16
+ "./cli": {
17
+ "import": "./dist/cli/index.js",
18
+ "require": "./dist/cli/index.js"
19
+ }
20
+ },
21
+ "files": [
22
+ "dist",
23
+ "README.md"
24
+ ],
25
+ "keywords": [
26
+ "dependency",
27
+ "analysis",
28
+ "typescript",
29
+ "cli",
30
+ "library",
31
+ "api",
32
+ "jdepend",
33
+ "metrics",
34
+ "architecture",
35
+ "coupling",
36
+ "abstractness",
37
+ "instability",
38
+ "dependency-analysis",
39
+ "code-quality"
40
+ ],
41
+ "repository": {
42
+ "type": "git",
43
+ "url": "https://github.com/dvmhmdsd/tdepend.git"
44
+ },
45
+ "bugs": {
46
+ "url": "https://github.com/dvmhmdsd/tdepend/issues"
47
+ },
48
+ "homepage": "https://github.com/dvmhmdsd/tdepend#readme",
49
+ "author": "Mohamed Saad <mohamed.tarif999@gmail.com>",
50
+ "license": "MIT",
51
+ "packageManager": "pnpm@8.15.4",
52
+ "engines": {
53
+ "node": ">=20.0.0"
54
+ },
55
+ "dependencies": {
56
+ "commander": "^12.0.0",
57
+ "glob": "^13.0.0",
58
+ "ts-morph": "^27.0.2",
59
+ "zod": "^4.1.13"
60
+ },
61
+ "devDependencies": {
62
+ "@types/glob": "^9.0.0",
63
+ "@types/node": "^20.11.30",
64
+ "prettier": "^3.1.1",
65
+ "ts-node": "^10.9.2",
66
+ "typescript": "^5.6.3",
67
+ "vitest": "^1.6.0"
68
+ },
69
+ "scripts": {
70
+ "build": "tsc -p tsconfig.json",
71
+ "typecheck": "tsc -p tsconfig.json --noEmit",
72
+ "dev": "ts-node src/cli/index.ts analyze --help",
73
+ "cli": "node dist/cli/index.js",
74
+ "test": "vitest run",
75
+ "format": "prettier --write ."
76
+ }
77
+ }