@tech-debt/core 0.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.
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # @tech-debt/core
2
+
3
+ Comment scanner, git blame enrichment, and debt aggregations for Tech Debt.
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Sample fixture used to verify tech-debt scanning.
3
+ *
4
+ * @deprecated Use the new scanner API instead.
5
+ */
6
+ export declare function legacyHelper(): number;
7
+ export declare const FLAG = true;
8
+ //# sourceMappingURL=sample.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.d.ts","sourceRoot":"","sources":["../../src/__fixtures__/sample.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,wBAAgB,YAAY,WAI3B;AAGD,eAAO,MAAM,IAAI,OAAO,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Sample fixture used to verify tech-debt scanning.
3
+ *
4
+ * @deprecated Use the new scanner API instead.
5
+ */
6
+ export function legacyHelper() {
7
+ // TODO: replace with async variant
8
+ // FIXME: handle empty input
9
+ return 42;
10
+ }
11
+ /* TODO: migrate callers off this module */
12
+ export const FLAG = true;
13
+ //# sourceMappingURL=sample.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sample.js","sourceRoot":"","sources":["../../src/__fixtures__/sample.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,UAAU,YAAY;IAC1B,mCAAmC;IACnC,4BAA4B;IAC5B,OAAO,EAAE,CAAC;AACZ,CAAC;AAED,2CAA2C;AAC3C,MAAM,CAAC,MAAM,IAAI,GAAG,IAAI,CAAC"}
@@ -0,0 +1,9 @@
1
+ import type { AgeBucket, AuthorDebt, DebtItem, DebtKind, DebtStats, FileDebt, SearchEntry } from './types.js';
2
+ export declare function ageBucketFromDays(days: number | null | undefined): AgeBucket;
3
+ export declare function emptyKindCounts(): Record<DebtKind, number>;
4
+ export declare function emptyAgeCounts(): Record<AgeBucket, number>;
5
+ export declare function buildAuthors(items: DebtItem[]): AuthorDebt[];
6
+ export declare function buildFiles(items: DebtItem[]): FileDebt[];
7
+ export declare function buildSearchIndex(items: DebtItem[]): SearchEntry[];
8
+ export declare function buildStats(items: DebtItem[], scannedFiles: number, scanDurationMs: number, blameEnabled: boolean): DebtStats;
9
+ //# sourceMappingURL=aggregate.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.d.ts","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,UAAU,EACV,QAAQ,EACR,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,WAAW,EACZ,MAAM,YAAY,CAAC;AAEpB,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GAAG,SAAS,CAO5E;AAED,wBAAgB,eAAe,IAAI,MAAM,CAAC,QAAQ,EAAE,MAAM,CAAC,CAE1D;AAED,wBAAgB,cAAc,IAAI,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,CAS1D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,UAAU,EAAE,CA4C5D;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,QAAQ,EAAE,CA6BxD;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,QAAQ,EAAE,GAAG,WAAW,EAAE,CAcjE;AAED,wBAAgB,UAAU,CACxB,KAAK,EAAE,QAAQ,EAAE,EACjB,YAAY,EAAE,MAAM,EACpB,cAAc,EAAE,MAAM,EACtB,YAAY,EAAE,OAAO,GACpB,SAAS,CAkCX"}
@@ -0,0 +1,139 @@
1
+ export function ageBucketFromDays(days) {
2
+ if (days == null || Number.isNaN(days))
3
+ return 'unknown';
4
+ if (days < 30)
5
+ return 'fresh';
6
+ if (days < 90)
7
+ return 'recent';
8
+ if (days < 180)
9
+ return 'aging';
10
+ if (days < 365)
11
+ return 'stale';
12
+ return 'ancient';
13
+ }
14
+ export function emptyKindCounts() {
15
+ return { todo: 0, fixme: 0, deprecated: 0 };
16
+ }
17
+ export function emptyAgeCounts() {
18
+ return {
19
+ fresh: 0,
20
+ recent: 0,
21
+ aging: 0,
22
+ stale: 0,
23
+ ancient: 0,
24
+ unknown: 0,
25
+ };
26
+ }
27
+ export function buildAuthors(items) {
28
+ const map = new Map();
29
+ for (const item of items) {
30
+ const author = item.blame?.author ?? 'Unknown';
31
+ const email = item.blame?.authorEmail ?? '';
32
+ const key = `${author}|${email}`;
33
+ let entry = map.get(key);
34
+ if (!entry) {
35
+ entry = {
36
+ author,
37
+ authorEmail: email,
38
+ total: 0,
39
+ byKind: emptyKindCounts(),
40
+ oldestAgeDays: null,
41
+ averageAgeDays: null,
42
+ items: [],
43
+ };
44
+ map.set(key, entry);
45
+ }
46
+ entry.total++;
47
+ entry.byKind[item.kind]++;
48
+ entry.items.push(item.id);
49
+ const age = item.blame?.ageDays;
50
+ if (age != null) {
51
+ entry.oldestAgeDays =
52
+ entry.oldestAgeDays == null ? age : Math.max(entry.oldestAgeDays, age);
53
+ }
54
+ }
55
+ for (const entry of map.values()) {
56
+ const ages = entry.items
57
+ .map((id) => items.find((i) => i.id === id)?.blame?.ageDays)
58
+ .filter((d) => d != null);
59
+ entry.averageAgeDays =
60
+ ages.length === 0
61
+ ? null
62
+ : Math.round(ages.reduce((a, b) => a + b, 0) / ages.length);
63
+ }
64
+ return [...map.values()].sort((a, b) => b.total - a.total);
65
+ }
66
+ export function buildFiles(items) {
67
+ const map = new Map();
68
+ for (const item of items) {
69
+ let entry = map.get(item.filePath);
70
+ if (!entry) {
71
+ entry = {
72
+ path: item.filePath,
73
+ relativePath: item.relativePath,
74
+ total: 0,
75
+ byKind: emptyKindCounts(),
76
+ oldestAgeDays: null,
77
+ items: [],
78
+ };
79
+ map.set(item.filePath, entry);
80
+ }
81
+ entry.total++;
82
+ entry.byKind[item.kind]++;
83
+ entry.items.push(item.id);
84
+ const age = item.blame?.ageDays;
85
+ if (age != null) {
86
+ entry.oldestAgeDays =
87
+ entry.oldestAgeDays == null ? age : Math.max(entry.oldestAgeDays, age);
88
+ }
89
+ }
90
+ return [...map.values()].sort((a, b) => b.total - a.total);
91
+ }
92
+ export function buildSearchIndex(items) {
93
+ return items.map((item) => ({
94
+ id: item.id,
95
+ label: item.message,
96
+ kind: item.kind,
97
+ path: item.relativePath,
98
+ keywords: [
99
+ item.kind,
100
+ item.message,
101
+ item.relativePath,
102
+ item.blame?.author ?? '',
103
+ item.raw,
104
+ ].filter(Boolean),
105
+ }));
106
+ }
107
+ export function buildStats(items, scannedFiles, scanDurationMs, blameEnabled) {
108
+ const byKind = emptyKindCounts();
109
+ const byAge = emptyAgeCounts();
110
+ const authors = new Set();
111
+ const ages = [];
112
+ let blamed = 0;
113
+ for (const item of items) {
114
+ byKind[item.kind]++;
115
+ byAge[item.ageBucket]++;
116
+ if (item.blame) {
117
+ blamed++;
118
+ authors.add(`${item.blame.author}|${item.blame.authorEmail}`);
119
+ ages.push(item.blame.ageDays);
120
+ }
121
+ }
122
+ const fileSet = new Set(items.map((i) => i.filePath));
123
+ return {
124
+ totalItems: items.length,
125
+ totalFiles: fileSet.size,
126
+ scannedFiles,
127
+ byKind,
128
+ byAge,
129
+ authors: authors.size,
130
+ oldestAgeDays: ages.length ? Math.max(...ages) : null,
131
+ averageAgeDays: ages.length
132
+ ? Math.round(ages.reduce((a, b) => a + b, 0) / ages.length)
133
+ : null,
134
+ scanDurationMs,
135
+ blameEnabled,
136
+ blameCoverage: items.length === 0 ? 0 : blamed / items.length,
137
+ };
138
+ }
139
+ //# sourceMappingURL=aggregate.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"aggregate.js","sourceRoot":"","sources":["../src/aggregate.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { BlameInfo } from './types.js';
2
+ /**
3
+ * Blame specific lines in a file using a single `git blame --line-porcelain` pass.
4
+ * Returns a map of line number → blame info.
5
+ */
6
+ export declare function blameFileLines(root: string, filePath: string, lines: number[]): Promise<Map<number, BlameInfo>>;
7
+ //# sourceMappingURL=blame.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blame.d.ts","sourceRoot":"","sources":["../src/blame.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAS5C;;;GAGG;AACH,wBAAsB,cAAc,CAClC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,EAAE,GACd,OAAO,CAAC,GAAG,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC,CA8BjC"}
package/dist/blame.js ADDED
@@ -0,0 +1,86 @@
1
+ import { execFile } from 'node:child_process';
2
+ import { promisify } from 'node:util';
3
+ const execFileAsync = promisify(execFile);
4
+ /**
5
+ * Blame specific lines in a file using a single `git blame --line-porcelain` pass.
6
+ * Returns a map of line number → blame info.
7
+ */
8
+ export async function blameFileLines(root, filePath, lines) {
9
+ const result = new Map();
10
+ if (lines.length === 0)
11
+ return result;
12
+ const unique = [...new Set(lines)].sort((a, b) => a - b);
13
+ try {
14
+ // Blame the whole file once — cheaper than N -L calls for dense debt files
15
+ const { stdout } = await execFileAsync('git', ['blame', '--line-porcelain', '--', filePath], {
16
+ cwd: root,
17
+ maxBuffer: 20 * 1024 * 1024,
18
+ encoding: 'utf-8',
19
+ });
20
+ const parsed = parsePorcelain(stdout);
21
+ const wanted = new Set(unique);
22
+ for (const entry of parsed) {
23
+ if (wanted.has(entry.line)) {
24
+ result.set(entry.line, entry.info);
25
+ }
26
+ }
27
+ }
28
+ catch {
29
+ // Not a git repo, untracked file, or git unavailable — leave empty
30
+ }
31
+ return result;
32
+ }
33
+ function parsePorcelain(stdout) {
34
+ const entries = [];
35
+ const blocks = stdout.split(/\n(?=[0-9a-f]{40} )/i);
36
+ for (const block of blocks) {
37
+ if (!block.trim())
38
+ continue;
39
+ const lines = block.split('\n');
40
+ const header = lines[0]?.match(/^([0-9a-f]{40})\s+(\d+)\s+(\d+)(?:\s+(\d+))?/i);
41
+ if (!header)
42
+ continue;
43
+ const commitHash = header[1];
44
+ const resultLine = parseInt(header[3], 10);
45
+ let author = 'Unknown';
46
+ let authorEmail = '';
47
+ let authorTime = 0;
48
+ let summary = '';
49
+ for (let i = 1; i < lines.length; i++) {
50
+ const line = lines[i];
51
+ if (line.startsWith('author '))
52
+ author = line.slice(7);
53
+ else if (line.startsWith('author-mail ')) {
54
+ authorEmail = line.slice(12).replace(/^<|>$/g, '');
55
+ }
56
+ else if (line.startsWith('author-time ')) {
57
+ authorTime = parseInt(line.slice(12), 10) * 1000;
58
+ }
59
+ else if (line.startsWith('summary ')) {
60
+ summary = line.slice(8);
61
+ }
62
+ else if (line.startsWith('\t')) {
63
+ break;
64
+ }
65
+ }
66
+ const committedAt = authorTime
67
+ ? new Date(authorTime).toISOString()
68
+ : new Date(0).toISOString();
69
+ const ageDays = authorTime
70
+ ? Math.max(0, Math.floor((Date.now() - authorTime) / (1000 * 60 * 60 * 24)))
71
+ : 0;
72
+ entries.push({
73
+ line: resultLine,
74
+ info: {
75
+ author,
76
+ authorEmail,
77
+ committedAt,
78
+ ageDays,
79
+ commitHash: commitHash.slice(0, 12),
80
+ summary: summary || undefined,
81
+ },
82
+ });
83
+ }
84
+ return entries;
85
+ }
86
+ //# sourceMappingURL=blame.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"blame.js","sourceRoot":"","sources":["../src/blame.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,11 @@
1
+ import type { DebtKind } from './types.js';
2
+ export interface RawMatch {
3
+ kind: DebtKind;
4
+ message: string;
5
+ raw: string;
6
+ line: number;
7
+ column: number;
8
+ context?: string;
9
+ }
10
+ export declare function parseComments(content: string, filePath?: string): RawMatch[];
11
+ //# sourceMappingURL=comment-parser.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../src/comment-parser.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAE3C,MAAM,WAAW,QAAQ;IACvB,IAAI,EAAE,QAAQ,CAAC;IACf,OAAO,EAAE,MAAM,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAmCD,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAK,GAAG,QAAQ,EAAE,CAkExE"}
@@ -0,0 +1,114 @@
1
+ const LINE_PATTERNS = [
2
+ { kind: 'todo', hasPrefix: true, regex: /^(\s*\/\/\/?!?\s*)TODO\b\s*:?\s*(.*)$/i },
3
+ { kind: 'fixme', hasPrefix: true, regex: /^(\s*\/\/\/?!?\s*)FIXME\b\s*:?\s*(.*)$/i },
4
+ { kind: 'todo', hasPrefix: true, regex: /^(\s*#\s*)TODO\b\s*:?\s*(.*)$/i },
5
+ { kind: 'fixme', hasPrefix: true, regex: /^(\s*#\s*)FIXME\b\s*:?\s*(.*)$/i },
6
+ { kind: 'todo', hasPrefix: true, regex: /^(\s*\*\s*)TODO\b\s*:?\s*(.*)$/i },
7
+ { kind: 'fixme', hasPrefix: true, regex: /^(\s*\*\s*)FIXME\b\s*:?\s*(.*)$/i },
8
+ { kind: 'deprecated', hasPrefix: true, regex: /^(\s*\*\s*)@deprecated\b\s*:?\s*(.*)$/i },
9
+ { kind: 'deprecated', hasPrefix: true, regex: /^(\s*\/\/\/?!?\s*)@deprecated\b\s*:?\s*(.*)$/i },
10
+ { kind: 'deprecated', hasPrefix: true, regex: /^(\s*#\s*)@deprecated\b\s*:?\s*(.*)$/i },
11
+ ];
12
+ const MARKDOWN_LINE_PATTERNS = [
13
+ { kind: 'todo', hasPrefix: true, regex: /^(\s*[-*]\s+(?:\[[ xX]\]\s*)?)TODO\b\s*:?\s*(.*)$/i },
14
+ { kind: 'fixme', hasPrefix: true, regex: /^(\s*[-*]\s+(?:\[[ xX]\]\s*)?)FIXME\b\s*:?\s*(.*)$/i },
15
+ ];
16
+ const INLINE_PATTERNS = [
17
+ { kind: 'todo', regex: /<!--\s*TODO\b\s*:?\s*(.*?)-->/gi },
18
+ { kind: 'fixme', regex: /<!--\s*FIXME\b\s*:?\s*(.*?)-->/gi },
19
+ { kind: 'todo', regex: /\/\*+\s*TODO\b\s*:?\s*(.*?)(?:\*\/|$)/gi },
20
+ { kind: 'fixme', regex: /\/\*+\s*FIXME\b\s*:?\s*(.*?)(?:\*\/|$)/gi },
21
+ { kind: 'deprecated', regex: /\/\*+\s*@deprecated\b\s*:?\s*(.*?)(?:\*\/|$)/gi },
22
+ ];
23
+ export function parseComments(content, filePath = '') {
24
+ const lines = content.split(/\r?\n/);
25
+ const matches = [];
26
+ const seen = new Set();
27
+ const isMarkdown = /\.(md|mdx)$/i.test(filePath);
28
+ const linePatterns = isMarkdown ? MARKDOWN_LINE_PATTERNS : LINE_PATTERNS;
29
+ const inlinePatterns = isMarkdown
30
+ ? INLINE_PATTERNS.filter((p) => p.regex.source.includes('<!--'))
31
+ : INLINE_PATTERNS;
32
+ for (let i = 0; i < lines.length; i++) {
33
+ const lineText = lines[i];
34
+ for (const pattern of linePatterns) {
35
+ const match = pattern.regex.exec(lineText);
36
+ // Reset sticky state for non-/g patterns reused across lines
37
+ pattern.regex.lastIndex = 0;
38
+ if (!match)
39
+ continue;
40
+ const message = cleanMessage(pattern.hasPrefix ? (match[2] ?? '') : (match[1] ?? ''));
41
+ const raw = match[0].trim();
42
+ const line = i + 1;
43
+ const column = (match.index ?? 0) + 1;
44
+ const key = `${pattern.kind}:${line}:${column}:${raw.slice(0, 80)}`;
45
+ if (seen.has(key))
46
+ continue;
47
+ seen.add(key);
48
+ matches.push({
49
+ kind: pattern.kind,
50
+ message: message || defaultMessage(pattern.kind),
51
+ raw,
52
+ line,
53
+ column,
54
+ context: buildContext(lines, line),
55
+ });
56
+ }
57
+ }
58
+ for (const pattern of inlinePatterns) {
59
+ pattern.regex.lastIndex = 0;
60
+ let match;
61
+ while ((match = pattern.regex.exec(content)) !== null) {
62
+ const index = match.index;
63
+ const line = offsetToLine(content, index);
64
+ const column = index - lineStartOffset(content, index) + 1;
65
+ const message = cleanMessage(match[1] ?? '');
66
+ const raw = match[0].trim();
67
+ const key = `${pattern.kind}:${line}:${column}:${raw.slice(0, 80)}`;
68
+ if (seen.has(key))
69
+ continue;
70
+ seen.add(key);
71
+ matches.push({
72
+ kind: pattern.kind,
73
+ message: message || defaultMessage(pattern.kind),
74
+ raw,
75
+ line,
76
+ column,
77
+ context: buildContext(lines, line),
78
+ });
79
+ }
80
+ }
81
+ matches.sort((a, b) => a.line - b.line || a.column - b.column);
82
+ return matches;
83
+ }
84
+ function cleanMessage(text) {
85
+ return text
86
+ .replace(/\*+\/?\s*$/, '')
87
+ .replace(/-->$/, '')
88
+ .replace(/\s+/g, ' ')
89
+ .trim();
90
+ }
91
+ function defaultMessage(kind) {
92
+ if (kind === 'deprecated')
93
+ return 'Deprecated';
94
+ return '(no message)';
95
+ }
96
+ function offsetToLine(content, offset) {
97
+ let line = 1;
98
+ for (let i = 0; i < offset && i < content.length; i++) {
99
+ if (content[i] === '\n')
100
+ line++;
101
+ }
102
+ return line;
103
+ }
104
+ function lineStartOffset(content, offset) {
105
+ const before = content.lastIndexOf('\n', offset - 1);
106
+ return before === -1 ? 0 : before + 1;
107
+ }
108
+ function buildContext(lines, line) {
109
+ const idx = line - 1;
110
+ const start = Math.max(0, idx - 1);
111
+ const end = Math.min(lines.length, idx + 2);
112
+ return lines.slice(start, end).join('\n');
113
+ }
114
+ //# sourceMappingURL=comment-parser.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"comment-parser.js","sourceRoot":"","sources":["../src/comment-parser.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ import type { ProjectConfig } from './types.js';
2
+ declare const SOURCE_EXTENSIONS: Set<string>;
3
+ declare const IGNORE_DIRS: Set<string>;
4
+ export declare function discoverProject(root: string): ProjectConfig;
5
+ export declare function collectSourceFiles(root: string): string[];
6
+ export { SOURCE_EXTENSIONS, IGNORE_DIRS };
7
+ //# sourceMappingURL=discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.d.ts","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD,QAAA,MAAM,iBAAiB,aAQrB,CAAC;AAEH,QAAA,MAAM,WAAW,aA+Bf,CAAC;AAEH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,CAY3D;AAED,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,EAAE,CAIzD;AA0DD,OAAO,EAAE,iBAAiB,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,119 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { execFileSync } from 'node:child_process';
4
+ const SOURCE_EXTENSIONS = new Set([
5
+ '.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
6
+ '.py', '.go', '.rs', '.java', '.kt', '.kts',
7
+ '.swift', '.rb', '.php', '.cs', '.scala',
8
+ '.vue', '.svelte', '.css', '.scss', '.sass', '.less',
9
+ '.html', '.htm',
10
+ '.sh', '.bash', '.zsh', '.yml', '.yaml',
11
+ '.sql', '.graphql', '.gql',
12
+ ]);
13
+ const IGNORE_DIRS = new Set([
14
+ 'node_modules',
15
+ '.git',
16
+ 'dist',
17
+ 'build',
18
+ 'out',
19
+ '.expo',
20
+ 'android',
21
+ 'ios',
22
+ 'coverage',
23
+ '.next',
24
+ '.nuxt',
25
+ '.output',
26
+ '__tests__',
27
+ '__mocks__',
28
+ '.venv',
29
+ 'venv',
30
+ '.idea',
31
+ '.turbo',
32
+ '.cache',
33
+ 'vendor',
34
+ 'Pods',
35
+ '.gradle',
36
+ 'DerivedData',
37
+ '.svelte-kit',
38
+ 'target',
39
+ 'bin',
40
+ 'obj',
41
+ '.parcel-cache',
42
+ '.yarn',
43
+ 'storybook-static',
44
+ ]);
45
+ export function discoverProject(root) {
46
+ const resolved = path.resolve(root);
47
+ const pkgPath = findNearestFile(resolved, 'package.json');
48
+ const pkg = pkgPath ? readJson(pkgPath) : null;
49
+ const name = pkg?.name ?? path.basename(resolved);
50
+ const isGitRepo = isInsideGitRepo(resolved);
51
+ return {
52
+ root: resolved,
53
+ name,
54
+ isGitRepo,
55
+ };
56
+ }
57
+ export function collectSourceFiles(root) {
58
+ const files = [];
59
+ walk(root, root, files);
60
+ return files;
61
+ }
62
+ function walk(root, dir, out) {
63
+ let entries;
64
+ try {
65
+ entries = fs.readdirSync(dir, { withFileTypes: true });
66
+ }
67
+ catch {
68
+ return;
69
+ }
70
+ for (const entry of entries) {
71
+ if (entry.name.startsWith('.'))
72
+ continue;
73
+ const full = path.join(dir, entry.name);
74
+ if (entry.isDirectory()) {
75
+ if (IGNORE_DIRS.has(entry.name))
76
+ continue;
77
+ walk(root, full, out);
78
+ continue;
79
+ }
80
+ if (!entry.isFile())
81
+ continue;
82
+ const ext = path.extname(entry.name).toLowerCase();
83
+ if (!SOURCE_EXTENSIONS.has(ext))
84
+ continue;
85
+ out.push(full);
86
+ }
87
+ }
88
+ function findNearestFile(root, filename) {
89
+ let current = root;
90
+ while (current !== path.dirname(current)) {
91
+ const candidate = path.join(current, filename);
92
+ if (fs.existsSync(candidate))
93
+ return candidate;
94
+ current = path.dirname(current);
95
+ }
96
+ return null;
97
+ }
98
+ function readJson(filePath) {
99
+ try {
100
+ return JSON.parse(fs.readFileSync(filePath, 'utf-8'));
101
+ }
102
+ catch {
103
+ return null;
104
+ }
105
+ }
106
+ function isInsideGitRepo(root) {
107
+ try {
108
+ execFileSync('git', ['rev-parse', '--is-inside-work-tree'], {
109
+ cwd: root,
110
+ stdio: ['ignore', 'pipe', 'ignore'],
111
+ });
112
+ return true;
113
+ }
114
+ catch {
115
+ return false;
116
+ }
117
+ }
118
+ export { SOURCE_EXTENSIONS, IGNORE_DIRS };
119
+ //# sourceMappingURL=discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"discovery.js","sourceRoot":"","sources":["../src/discovery.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,7 @@
1
+ export type { DebtKind, AgeBucket, BlameInfo, DebtItem, AuthorDebt, FileDebt, DebtStats, ProjectConfig, SearchEntry, DebtReport, ScanOptions, ScanProgress, } from './types.js';
2
+ export { discoverProject, collectSourceFiles } from './discovery.js';
3
+ export { parseComments } from './comment-parser.js';
4
+ export { blameFileLines } from './blame.js';
5
+ export { ageBucketFromDays, buildAuthors, buildFiles, buildSearchIndex, buildStats, emptyKindCounts, emptyAgeCounts, } from './aggregate.js';
6
+ export { scanProject, getItemDetail, getFileDebt, getAuthorDebt, type ProgressCallback, } from './scanner.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,QAAQ,EACR,SAAS,EACT,SAAS,EACT,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,SAAS,EACT,aAAa,EACb,WAAW,EACX,UAAU,EACV,WAAW,EACX,YAAY,GACb,MAAM,YAAY,CAAC;AAEpB,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,EACb,KAAK,gBAAgB,GACtB,MAAM,cAAc,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export { discoverProject, collectSourceFiles } from './discovery.js';
2
+ export { parseComments } from './comment-parser.js';
3
+ export { blameFileLines } from './blame.js';
4
+ export { ageBucketFromDays, buildAuthors, buildFiles, buildSearchIndex, buildStats, emptyKindCounts, emptyAgeCounts, } from './aggregate.js';
5
+ export { scanProject, getItemDetail, getFileDebt, getAuthorDebt, } from './scanner.js';
6
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,eAAe,EAAE,kBAAkB,EAAE,MAAM,gBAAgB,CAAC;AACrE,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,OAAO,EACL,iBAAiB,EACjB,YAAY,EACZ,UAAU,EACV,gBAAgB,EAChB,UAAU,EACV,eAAe,EACf,cAAc,GACf,MAAM,gBAAgB,CAAC;AACxB,OAAO,EACL,WAAW,EACX,aAAa,EACb,WAAW,EACX,aAAa,GAEd,MAAM,cAAc,CAAC"}
@@ -0,0 +1,13 @@
1
+ import type { DebtItem, DebtReport, ScanOptions, ScanProgress } from './types.js';
2
+ export type ProgressCallback = (progress: ScanProgress) => void;
3
+ export declare function scanProject(options: ScanOptions, onProgress?: ProgressCallback): Promise<DebtReport>;
4
+ export declare function getItemDetail(report: DebtReport, itemId: string): DebtItem | null;
5
+ export declare function getFileDebt(report: DebtReport, filePath: string): {
6
+ file: DebtReport['files'][number];
7
+ items: DebtItem[];
8
+ } | null;
9
+ export declare function getAuthorDebt(report: DebtReport, author: string): {
10
+ author: DebtReport['authors'][number];
11
+ items: DebtItem[];
12
+ } | null;
13
+ //# sourceMappingURL=scanner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.d.ts","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"AAaA,OAAO,KAAK,EACV,QAAQ,EACR,UAAU,EACV,WAAW,EACX,YAAY,EACb,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,gBAAgB,GAAG,CAAC,QAAQ,EAAE,YAAY,KAAK,IAAI,CAAC;AAEhE,wBAAsB,WAAW,CAC/B,OAAO,EAAE,WAAW,EACpB,UAAU,CAAC,EAAE,gBAAgB,GAC5B,OAAO,CAAC,UAAU,CAAC,CA+KrB;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb,QAAQ,GAAG,IAAI,CAEjB;AAED,wBAAgB,WAAW,CACzB,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,GACf;IAAE,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,IAAI,CAYjE;AAED,wBAAgB,aAAa,CAC3B,MAAM,EAAE,UAAU,EAClB,MAAM,EAAE,MAAM,GACb;IAAE,MAAM,EAAE,UAAU,CAAC,SAAS,CAAC,CAAC,MAAM,CAAC,CAAC;IAAC,KAAK,EAAE,QAAQ,EAAE,CAAA;CAAE,GAAG,IAAI,CAQrE"}
@@ -0,0 +1,186 @@
1
+ import fs from 'node:fs';
2
+ import fsp from 'node:fs/promises';
3
+ import path from 'node:path';
4
+ import { discoverProject, collectSourceFiles } from './discovery.js';
5
+ import { parseComments } from './comment-parser.js';
6
+ import { blameFileLines } from './blame.js';
7
+ import { ageBucketFromDays, buildAuthors, buildFiles, buildSearchIndex, buildStats, } from './aggregate.js';
8
+ export async function scanProject(options, onProgress) {
9
+ const started = Date.now();
10
+ const blameEnabled = options.blame !== false;
11
+ onProgress?.({ phase: 'discover', message: 'Discovering project...' });
12
+ const config = discoverProject(options.root);
13
+ const shouldBlame = blameEnabled && config.isGitRepo;
14
+ let files;
15
+ if (options.incremental && options.changedFiles && options.cache) {
16
+ files = options.changedFiles.filter((f) => fs.existsSync(f));
17
+ for (const changed of options.changedFiles) {
18
+ if (!files.includes(changed)) {
19
+ options.cache.delete(changed);
20
+ }
21
+ }
22
+ }
23
+ else {
24
+ files = collectSourceFiles(config.root);
25
+ options.cache?.clear();
26
+ }
27
+ onProgress?.({
28
+ phase: 'scan',
29
+ message: `Scanning ${files.length} files...`,
30
+ current: 0,
31
+ total: files.length,
32
+ });
33
+ const fileItems = new Map();
34
+ let scanned = 0;
35
+ for (const filePath of files) {
36
+ scanned++;
37
+ if (scanned % 50 === 0 || scanned === files.length) {
38
+ onProgress?.({
39
+ phase: 'scan',
40
+ message: `Scanning files (${scanned}/${files.length})...`,
41
+ current: scanned,
42
+ total: files.length,
43
+ });
44
+ }
45
+ try {
46
+ const content = await fsp.readFile(filePath, 'utf-8');
47
+ // Skip huge / binary-looking files
48
+ if (content.length > 1_500_000 || content.includes('\0'))
49
+ continue;
50
+ const relativePath = path.relative(config.root, filePath);
51
+ const matches = parseComments(content, relativePath);
52
+ if (matches.length === 0) {
53
+ fileItems.set(filePath, []);
54
+ continue;
55
+ }
56
+ const items = matches.map((m, idx) => ({
57
+ id: `debt:${relativePath}:${m.line}:${m.kind}:${idx}`,
58
+ kind: m.kind,
59
+ message: m.message,
60
+ raw: m.raw,
61
+ filePath,
62
+ relativePath,
63
+ line: m.line,
64
+ column: m.column,
65
+ context: m.context,
66
+ ageBucket: 'unknown',
67
+ }));
68
+ fileItems.set(filePath, items);
69
+ }
70
+ catch {
71
+ // Unreadable file — skip
72
+ }
73
+ }
74
+ // Merge with cache for incremental scans
75
+ if (options.incremental && options.cache) {
76
+ for (const [filePath, items] of fileItems) {
77
+ options.cache.set(filePath, items);
78
+ }
79
+ }
80
+ else if (options.cache) {
81
+ for (const [filePath, items] of fileItems) {
82
+ options.cache.set(filePath, items);
83
+ }
84
+ }
85
+ const cacheSource = options.cache ?? fileItems;
86
+ const allBeforeBlame = [];
87
+ for (const items of cacheSource.values()) {
88
+ allBeforeBlame.push(...items);
89
+ }
90
+ // Group by file for blame
91
+ if (shouldBlame) {
92
+ const byFile = new Map();
93
+ for (const item of allBeforeBlame) {
94
+ const list = byFile.get(item.filePath) ?? [];
95
+ list.push(item);
96
+ byFile.set(item.filePath, list);
97
+ }
98
+ const filePaths = [...byFile.keys()];
99
+ onProgress?.({
100
+ phase: 'blame',
101
+ message: `Running git blame on ${filePaths.length} files...`,
102
+ current: 0,
103
+ total: filePaths.length,
104
+ });
105
+ let blamed = 0;
106
+ // Concurrency limit to avoid spawning too many git processes
107
+ const concurrency = 8;
108
+ for (let i = 0; i < filePaths.length; i += concurrency) {
109
+ const batch = filePaths.slice(i, i + concurrency);
110
+ await Promise.all(batch.map(async (filePath) => {
111
+ const items = byFile.get(filePath);
112
+ const lines = items.map((it) => it.line);
113
+ const blameMap = await blameFileLines(config.root, filePath, lines);
114
+ for (const item of items) {
115
+ const blame = blameMap.get(item.line);
116
+ if (blame) {
117
+ item.blame = blame;
118
+ item.ageBucket = ageBucketFromDays(blame.ageDays);
119
+ }
120
+ }
121
+ }));
122
+ blamed += batch.length;
123
+ onProgress?.({
124
+ phase: 'blame',
125
+ message: `Git blame (${blamed}/${filePaths.length})...`,
126
+ current: blamed,
127
+ total: filePaths.length,
128
+ });
129
+ }
130
+ }
131
+ onProgress?.({ phase: 'aggregate', message: 'Building report...' });
132
+ const items = allBeforeBlame.sort((a, b) => {
133
+ const ageA = a.blame?.ageDays ?? -1;
134
+ const ageB = b.blame?.ageDays ?? -1;
135
+ if (ageA !== ageB)
136
+ return ageB - ageA;
137
+ return a.relativePath.localeCompare(b.relativePath) || a.line - b.line;
138
+ });
139
+ // Re-sync cache with blamed items
140
+ if (options.cache) {
141
+ const regrouped = new Map();
142
+ for (const item of items) {
143
+ const list = regrouped.get(item.filePath) ?? [];
144
+ list.push(item);
145
+ regrouped.set(item.filePath, list);
146
+ }
147
+ for (const [filePath, list] of regrouped) {
148
+ options.cache.set(filePath, list);
149
+ }
150
+ }
151
+ const scannedFiles = options.incremental && options.cache
152
+ ? options.cache.size
153
+ : files.length;
154
+ const report = {
155
+ config,
156
+ items,
157
+ authors: buildAuthors(items),
158
+ files: buildFiles(items),
159
+ searchIndex: buildSearchIndex(items),
160
+ stats: buildStats(items, scannedFiles, Date.now() - started, shouldBlame),
161
+ scannedAt: new Date().toISOString(),
162
+ };
163
+ onProgress?.({ phase: 'done', message: `Found ${items.length} debt items` });
164
+ return report;
165
+ }
166
+ export function getItemDetail(report, itemId) {
167
+ return report.items.find((i) => i.id === itemId) ?? null;
168
+ }
169
+ export function getFileDebt(report, filePath) {
170
+ const normalized = filePath.replace(/^file:/, '');
171
+ const file = report.files.find((f) => f.path === normalized ||
172
+ f.relativePath === normalized ||
173
+ f.path.endsWith(normalized)) ?? null;
174
+ if (!file)
175
+ return null;
176
+ const items = report.items.filter((i) => file.items.includes(i.id));
177
+ return { file, items };
178
+ }
179
+ export function getAuthorDebt(report, author) {
180
+ const entry = report.authors.find((a) => a.author === author || a.authorEmail === author) ?? null;
181
+ if (!entry)
182
+ return null;
183
+ const items = report.items.filter((i) => entry.items.includes(i.id));
184
+ return { author: entry, items };
185
+ }
186
+ //# sourceMappingURL=scanner.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"scanner.js","sourceRoot":"","sources":["../src/scanner.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,89 @@
1
+ export type DebtKind = 'todo' | 'fixme' | 'deprecated';
2
+ export type AgeBucket = 'fresh' | 'recent' | 'aging' | 'stale' | 'ancient' | 'unknown';
3
+ export interface BlameInfo {
4
+ author: string;
5
+ authorEmail: string;
6
+ committedAt: string;
7
+ ageDays: number;
8
+ commitHash: string;
9
+ summary?: string;
10
+ }
11
+ export interface DebtItem {
12
+ id: string;
13
+ kind: DebtKind;
14
+ message: string;
15
+ raw: string;
16
+ filePath: string;
17
+ relativePath: string;
18
+ line: number;
19
+ column: number;
20
+ context?: string;
21
+ blame?: BlameInfo;
22
+ ageBucket: AgeBucket;
23
+ }
24
+ export interface AuthorDebt {
25
+ author: string;
26
+ authorEmail: string;
27
+ total: number;
28
+ byKind: Record<DebtKind, number>;
29
+ oldestAgeDays: number | null;
30
+ averageAgeDays: number | null;
31
+ items: string[];
32
+ }
33
+ export interface FileDebt {
34
+ path: string;
35
+ relativePath: string;
36
+ total: number;
37
+ byKind: Record<DebtKind, number>;
38
+ oldestAgeDays: number | null;
39
+ items: string[];
40
+ }
41
+ export interface DebtStats {
42
+ totalItems: number;
43
+ totalFiles: number;
44
+ scannedFiles: number;
45
+ byKind: Record<DebtKind, number>;
46
+ byAge: Record<AgeBucket, number>;
47
+ authors: number;
48
+ oldestAgeDays: number | null;
49
+ averageAgeDays: number | null;
50
+ scanDurationMs: number;
51
+ blameEnabled: boolean;
52
+ blameCoverage: number;
53
+ }
54
+ export interface ProjectConfig {
55
+ root: string;
56
+ name: string;
57
+ isGitRepo: boolean;
58
+ }
59
+ export interface SearchEntry {
60
+ id: string;
61
+ label: string;
62
+ kind: DebtKind;
63
+ path: string;
64
+ keywords: string[];
65
+ }
66
+ export interface DebtReport {
67
+ config: ProjectConfig;
68
+ items: DebtItem[];
69
+ authors: AuthorDebt[];
70
+ files: FileDebt[];
71
+ searchIndex: SearchEntry[];
72
+ stats: DebtStats;
73
+ scannedAt: string;
74
+ }
75
+ export interface ScanOptions {
76
+ root: string;
77
+ blame?: boolean;
78
+ incremental?: boolean;
79
+ changedFiles?: string[];
80
+ /** Cache of previous items keyed by absolute file path */
81
+ cache?: Map<string, DebtItem[]>;
82
+ }
83
+ export interface ScanProgress {
84
+ phase: 'discover' | 'scan' | 'blame' | 'aggregate' | 'done';
85
+ message: string;
86
+ current?: number;
87
+ total?: number;
88
+ }
89
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
package/package.json ADDED
@@ -0,0 +1,28 @@
1
+ {
2
+ "name": "@tech-debt/core",
3
+ "version": "0.1.0",
4
+ "description": "Comment scanner and technical debt aggregation engine",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js"
12
+ }
13
+ },
14
+ "files": ["dist", "README.md"],
15
+ "scripts": {
16
+ "build": "tsc -p tsconfig.json",
17
+ "dev": "tsc -p tsconfig.json --watch",
18
+ "prepublishOnly": "npm run build"
19
+ },
20
+ "devDependencies": {
21
+ "@types/node": "^22.10.2",
22
+ "typescript": "^5.7.2"
23
+ },
24
+ "license": "MIT",
25
+ "engines": {
26
+ "node": ">=18"
27
+ }
28
+ }