@ace-sdk/core 2.0.0 → 2.1.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 (35) hide show
  1. package/dist/cache/project-index.d.ts +152 -0
  2. package/dist/cache/project-index.d.ts.map +1 -0
  3. package/dist/cache/project-index.js +290 -0
  4. package/dist/cache/project-index.js.map +1 -0
  5. package/dist/config/loader.d.ts.map +1 -1
  6. package/dist/config/loader.js +15 -0
  7. package/dist/config/loader.js.map +1 -1
  8. package/dist/index.d.ts +13 -1
  9. package/dist/index.d.ts.map +1 -1
  10. package/dist/index.js +10 -0
  11. package/dist/index.js.map +1 -1
  12. package/dist/services/bootstrap-stream.d.ts +113 -0
  13. package/dist/services/bootstrap-stream.d.ts.map +1 -0
  14. package/dist/services/bootstrap-stream.js +261 -0
  15. package/dist/services/bootstrap-stream.js.map +1 -0
  16. package/dist/services/import-graph.d.ts +111 -0
  17. package/dist/services/import-graph.d.ts.map +1 -0
  18. package/dist/services/import-graph.js +292 -0
  19. package/dist/services/import-graph.js.map +1 -0
  20. package/dist/services/language-detector.d.ts +120 -0
  21. package/dist/services/language-detector.d.ts.map +1 -0
  22. package/dist/services/language-detector.js +210 -0
  23. package/dist/services/language-detector.js.map +1 -0
  24. package/dist/types/bootstrap-events.d.ts +251 -0
  25. package/dist/types/bootstrap-events.d.ts.map +1 -0
  26. package/dist/types/bootstrap-events.js +103 -0
  27. package/dist/types/bootstrap-events.js.map +1 -0
  28. package/dist/types/config.d.ts +5 -0
  29. package/dist/types/config.d.ts.map +1 -1
  30. package/dist/types/config.js.map +1 -1
  31. package/dist/types/project-dna.d.ts +151 -0
  32. package/dist/types/project-dna.d.ts.map +1 -0
  33. package/dist/types/project-dna.js +42 -0
  34. package/dist/types/project-dna.js.map +1 -0
  35. package/package.json +3 -2
