@snevins/repo-mapper 1.0.3
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/LICENSE +21 -0
- package/README.md +103 -0
- package/dist/cache.d.ts +21 -0
- package/dist/cache.js +123 -0
- package/dist/cli.d.ts +6 -0
- package/dist/cli.js +65 -0
- package/dist/files.d.ts +20 -0
- package/dist/files.js +206 -0
- package/dist/graph.d.ts +6 -0
- package/dist/graph.js +77 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +130 -0
- package/dist/languages.d.ts +40 -0
- package/dist/languages.js +609 -0
- package/dist/output.d.ts +19 -0
- package/dist/output.js +135 -0
- package/dist/pagerank.d.ts +6 -0
- package/dist/pagerank.js +155 -0
- package/dist/parser.d.ts +31 -0
- package/dist/parser.js +344 -0
- package/dist/ranking.d.ts +13 -0
- package/dist/ranking.js +55 -0
- package/dist/tokens.d.ts +10 -0
- package/dist/tokens.js +23 -0
- package/dist/types.d.ts +113 -0
- package/dist/types.js +1 -0
- package/package.json +72 -0
package/dist/ranking.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build personalization vector for focus files.
|
|
3
|
+
* Each focus file gets weight 1.0.
|
|
4
|
+
*/
|
|
5
|
+
export function buildPersonalization(focusFiles) {
|
|
6
|
+
const result = new Map();
|
|
7
|
+
for (const file of focusFiles) {
|
|
8
|
+
result.set(file, 1.0);
|
|
9
|
+
}
|
|
10
|
+
return result;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* Rank definitions by propagating PageRank through symbol edges.
|
|
14
|
+
* Focus file definitions are excluded from output.
|
|
15
|
+
*
|
|
16
|
+
* Formula: def_rank[definer:ident] += PR(referencer) * edge_weight / out_weight(referencer)
|
|
17
|
+
*/
|
|
18
|
+
export function rankDefinitions(graph, fileRanks, focusFiles) {
|
|
19
|
+
const focusSet = focusFiles ?? new Set();
|
|
20
|
+
const accumulator = new Map();
|
|
21
|
+
for (const [from, toMap] of graph.symbolEdges) {
|
|
22
|
+
const outWeight = graph.outWeights.get(from);
|
|
23
|
+
if (outWeight === undefined || outWeight === 0) {
|
|
24
|
+
continue;
|
|
25
|
+
}
|
|
26
|
+
const pr = fileRanks.get(from) ?? 0;
|
|
27
|
+
for (const [to, symbolMap] of toMap) {
|
|
28
|
+
if (focusSet.has(to)) {
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
for (const [symbol, count] of symbolMap) {
|
|
32
|
+
const key = `${to}\0${symbol}`;
|
|
33
|
+
const contribution = (pr * count) / outWeight;
|
|
34
|
+
accumulator.set(key, (accumulator.get(key) ?? 0) + contribution);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
const result = [];
|
|
39
|
+
for (const [key, rank] of accumulator) {
|
|
40
|
+
const sepIdx = key.indexOf("\0");
|
|
41
|
+
const file = key.slice(0, sepIdx);
|
|
42
|
+
const ident = key.slice(sepIdx + 1);
|
|
43
|
+
result.push({ file, ident, rank });
|
|
44
|
+
}
|
|
45
|
+
result.sort((a, b) => {
|
|
46
|
+
if (b.rank !== a.rank) {
|
|
47
|
+
return b.rank - a.rank;
|
|
48
|
+
}
|
|
49
|
+
if (a.file !== b.file) {
|
|
50
|
+
return a.file.localeCompare(b.file);
|
|
51
|
+
}
|
|
52
|
+
return a.ident.localeCompare(b.ident);
|
|
53
|
+
});
|
|
54
|
+
return result;
|
|
55
|
+
}
|
package/dist/tokens.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Count special characters (non-alphanumeric, non-whitespace).
|
|
3
|
+
* Used for token estimation adjustment.
|
|
4
|
+
*/
|
|
5
|
+
export declare function countSpecialChars(text: string): number;
|
|
6
|
+
/**
|
|
7
|
+
* Estimate token count using heuristic from spec §8.1:
|
|
8
|
+
* tokens ≈ (character_count / 4) + (special_char_count × 0.3)
|
|
9
|
+
*/
|
|
10
|
+
export declare function estimateTokens(text: string): number;
|
package/dist/tokens.js
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const ALPHANUMERIC_OR_WHITESPACE = /[a-zA-Z0-9\s]/;
|
|
2
|
+
/**
|
|
3
|
+
* Count special characters (non-alphanumeric, non-whitespace).
|
|
4
|
+
* Used for token estimation adjustment.
|
|
5
|
+
*/
|
|
6
|
+
export function countSpecialChars(text) {
|
|
7
|
+
let count = 0;
|
|
8
|
+
for (const char of text) {
|
|
9
|
+
if (!ALPHANUMERIC_OR_WHITESPACE.test(char)) {
|
|
10
|
+
count++;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
return count;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Estimate token count using heuristic from spec §8.1:
|
|
17
|
+
* tokens ≈ (character_count / 4) + (special_char_count × 0.3)
|
|
18
|
+
*/
|
|
19
|
+
export function estimateTokens(text) {
|
|
20
|
+
const charCount = text.length;
|
|
21
|
+
const specialCount = countSpecialChars(text);
|
|
22
|
+
return Math.floor(charCount / 4 + specialCount * 0.3);
|
|
23
|
+
}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A parsed symbol occurrence (definition or reference) in source code.
|
|
3
|
+
*/
|
|
4
|
+
export interface Tag {
|
|
5
|
+
readonly relPath: string;
|
|
6
|
+
readonly absPath: string;
|
|
7
|
+
readonly line: number;
|
|
8
|
+
readonly name: string;
|
|
9
|
+
readonly kind: "def" | "ref";
|
|
10
|
+
readonly signature?: string;
|
|
11
|
+
}
|
|
12
|
+
/**
|
|
13
|
+
* CLI options parsed from command line arguments.
|
|
14
|
+
*/
|
|
15
|
+
export interface CliOptions {
|
|
16
|
+
readonly tokens: number;
|
|
17
|
+
readonly focus: readonly string[];
|
|
18
|
+
readonly output: string | undefined;
|
|
19
|
+
readonly refresh: boolean;
|
|
20
|
+
readonly verbose: boolean;
|
|
21
|
+
readonly ignore: readonly string[];
|
|
22
|
+
readonly noIgnore: boolean;
|
|
23
|
+
readonly maxFiles: number;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Result of parsing CLI arguments.
|
|
27
|
+
*/
|
|
28
|
+
export interface ParsedArgs {
|
|
29
|
+
readonly paths: readonly string[];
|
|
30
|
+
readonly options: CliOptions;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Options for file discovery.
|
|
34
|
+
*/
|
|
35
|
+
export interface FileDiscoveryOptions {
|
|
36
|
+
readonly rootDir: string;
|
|
37
|
+
readonly maxDepth?: number;
|
|
38
|
+
readonly extensions?: ReadonlySet<string>;
|
|
39
|
+
readonly ignoredDirs?: ReadonlySet<string>;
|
|
40
|
+
readonly ignoredPatterns?: readonly string[];
|
|
41
|
+
readonly respectGitignore?: boolean;
|
|
42
|
+
readonly includeHidden?: boolean;
|
|
43
|
+
readonly maxFiles?: number;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Result of file discovery.
|
|
47
|
+
*/
|
|
48
|
+
export interface FileDiscoveryResult {
|
|
49
|
+
readonly files: readonly string[];
|
|
50
|
+
readonly totalDiscovered: number;
|
|
51
|
+
readonly wasLimited: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Options for PageRank computation.
|
|
55
|
+
*/
|
|
56
|
+
export interface PageRankOptions {
|
|
57
|
+
/** Damping factor (default: 0.85) */
|
|
58
|
+
readonly dampingFactor?: number;
|
|
59
|
+
/** Convergence threshold for score changes (default: 1e-6) */
|
|
60
|
+
readonly convergenceThreshold?: number;
|
|
61
|
+
/** Maximum iterations before stopping (default: 100) */
|
|
62
|
+
readonly maxIterations?: number;
|
|
63
|
+
/** Optional personalization vector to bias scores toward specific files */
|
|
64
|
+
readonly personalization?: ReadonlyMap<string, number>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* File reference graph for ranking.
|
|
68
|
+
* Nodes are files (relPath), edges are symbol references.
|
|
69
|
+
*
|
|
70
|
+
* Note: ReadonlyMap provides type-level immutability for consumers.
|
|
71
|
+
* Internal Maps are structurally compatible but not frozen at runtime.
|
|
72
|
+
*/
|
|
73
|
+
export interface FileGraph {
|
|
74
|
+
/** Unique file paths (relPath), sorted for determinism */
|
|
75
|
+
readonly nodes: readonly string[];
|
|
76
|
+
/** File-level edges: from → to → total weight (for PageRank) */
|
|
77
|
+
readonly edges: ReadonlyMap<string, ReadonlyMap<string, number>>;
|
|
78
|
+
/** Symbol-level edges: from → to → symbol → count (for definition ranking) */
|
|
79
|
+
readonly symbolEdges: ReadonlyMap<string, ReadonlyMap<string, ReadonlyMap<string, number>>>;
|
|
80
|
+
/** Total outgoing weight per file */
|
|
81
|
+
readonly outWeights: ReadonlyMap<string, number>;
|
|
82
|
+
/** Definitions indexed by symbol name */
|
|
83
|
+
readonly defsByName: ReadonlyMap<string, readonly Tag[]>;
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* A ranked definition for output.
|
|
87
|
+
*/
|
|
88
|
+
export interface RankedDefinition {
|
|
89
|
+
readonly file: string;
|
|
90
|
+
readonly ident: string;
|
|
91
|
+
readonly rank: number;
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* A cached entry for a single file.
|
|
95
|
+
*/
|
|
96
|
+
export interface CacheEntry {
|
|
97
|
+
readonly mtime: number;
|
|
98
|
+
readonly tags: readonly Tag[];
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* The cache file structure stored on disk.
|
|
102
|
+
*/
|
|
103
|
+
export interface CacheFile {
|
|
104
|
+
readonly version: number;
|
|
105
|
+
readonly entries: Record<string, CacheEntry>;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* In-memory cache structure.
|
|
109
|
+
*/
|
|
110
|
+
export interface Cache {
|
|
111
|
+
readonly version: number;
|
|
112
|
+
readonly entries: Map<string, CacheEntry>;
|
|
113
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/package.json
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@snevins/repo-mapper",
|
|
3
|
+
"version": "1.0.3",
|
|
4
|
+
"description": "Generate token-budgeted repo maps for LLM context using tree-sitter and PageRank",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"bin": {
|
|
15
|
+
"repo-mapper": "dist/index.js"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"README.md",
|
|
20
|
+
"LICENSE"
|
|
21
|
+
],
|
|
22
|
+
"sideEffects": false,
|
|
23
|
+
"scripts": {
|
|
24
|
+
"build": "tsc",
|
|
25
|
+
"prepack": "pnpm build",
|
|
26
|
+
"start": "node dist/index.js",
|
|
27
|
+
"test": "vitest run",
|
|
28
|
+
"test:watch": "vitest",
|
|
29
|
+
"lint": "eslint .",
|
|
30
|
+
"lint:fix": "eslint . --fix"
|
|
31
|
+
},
|
|
32
|
+
"engines": {
|
|
33
|
+
"node": ">=20"
|
|
34
|
+
},
|
|
35
|
+
"repository": {
|
|
36
|
+
"type": "git",
|
|
37
|
+
"url": "git+https://github.com/stevennevins/repo-mapper.git"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/stevennevins/repo-mapper#readme",
|
|
40
|
+
"bugs": {
|
|
41
|
+
"url": "https://github.com/stevennevins/repo-mapper/issues"
|
|
42
|
+
},
|
|
43
|
+
"keywords": [
|
|
44
|
+
"llm",
|
|
45
|
+
"context",
|
|
46
|
+
"repo-map",
|
|
47
|
+
"tree-sitter",
|
|
48
|
+
"pagerank",
|
|
49
|
+
"ai",
|
|
50
|
+
"code-analysis"
|
|
51
|
+
],
|
|
52
|
+
"author": "Steven Nevins",
|
|
53
|
+
"license": "MIT",
|
|
54
|
+
"devDependencies": {
|
|
55
|
+
"@eslint/js": "^9.39.2",
|
|
56
|
+
"@types/node": "^25.0.9",
|
|
57
|
+
"eslint": "^9.39.2",
|
|
58
|
+
"typescript": "^5.9.3",
|
|
59
|
+
"typescript-eslint": "^8.53.0",
|
|
60
|
+
"vitest": "^4.0.17"
|
|
61
|
+
},
|
|
62
|
+
"dependencies": {
|
|
63
|
+
"ignore": "^7.0.5",
|
|
64
|
+
"tree-sitter-go": "^0.25.0",
|
|
65
|
+
"tree-sitter-javascript": "^0.25.0",
|
|
66
|
+
"tree-sitter-python": "^0.25.0",
|
|
67
|
+
"tree-sitter-rust": "^0.24.0",
|
|
68
|
+
"tree-sitter-solidity": "^1.2.13",
|
|
69
|
+
"tree-sitter-typescript": "^0.23.2",
|
|
70
|
+
"web-tree-sitter": "^0.26.3"
|
|
71
|
+
}
|
|
72
|
+
}
|