@@ -0,0 +1,292 @@
1
+ /**
2
+ * Import Graph Analysis Service
3
+ *
4
+ * Uses Skott for JS/TS dependency graph analysis with dead code detection.
5
+ * Routes to appropriate analyzer based on primary language.
6
+ *
7
+ * @package @ace-sdk/core
8
+ */
9
+ import skott from 'skott';
10
+ import { LanguageDetector } from './language-detector.js';
11
+ // =============================================================================
12
+ // Constants
13
+ // =============================================================================
14
+ /**
15
+ * Default paths to ignore during analysis
16
+ */
17
+ export const DEFAULT_IGNORE_PATHS = [
18
+ 'node_modules',
19
+ 'dist',
20
+ 'build',
21
+ '.git',
22
+ '.next',
23
+ 'coverage',
24
+ '__tests__',
25
+ '__mocks__',
26
+ '*.test.*',
27
+ '*.spec.*'
28
+ ];
29
+ /**
30
+ * Minimum number of importers to be considered a hub
31
+ */
32
+ export const HUB_THRESHOLD = 5;
33
+ // =============================================================================
34
+ // Import Graph Builder
35
+ // =============================================================================
36
+ /**
37
+ * Build import graph using Skott for JS/TS projects
38
+ */
39
+ async function buildSkottGraph(options) {
40
+ const { repoPath, ignorePaths = DEFAULT_IGNORE_PATHS } = options;
41
+ const graph = {
42
+ nodes: new Map(),
43
+ entryPoints: [],
44
+ hubFiles: [],
45
+ leafFiles: [],
46
+ circularDeps: [],
47
+ deadCode: [],
48
+ unusedDeps: []
49
+ };
50
+ try {
51
+ // Run Skott analysis with config
52
+ const skottInstance = await skott({
53
+ cwd: repoPath,
54
+ entrypoint: options.entryPoints?.[0],
55
+ includeBaseDir: false,
56
+ ignorePatterns: ignorePaths,
57
+ dependencyTracking: {
58
+ thirdParty: true,
59
+ builtin: false,
60
+ typeOnly: true
61
+ },
62
+ fileExtensions: ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs'],
63
+ tsConfigPath: 'tsconfig.json',
64
+ manifestPath: 'package.json',
65
+ incremental: false,
66
+ circularMaxDepth: 10,
67
+ verbose: false
68
+ });
69
+ // Get structure from the instance
70
+ const structure = skottInstance.getStructure();
71
+ const { files, graph: skottGraph } = structure;
72
+ // Get circular dependencies and unused deps from graph API
73
+ const graphApi = skottInstance.useGraph();
74
+ const circularDependencies = graphApi.findCircularDependencies();
75
+ const unusedDependencies = await skottInstance.findUnusedDependencies();
76
+ // Build our graph from Skott's output
77
+ // SkottNode has: { id, adjacentTo: string[], body: { size, thirdPartyDependencies, builtinDependencies } }
78
+ for (const file of files) {
79
+ const node = skottGraph[file];
80
+ const deps = node?.adjacentTo || [];
81
+ graph.nodes.set(file, {
82
+ path: file,
83
+ imports: deps,
84
+ importedBy: [],
85
+ isEntryPoint: false,
86
+ isHub: false,
87
+ isLeaf: deps.length === 0
88
+ });
89
+ }
90
+ // Build reverse mapping (who imports this file)
91
+ for (const [filePath, node] of graph.nodes) {
92
+ for (const dep of node.imports) {
93
+ const depNode = graph.nodes.get(dep);
94
+ if (depNode) {
95
+ depNode.importedBy.push(filePath);
96
+ }
97
+ }
98
+ }
99
+ // Identify entry points, hubs, and dead code
100
+ for (const [filePath, node] of graph.nodes) {
101
+ // Entry point: no one imports this file
102
+ if (node.importedBy.length === 0) {
103
+ node.isEntryPoint = true;
104
+ graph.entryPoints.push(filePath);
105
+ }
106
+ // Hub: many files import this
107
+ if (node.importedBy.length >= HUB_THRESHOLD) {
108
+ node.isHub = true;
109
+ graph.hubFiles.push(filePath);
110
+ }
111
+ // Leaf: no dependencies
112
+ if (node.isLeaf) {
113
+ graph.leafFiles.push(filePath);
114
+ }
115
+ }
116
+ // Dead code: files that are never imported (but not entry points)
117
+ // Use Skott's circular dependencies detection
118
+ graph.circularDeps = circularDependencies || [];
119
+ // Unused npm dependencies (thirdParty is the property containing unused deps)
120
+ graph.unusedDeps = unusedDependencies?.thirdParty || [];
121
+ // Find orphan files (not entry points but never imported)
122
+ for (const [filePath, node] of graph.nodes) {
123
+ if (node.importedBy.length === 0 && !isLikelyEntryPoint(filePath)) {
124
+ graph.deadCode.push(filePath);
125
+ }
126
+ }
127
+ return graph;
128
+ }
129
+ catch (error) {
130
+ console.error('Skott analysis failed:', error);
131
+ return graph;
132
+ }
133
+ }
134
+ /**
135
+ * Check if a file is likely an entry point
136
+ */
137
+ function isLikelyEntryPoint(filePath) {
138
+ const entryPatterns = [
139
+ /^index\.[jt]sx?$/,
140
+ /^main\.[jt]sx?$/,
141
+ /^app\.[jt]sx?$/,
142
+ /^server\.[jt]sx?$/,
143
+ /^cli\.[jt]sx?$/,
144
+ /\/index\.[jt]sx?$/,
145
+ /\/main\.[jt]sx?$/,
146
+ /src\/index\.[jt]sx?$/,
147
+ /src\/main\.[jt]sx?$/
148
+ ];
149
+ return entryPatterns.some(pattern => pattern.test(filePath));
150
+ }
151
+ /**
152
+ * Build import graph using git co-occurrence for non-JS/TS projects
153
+ * (Fallback when no static analyzer is available)
154
+ */
155
+ async function buildGitCooccurrenceGraph(_options) {
156
+ // For non-JS/TS projects, we can't do static analysis
157
+ // Return empty graph - future: implement git co-occurrence analysis
158
+ return {
159
+ nodes: new Map(),
160
+ entryPoints: [],
161
+ hubFiles: [],
162
+ leafFiles: [],
163
+ circularDeps: [],
164
+ deadCode: [],
165
+ unusedDeps: []
166
+ };
167
+ }
168
+ // =============================================================================
169
+ // Main Export
170
+ // =============================================================================
171
+ /**
172
+ * Build import graph with language-based routing
173
+ *
174
+ * Routes to the best analyzer based on primary language:
175
+ * - TypeScript/JavaScript: Skott (fast, dead code detection)
176
+ * - Other languages: Git co-occurrence fallback
177
+ *
178
+ * @param options - Import graph options
179
+ * @returns Complete import graph analysis
180
+ *
181
+ * @example
182
+ * ```typescript
183
+ * const graph = await buildImportGraph({ repoPath: '/path/to/repo' });
184
+ *
185
+ * console.log(`Entry points: ${graph.entryPoints.length}`);
186
+ * console.log(`Hub files: ${graph.hubFiles.length}`);
187
+ * console.log(`Dead code: ${graph.deadCode.length}`);
188
+ * console.log(`Circular deps: ${graph.circularDeps.length}`);
189
+ * ```
190
+ */
191
+ export async function buildImportGraph(options) {
192
+ const detector = new LanguageDetector();
193
+ const primaryLang = await detector.getPrimaryLanguage(options.repoPath);
194
+ // Route to best analyzer for this language
195
+ switch (primaryLang) {
196
+ case 'TypeScript':
197
+ case 'JavaScript':
198
+ case 'TSX':
199
+ case 'JSX':
200
+ return buildSkottGraph(options);
201
+ // Future: Add support for other languages
202
+ // case 'Java':
203
+ // case 'Python':
204
+ // case 'Go':
205
+ // return buildDependsGraph(options);
206
+ default:
207
+ // Fallback to git co-occurrence
208
+ return buildGitCooccurrenceGraph(options);
209
+ }
210
+ }
211
+ /**
212
+ * Select priority files from import graph for bootstrap
213
+ *
214
+ * Priority order:
215
+ * 1. Entry points (always include)
216
+ * 2. Hub files (most imported - high value)
217
+ * 3. Files in circular deps (need attention)
218
+ * 4. Leaf files with many exports (API surface)
219
+ * 5. Fill remaining with diverse sampling
220
+ *
221
+ * @param graph - Import graph to select from
222
+ * @param maxFiles - Maximum files to select
223
+ * @returns Array of priority file paths
224
+ */
225
+ export function selectPriorityFiles(graph, maxFiles) {
226
+ const priority = [];
227
+ const seen = new Set();
228
+ const addUnique = (files, limit) => {
229
+ let added = 0;
230
+ for (const file of files) {
231
+ if (!seen.has(file)) {
232
+ seen.add(file);
233
+ priority.push(file);
234
+ added++;
235
+ if (limit && added >= limit)
236
+ break;
237
+ }
238
+ }
239
+ };
240
+ // 1. Entry points (always include)
241
+ addUnique(graph.entryPoints, 10);
242
+ // 2. Hub files (most imported - high value)
243
+ const sortedHubs = [...graph.hubFiles].sort((a, b) => {
244
+ const aNode = graph.nodes.get(a);
245
+ const bNode = graph.nodes.get(b);
246
+ return (bNode?.importedBy.length || 0) - (aNode?.importedBy.length || 0);
247
+ });
248
+ addUnique(sortedHubs, 20);
249
+ // 3. Files in circular deps (need attention)
250
+ const circularFiles = graph.circularDeps.flat();
251
+ addUnique(circularFiles, 10);
252
+ // 4. Leaf files with many exports (API surface)
253
+ const apiSurface = [...graph.nodes.entries()]
254
+ .filter(([_, n]) => n.isLeaf && n.importedBy.length > 0)
255
+ .sort((a, b) => b[1].importedBy.length - a[1].importedBy.length)
256
+ .map(([p]) => p);
257
+ addUnique(apiSurface, 20);
258
+ // 5. Fill remaining with diverse sampling
259
+ if (priority.length < maxFiles) {
260
+ const remaining = [...graph.nodes.keys()].filter(p => !seen.has(p));
261
+ addUnique(remaining, maxFiles - priority.length);
262
+ }
263
+ return priority.slice(0, maxFiles);
264
+ }
265
+ /**
266
+ * Convert import graph to GraphMetrics for ProjectDNA
267
+ */
268
+ export function graphToMetrics(graph) {
269
+ return {
270
+ totalFiles: graph.nodes.size,
271
+ hubFiles: graph.hubFiles.slice(0, 20),
272
+ entryPoints: graph.entryPoints.slice(0, 10),
273
+ leafNodes: graph.leafFiles.slice(0, 20),
274
+ circularDeps: graph.circularDeps.slice(0, 10)
275
+ };
276
+ }
277
+ /**
278
+ * Calculate code health metrics from import graph
279
+ */
280
+ export function calculateHealthMetrics(graph, totalFiles, avgFileSize, maxFileSize) {
281
+ const deadCodePercentage = totalFiles > 0
282
+ ? (graph.deadCode.length / totalFiles) * 100
283
+ : 0;
284
+ return {
285
+ deadCodePercentage,
286
+ circularDepsCount: graph.circularDeps.length,
287
+ unusedDepsCount: graph.unusedDeps.length,
288
+ avgFileSize,
289
+ maxFileSize
290
+ };
291
+ }
292
+ //# sourceMappingURL=import-graph.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"import-graph.js","sourceRoot":"","sources":["../../src/services/import-graph.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * Language Detection Service using GitHub Linguist
3
+ *
4
+ * Dynamically detects programming languages instead of hardcoding file extensions.
5
+ * Uses linguist-js which is a JavaScript port of GitHub's Linguist library.
6
+ *
7
+ * @package @ace-sdk/core
8
+ */
9
+ import type { Category } from 'linguist-js/dist/types.js';
10
+ import type { LanguageStats as ProjectLanguageStats } from '../types/project-dna.js';
11
+ /**
12
+ * Raw language statistics from linguist-js
13
+ */
14
+ export interface LanguageStats {
15
+ files: {
16
+ count: number;
17
+ results: Record<string, string | null>;
18
+ };
19
+ languages: {
20
+ count: number;
21
+ results: Record<string, {
22
+ type: string;
23
+ bytes: number;
24
+ }>;
25
+ };
26
+ }
27
+ /**
28
+ * Options for language analysis
29
+ */
30
+ export interface LanguageAnalysisOptions {
31
+ /** Use quick mode (skip complex analysis) */
32
+ quick?: boolean;
33
+ /** Glob patterns for files to ignore */
34
+ ignoredFiles?: string[];
35
+ /** File categories to include */
36
+ categories?: Category[];
37
+ }
38
+ /**
39
+ * Default ignored patterns (vendored, generated, lock files)
40
+ */
41
+ export declare const DEFAULT_IGNORED_PATTERNS: string[];
42
+ /**
43
+ * Default categories (exclude prose/documentation)
44
+ */
45
+ export declare const DEFAULT_CATEGORIES: Category[];
46
+ /**
47
+ * Language detection service using GitHub Linguist
48
+ *
49
+ * @example
50
+ * ```typescript
51
+ * const detector = new LanguageDetector();
52
+ *
53
+ * // Get primary language
54
+ * const primary = await detector.getPrimaryLanguage('/path/to/repo');
55
+ * console.log(primary); // "TypeScript"
56
+ *
57
+ * // Get language breakdown
58
+ * const breakdown = await detector.getLanguageBreakdown('/path/to/repo');
59
+ * console.log(breakdown); // { TypeScript: 75.5, JavaScript: 20.3, ... }
60
+ *
61
+ * // Get all programming files
62
+ * const files = await detector.getProgrammingFiles('/path/to/repo', 1000);
63
+ * console.log(files); // ["src/index.ts", "src/utils.ts", ...]
64
+ * ```
65
+ */
66
+ export declare class LanguageDetector {
67
+ /**
68
+ * Analyze a directory and detect all programming languages
69
+ *
70
+ * @param repoPath - Path to repository
71
+ * @param options - Analysis options
72
+ * @returns Language statistics with file mappings
73
+ */
74
+ analyzeDirectory(repoPath: string, options?: LanguageAnalysisOptions): Promise<LanguageStats>;
75
+ /**
76
+ * Get all source files of programming languages (excluding vendor, generated, docs)
77
+ *
78
+ * @param repoPath - Path to repository
79
+ * @param maxFiles - Maximum files to return (-1 for unlimited)
80
+ * @returns Array of file paths
81
+ */
82
+ getProgrammingFiles(repoPath: string, maxFiles?: number): Promise<string[]>;
83
+ /**
84
+ * Get language breakdown for repository
85
+ *
86
+ * @param repoPath - Path to repository
87
+ * @returns Map of language name to percentage
88
+ */
89
+ getLanguageBreakdown(repoPath: string): Promise<Record<string, number>>;
90
+ /**
91
+ * Get detailed language stats for ProjectDNA
92
+ *
93
+ * @param repoPath - Path to repository
94
+ * @returns Array of LanguageStats for ProjectDNA
95
+ */
96
+ getLanguageStatsForDNA(repoPath: string): Promise<ProjectLanguageStats[]>;
97
+ /**
98
+ * Check if file is a programming language file
99
+ *
100
+ * @param filepath - Full path to file
101
+ * @returns Language name or null
102
+ */
103
+ detectFileLanguage(filepath: string): Promise<string | null>;
104
+ /**
105
+ * Get primary language of repository
106
+ *
107
+ * @param repoPath - Path to repository
108
+ * @returns Primary language name or null
109
+ */
110
+ getPrimaryLanguage(repoPath: string): Promise<string | null>;
111
+ /**
112
+ * Get files by language
113
+ *
114
+ * @param repoPath - Path to repository
115
+ * @param language - Language to filter by
116
+ * @returns Array of file paths for that language
117
+ */
118
+ getFilesByLanguage(repoPath: string, language: string): Promise<string[]>;
119
+ }
120
+ //# sourceMappingURL=language-detector.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.d.ts","sourceRoot":"","sources":["../../src/services/language-detector.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,2BAA2B,CAAC;AAC1D,OAAO,KAAK,EAAE,aAAa,IAAI,oBAAoB,EAAE,MAAM,yBAAyB,CAAC;AAMrF;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE;QACL,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAC,CAAC;KACxC,CAAC;IACF,SAAS,EAAE;QACT,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE;YACtB,IAAI,EAAE,MAAM,CAAC;YACb,KAAK,EAAE,MAAM,CAAC;SACf,CAAC,CAAC;KACJ,CAAC;CACH;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACtC,6CAA6C;IAC7C,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,wCAAwC;IACxC,YAAY,CAAC,EAAE,MAAM,EAAE,CAAC;IACxB,iCAAiC;IACjC,UAAU,CAAC,EAAE,QAAQ,EAAE,CAAC;CACzB;AAMD;;GAEG;AACH,eAAO,MAAM,wBAAwB,UAcpC,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,kBAAkB,EAAE,QAAQ,EAAsC,CAAC;AAMhF;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,gBAAgB;IAC3B;;;;;;OAMG;IACG,gBAAgB,CACpB,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,aAAa,CAAC;IA8BzB;;;;;;OAMG;IACG,mBAAmB,CACvB,QAAQ,EAAE,MAAM,EAChB,QAAQ,GAAE,MAAa,GACtB,OAAO,CAAC,MAAM,EAAE,CAAC;IAgBpB;;;;;OAKG;IACG,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAmB7E;;;;;OAKG;IACG,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,EAAE,CAAC;IAoC/E;;;;;OAKG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAalE;;;;;OAKG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IASlE;;;;;;OAMG;IACG,kBAAkB,CAAC,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;CAOhF"}
@@ -0,0 +1,210 @@
1
+ /**
2
+ * Language Detection Service using GitHub Linguist
3
+ *
4
+ * Dynamically detects programming languages instead of hardcoding file extensions.
5
+ * Uses linguist-js which is a JavaScript port of GitHub's Linguist library.
6
+ *
7
+ * @package @ace-sdk/core
8
+ */
9
+ import linguist from 'linguist-js';
10
+ // =============================================================================
11
+ // Default Options
12
+ // =============================================================================
13
+ /**
14
+ * Default ignored patterns (vendored, generated, lock files)
15
+ */
16
+ export const DEFAULT_IGNORED_PATTERNS = [
17
+ 'node_modules/**',
18
+ 'dist/**',
19
+ 'build/**',
20
+ '.git/**',
21
+ '.next/**',
22
+ 'target/**',
23
+ '__pycache__/**',
24
+ 'venv/**',
25
+ '*.min.js',
26
+ '*.bundle.js',
27
+ 'package-lock.json',
28
+ 'yarn.lock',
29
+ 'pnpm-lock.yaml'
30
+ ];
31
+ /**
32
+ * Default categories (exclude prose/documentation)
33
+ */
34
+ export const DEFAULT_CATEGORIES = ['programming', 'markup', 'data'];
35
+ // =============================================================================
36
+ // Language Detector Class
37
+ // =============================================================================
38
+ /**
39
+ * Language detection service using GitHub Linguist
40
+ *
41
+ * @example
42
+ * ```typescript
43
+ * const detector = new LanguageDetector();
44
+ *
45
+ * // Get primary language
46
+ * const primary = await detector.getPrimaryLanguage('/path/to/repo');
47
+ * console.log(primary); // "TypeScript"
48
+ *
49
+ * // Get language breakdown
50
+ * const breakdown = await detector.getLanguageBreakdown('/path/to/repo');
51
+ * console.log(breakdown); // { TypeScript: 75.5, JavaScript: 20.3, ... }
52
+ *
53
+ * // Get all programming files
54
+ * const files = await detector.getProgrammingFiles('/path/to/repo', 1000);
55
+ * console.log(files); // ["src/index.ts", "src/utils.ts", ...]
56
+ * ```
57
+ */
58
+ export class LanguageDetector {
59
+ /**
60
+ * Analyze a directory and detect all programming languages
61
+ *
62
+ * @param repoPath - Path to repository
63
+ * @param options - Analysis options
64
+ * @returns Language statistics with file mappings
65
+ */
66
+ async analyzeDirectory(repoPath, options = {}) {
67
+ const mergedOptions = {
68
+ quick: true,
69
+ ignoredFiles: DEFAULT_IGNORED_PATTERNS,
70
+ categories: DEFAULT_CATEGORIES,
71
+ ...options
72
+ };
73
+ try {
74
+ const result = await linguist(repoPath, mergedOptions);
75
+ return {
76
+ files: {
77
+ count: result.files.count,
78
+ results: result.files.results
79
+ },
80
+ languages: {
81
+ count: result.languages.count,
82
+ results: result.languages.results
83
+ }
84
+ };
85
+ }
86
+ catch (error) {
87
+ console.error('Language detection failed:', error);
88
+ return {
89
+ files: { count: 0, results: {} },
90
+ languages: { count: 0, results: {} }
91
+ };
92
+ }
93
+ }
94
+ /**
95
+ * Get all source files of programming languages (excluding vendor, generated, docs)
96
+ *
97
+ * @param repoPath - Path to repository
98
+ * @param maxFiles - Maximum files to return (-1 for unlimited)
99
+ * @returns Array of file paths
100
+ */
101
+ async getProgrammingFiles(repoPath, maxFiles = 5000) {
102
+ const stats = await this.analyzeDirectory(repoPath);
103
+ // Filter for programming and markup files
104
+ const programmingFiles = Object.entries(stats.files.results)
105
+ .filter(([_, lang]) => lang !== null) // Has detected language
106
+ .map(([filepath]) => filepath);
107
+ // Respect maxFiles limit
108
+ if (maxFiles === -1) {
109
+ return programmingFiles;
110
+ }
111
+ return programmingFiles.slice(0, maxFiles);
112
+ }
113
+ /**
114
+ * Get language breakdown for repository
115
+ *
116
+ * @param repoPath - Path to repository
117
+ * @returns Map of language name to percentage
118
+ */
119
+ async getLanguageBreakdown(repoPath) {
120
+ const stats = await this.analyzeDirectory(repoPath);
121
+ const totalBytes = Object.values(stats.languages.results)
122
+ .reduce((sum, lang) => sum + lang.bytes, 0);
123
+ if (totalBytes === 0) {
124
+ return {};
125
+ }
126
+ const breakdown = {};
127
+ for (const [langName, langData] of Object.entries(stats.languages.results)) {
128
+ breakdown[langName] = (langData.bytes / totalBytes) * 100;
129
+ }
130
+ return breakdown;
131
+ }
132
+ /**
133
+ * Get detailed language stats for ProjectDNA
134
+ *
135
+ * @param repoPath - Path to repository
136
+ * @returns Array of LanguageStats for ProjectDNA
137
+ */
138
+ async getLanguageStatsForDNA(repoPath) {
139
+ const stats = await this.analyzeDirectory(repoPath);
140
+ const totalBytes = Object.values(stats.languages.results)
141
+ .reduce((sum, lang) => sum + lang.bytes, 0);
142
+ if (totalBytes === 0) {
143
+ return [];
144
+ }
145
+ // Count files per language
146
+ const fileCountByLang = {};
147
+ for (const [_, lang] of Object.entries(stats.files.results)) {
148
+ if (lang) {
149
+ fileCountByLang[lang] = (fileCountByLang[lang] || 0) + 1;
150
+ }
151
+ }
152
+ // Build language stats
153
+ const languageStats = [];
154
+ for (const [langName, langData] of Object.entries(stats.languages.results)) {
155
+ languageStats.push({
156
+ name: langName,
157
+ percentage: (langData.bytes / totalBytes) * 100,
158
+ files: fileCountByLang[langName] || 0,
159
+ bytes: langData.bytes
160
+ });
161
+ }
162
+ // Sort by percentage descending
163
+ languageStats.sort((a, b) => b.percentage - a.percentage);
164
+ return languageStats;
165
+ }
166
+ /**
167
+ * Check if file is a programming language file
168
+ *
169
+ * @param filepath - Full path to file
170
+ * @returns Language name or null
171
+ */
172
+ async detectFileLanguage(filepath) {
173
+ try {
174
+ const result = await linguist([filepath], {
175
+ quick: true,
176
+ categories: DEFAULT_CATEGORIES
177
+ });
178
+ return result.files.results[filepath] || null;
179
+ }
180
+ catch {
181
+ return null;
182
+ }
183
+ }
184
+ /**
185
+ * Get primary language of repository
186
+ *
187
+ * @param repoPath - Path to repository
188
+ * @returns Primary language name or null
189
+ */
190
+ async getPrimaryLanguage(repoPath) {
191
+ const breakdown = await this.getLanguageBreakdown(repoPath);
192
+ const sorted = Object.entries(breakdown)
193
+ .sort((a, b) => b[1] - a[1]);
194
+ return sorted.length > 0 ? sorted[0][0] : null;
195
+ }
196
+ /**
197
+ * Get files by language
198
+ *
199
+ * @param repoPath - Path to repository
200
+ * @param language - Language to filter by
201
+ * @returns Array of file paths for that language
202
+ */
203
+ async getFilesByLanguage(repoPath, language) {
204
+ const stats = await this.analyzeDirectory(repoPath);
205
+ return Object.entries(stats.files.results)
206
+ .filter(([_, lang]) => lang === language)
207
+ .map(([filepath]) => filepath);
208
+ }
209
+ }
210
+ //# sourceMappingURL=language-detector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"language-detector.js","sourceRoot":"","sources":["../../src/services/language-detector.ts"],"names":[],"mappings":"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"}