sigmap 8.33.0 → 8.35.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/CHANGELOG.md +24 -0
- package/README.md +12 -12
- package/gen-context.js +531 -74
- package/llms-full.txt +9 -9
- package/llms.txt +7 -7
- package/package.json +1 -1
- package/packages/cli/package.json +1 -1
- package/packages/core/index.js +1 -0
- package/packages/core/package.json +1 -1
- package/src/config/loader.js +1 -1
- package/src/config/tune.js +1 -1
- package/src/discovery/language-detector.js +1 -0
- package/src/discovery/source-root-registry.js +10 -1
- package/src/discovery/source-root-scorer.js +1 -1
- package/src/extractors/cpp.js +8 -3
- package/src/extractors/csharp.js +8 -3
- package/src/extractors/css.js +1 -1
- package/src/extractors/dart.js +8 -3
- package/src/extractors/deps.js +23 -1
- package/src/extractors/dispatch.js +2 -0
- package/src/extractors/dockerfile.js +1 -1
- package/src/extractors/gdscript.js +2 -2
- package/src/extractors/go.js +13 -5
- package/src/extractors/html.js +1 -1
- package/src/extractors/javascript.js +7 -3
- package/src/extractors/kotlin.js +8 -3
- package/src/extractors/lua.js +152 -0
- package/src/extractors/markdown.js +1 -1
- package/src/extractors/php.js +8 -3
- package/src/extractors/properties.js +1 -1
- package/src/extractors/python.js +5 -2
- package/src/extractors/python_dataclass.js +3 -1
- package/src/extractors/r.js +1 -1
- package/src/extractors/ruby.js +1 -1
- package/src/extractors/rust.js +13 -5
- package/src/extractors/scala.js +8 -3
- package/src/extractors/shell.js +1 -1
- package/src/extractors/svelte.js +1 -1
- package/src/extractors/swift.js +8 -3
- package/src/extractors/toml.js +1 -1
- package/src/extractors/typescript.js +8 -4
- package/src/extractors/typescript_react.js +1 -1
- package/src/extractors/vue_sfc.js +3 -1
- package/src/extractors/xml.js +3 -1
- package/src/extractors/yaml.js +1 -1
- package/src/graph/call-graph.js +81 -1
- package/src/mcp/server.js +46 -4
- package/src/retrieval/ranker.js +14 -5
package/llms-full.txt
CHANGED
|
@@ -11,21 +11,21 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.35.0 | Benchmark: sigmap-v8.35-main (2026-09-13)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
18
18
|
---
|
|
19
19
|
|
|
20
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
20
|
+
## Core metrics (benchmark: sigmap-v8.35-main, 2026-09-13)
|
|
21
21
|
|
|
22
22
|
| Metric | Without SigMap | With SigMap |
|
|
23
23
|
|--------|----------------|-------------|
|
|
24
|
-
| Retrieval hit@5 | 44.0% (single-shot grep) | 78.
|
|
25
|
-
| Token reduction | — | 96.
|
|
26
|
-
| Task-success proxy (modeled) | — |
|
|
27
|
-
| Prompts per task | 2.84 | 1.
|
|
28
|
-
| Supported languages | — |
|
|
24
|
+
| Retrieval hit@5 | 44.0% (single-shot grep) | 78.6% (1.73× lift) |
|
|
25
|
+
| Token reduction | — | 96.6% average |
|
|
26
|
+
| Task-success proxy (modeled) | — | 61.0% |
|
|
27
|
+
| Prompts per task | 2.84 | 1.61 (43.4% fewer) |
|
|
28
|
+
| Supported languages | — | 33 |
|
|
29
29
|
| MCP tools | — | 21 |
|
|
30
30
|
| npm runtime dependencies | — | 0 |
|
|
31
31
|
|
|
@@ -370,9 +370,9 @@ impact = {"depth":3,"includeSigs":true}
|
|
|
370
370
|
|
|
371
371
|
---
|
|
372
372
|
|
|
373
|
-
## Supported languages (
|
|
373
|
+
## Supported languages (33 extractors)
|
|
374
374
|
|
|
375
|
-
cpp, csharp, css, dart, dockerfile, gdscript, go, graphql, html, java, javascript, kotlin, markdown, php, properties, protobuf, python, r, ruby, rust, scala, shell, sql, svelte, swift, terraform, toml, typescript, typescript_react, vue_sfc, xml, yaml
|
|
375
|
+
cpp, csharp, css, dart, dockerfile, gdscript, go, graphql, html, java, javascript, kotlin, lua, markdown, php, properties, protobuf, python, r, ruby, rust, scala, shell, sql, svelte, swift, terraform, toml, typescript, typescript_react, vue_sfc, xml, yaml
|
|
376
376
|
|
|
377
377
|
---
|
|
378
378
|
|
package/llms.txt
CHANGED
|
@@ -11,7 +11,7 @@ ranking keeps the relevant context in scope (cutting tokens ~97% as a side
|
|
|
11
11
|
effect), with no LLM calls, embeddings, or vector database. Works with Claude,
|
|
12
12
|
Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
13
13
|
|
|
14
|
-
# Version: 8.
|
|
14
|
+
# Version: 8.35.0 | Benchmark: sigmap-v8.35-main (2026-09-13)
|
|
15
15
|
# Source: auto-generated from package.json, version.json, benchmarks/latest.json, src/mcp/tools.js, src/config/defaults.js
|
|
16
16
|
# Regenerate: npm run generate:llms | Validate: npm run validate:llms
|
|
17
17
|
|
|
@@ -23,13 +23,13 @@ Cursor, GitHub Copilot, Aider, Windsurf, local LLMs, and MCP.
|
|
|
23
23
|
- No blast-radius awareness before editing a hub file — `--impact` shows every file a change touches.
|
|
24
24
|
- Pasted stack traces, CI logs, and JSON bloat the prompt — `squeeze` minimizes them and enriches the top frame from the symbol index.
|
|
25
25
|
|
|
26
|
-
## Core metrics (benchmark: sigmap-v8.
|
|
26
|
+
## Core metrics (benchmark: sigmap-v8.35-main, 2026-09-13)
|
|
27
27
|
|
|
28
|
-
- hit@5 retrieval: 78.
|
|
29
|
-
- Token reduction: 96.
|
|
30
|
-
- Task-success proxy:
|
|
31
|
-
- Prompts per task: 1.
|
|
32
|
-
- Languages:
|
|
28
|
+
- hit@5 retrieval: 78.6% vs 44.0% single-shot grep baseline (1.73× lift)
|
|
29
|
+
- Token reduction: 96.6% average across benchmark repos
|
|
30
|
+
- Task-success proxy: 61.0% (modeled from retrieval tiers, not measured LLM sessions)
|
|
31
|
+
- Prompts per task: 1.61 vs 2.84 baseline (43.4% fewer, modeled)
|
|
32
|
+
- Languages: 33 supported · MCP tools: 21
|
|
33
33
|
- Dependencies: zero npm runtime dependencies · fully offline
|
|
34
34
|
|
|
35
35
|
## Quick start
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sigmap",
|
|
3
|
-
"version": "8.
|
|
3
|
+
"version": "8.35.0",
|
|
4
4
|
"description": "The deterministic, verifiable grounding layer for AI code work — a zero-dependency signature-and-evidence map that grounds Claude, Cursor, Copilot, Aider, Windsurf, local LLMs & MCP agents against your real code (repo + installed libraries) so they stop hallucinating files, imports & APIs. Runs offline via npx; byte-stable output; ~97% token reduction as proof.",
|
|
5
5
|
"main": "packages/core/index.js",
|
|
6
6
|
"exports": {
|
package/packages/core/index.js
CHANGED
package/src/config/loader.js
CHANGED
|
@@ -81,7 +81,7 @@ const SUPPORTED_CODE_EXTS = new Set([
|
|
|
81
81
|
'.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs',
|
|
82
82
|
'.py', '.pyw', '.java', '.kt', '.kts', '.go', '.rs', '.cs',
|
|
83
83
|
'.cpp', '.c', '.h', '.hpp', '.cc', '.rb', '.rake', '.php',
|
|
84
|
-
'.swift', '.dart', '.scala', '.sc', '.vue', '.svelte',
|
|
84
|
+
'.swift', '.dart', '.scala', '.sc', '.lua', '.vue', '.svelte',
|
|
85
85
|
'.html', '.htm', '.css', '.scss', '.sass', '.less',
|
|
86
86
|
'.yml', '.yaml', '.sh', '.bash', '.zsh', '.fish',
|
|
87
87
|
'.sql', '.graphql', '.gql', '.tf', '.tfvars', '.proto',
|
package/src/config/tune.js
CHANGED
|
@@ -38,7 +38,7 @@ const TOKENS_PER_FILE = 25;
|
|
|
38
38
|
const SOURCE_EXTS = new Set([
|
|
39
39
|
'.js', '.mjs', '.cjs', '.jsx', '.ts', '.tsx', '.py', '.rb', '.go', '.rs',
|
|
40
40
|
'.java', '.kt', '.cs', '.cpp', '.c', '.h', '.hpp', '.swift', '.dart',
|
|
41
|
-
'.scala', '.php', '.gd', '.r', '.R',
|
|
41
|
+
'.scala', '.php', '.lua', '.gd', '.r', '.R',
|
|
42
42
|
]);
|
|
43
43
|
|
|
44
44
|
/** Raw user config file content, or null when absent/unparsable. */
|
|
@@ -19,6 +19,7 @@ const EXT_TO_LANG = {
|
|
|
19
19
|
'.java': 'java', '.kt': 'kotlin', '.cs': 'csharp', '.cpp': 'cpp',
|
|
20
20
|
'.c': 'cpp', '.h': 'cpp', '.hpp': 'cpp', '.swift': 'swift',
|
|
21
21
|
'.dart': 'dart', '.scala': 'scala', '.php': 'php',
|
|
22
|
+
'.lua': 'lua',
|
|
22
23
|
'.gd': 'gdscript',
|
|
23
24
|
'.r': 'r', '.R': 'r',
|
|
24
25
|
};
|
|
@@ -156,12 +156,21 @@ const REGISTRY = {
|
|
|
156
156
|
akka: { detectionFiles: [], detectionDeps: ['akka'], srcDirs: ['src/main/scala','src'] },
|
|
157
157
|
play: { detectionFiles: [], detectionDeps: ['play'], srcDirs: ['app','conf'] },
|
|
158
158
|
spark: { detectionFiles: [], detectionDeps: ['spark'],srcDirs: ['src/main/scala'] },
|
|
159
|
-
zio: { detectionFiles: [], detectionDeps: ['zio'],
|
|
159
|
+
zio: { detectionFiles: [], detectionDeps: ['zio'], srcDirs: ['src/main/scala'] },
|
|
160
160
|
},
|
|
161
161
|
srcDirs: ['src/main/scala','src'],
|
|
162
162
|
penalties: ['target'],
|
|
163
163
|
},
|
|
164
164
|
|
|
165
|
+
lua: {
|
|
166
|
+
manifestFiles: ['.luarc.json', 'selene.toml', 'stylua.toml'],
|
|
167
|
+
frameworks: {
|
|
168
|
+
luarocks: { detectionFiles: ['*.rockspec'], srcDirs: ['src','lua','lib'] },
|
|
169
|
+
},
|
|
170
|
+
srcDirs: ['src','lua','lib'],
|
|
171
|
+
penalties: ['.luarocks','luarocks_modules'],
|
|
172
|
+
},
|
|
173
|
+
|
|
165
174
|
r: {
|
|
166
175
|
manifestFiles: ['DESCRIPTION','renv.lock'],
|
|
167
176
|
frameworks: {
|
|
@@ -7,7 +7,7 @@ const { git } = require('../util/git');
|
|
|
7
7
|
const CODE_EXTS = new Set([
|
|
8
8
|
'.js','.mjs','.cjs','.ts','.tsx','.jsx',
|
|
9
9
|
'.py','.rb','.go','.rs','.java','.kt',
|
|
10
|
-
'.cs','.cpp','.c','.h','.swift','.dart','.scala','.php',
|
|
10
|
+
'.cs','.cpp','.c','.h','.swift','.dart','.scala','.php','.lua',
|
|
11
11
|
]);
|
|
12
12
|
|
|
13
13
|
const AUTO_SKIP = new Set([
|
package/src/extractors/cpp.js
CHANGED
|
@@ -5,8 +5,13 @@ const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
|
5
5
|
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed
|
|
7
7
|
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
8
|
-
|
|
9
|
-
|
|
8
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
9
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
10
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
11
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
12
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
13
|
+
const MEMBER_LIMIT = 120;
|
|
14
|
+
const PER_FILE_LIMIT = 200;
|
|
10
15
|
|
|
11
16
|
/**
|
|
12
17
|
* Extract signatures from C/C++ source code.
|
|
@@ -43,7 +48,7 @@ function extract(src) {
|
|
|
43
48
|
|
|
44
49
|
function extractBlock(src, startIndex) {
|
|
45
50
|
let depth = 1, i = startIndex;
|
|
46
|
-
const end = Math.min(src.length, startIndex +
|
|
51
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
47
52
|
while (i < end && depth > 0) {
|
|
48
53
|
if (src[i] === '{') depth++;
|
|
49
54
|
else if (src[i] === '}') depth--;
|
package/src/extractors/csharp.js
CHANGED
|
@@ -6,8 +6,13 @@ const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
|
6
6
|
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
7
7
|
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8
8
|
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
10
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
11
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
12
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
13
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
14
|
+
const MEMBER_LIMIT = 120;
|
|
15
|
+
const PER_FILE_LIMIT = 200;
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Extract signatures from C# source code.
|
|
@@ -42,7 +47,7 @@ function extract(src) {
|
|
|
42
47
|
|
|
43
48
|
function extractBlock(src, startIndex) {
|
|
44
49
|
let depth = 1, i = startIndex;
|
|
45
|
-
const end = Math.min(src.length, startIndex +
|
|
50
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
46
51
|
while (i < end && depth > 0) {
|
|
47
52
|
if (src[i] === '{') depth++;
|
|
48
53
|
else if (src[i] === '}') depth--;
|
package/src/extractors/css.js
CHANGED
|
@@ -4,7 +4,7 @@ const { capWithNotice } = require('../util/truncate');
|
|
|
4
4
|
|
|
5
5
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7
|
-
const PER_FILE_LIMIT =
|
|
7
|
+
const PER_FILE_LIMIT = 200;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract signatures from CSS/SCSS/SASS/Less source code.
|
package/src/extractors/dart.js
CHANGED
|
@@ -6,8 +6,13 @@ const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
|
6
6
|
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
7
7
|
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8
8
|
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
10
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
11
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
12
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
13
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
14
|
+
const MEMBER_LIMIT = 120;
|
|
15
|
+
const PER_FILE_LIMIT = 200;
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Extract signatures from Dart source code.
|
|
@@ -61,7 +66,7 @@ function extract(src) {
|
|
|
61
66
|
|
|
62
67
|
function extractBlock(src, startIndex) {
|
|
63
68
|
let depth = 1, i = startIndex;
|
|
64
|
-
const end = Math.min(src.length, startIndex +
|
|
69
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
65
70
|
while (i < end && depth > 0) {
|
|
66
71
|
if (src[i] === '{') depth++;
|
|
67
72
|
else if (src[i] === '}') depth--;
|
package/src/extractors/deps.js
CHANGED
|
@@ -89,6 +89,28 @@ function extractRDeps(src) {
|
|
|
89
89
|
return [...deps].slice(0, 5);
|
|
90
90
|
}
|
|
91
91
|
|
|
92
|
+
/**
|
|
93
|
+
* Extract Lua require() module dependencies.
|
|
94
|
+
* Captures `require "mod"` and `require("mod")`, returning compact module
|
|
95
|
+
* names as they appear in source.
|
|
96
|
+
* @param {string} src
|
|
97
|
+
* @returns {string[]}
|
|
98
|
+
*/
|
|
99
|
+
function extractLuaDeps(src) {
|
|
100
|
+
const deps = new Set();
|
|
101
|
+
const stripped = stripLuaComments(src || '');
|
|
102
|
+
for (const m of stripped.matchAll(/\brequire\s*(?:\(\s*)?["']([A-Za-z0-9_.\/-]+)["']\s*\)?/g)) {
|
|
103
|
+
if (m[1]) deps.add(m[1]);
|
|
104
|
+
}
|
|
105
|
+
return [...deps].slice(0, 5);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function stripLuaComments(src) {
|
|
109
|
+
return String(src || '')
|
|
110
|
+
.replace(/--\[\[[\s\S]*?\]\]/g, '')
|
|
111
|
+
.replace(/--.*$/gm, '');
|
|
112
|
+
}
|
|
113
|
+
|
|
92
114
|
/**
|
|
93
115
|
* Build reverse dependency map from forward map.
|
|
94
116
|
* @param {Map<string, string[]>} forwardMap
|
|
@@ -107,4 +129,4 @@ function buildReverseDepMap(forwardMap) {
|
|
|
107
129
|
return reverse;
|
|
108
130
|
}
|
|
109
131
|
|
|
110
|
-
module.exports = { extractPythonDeps, extractTSDeps, extractRDeps, buildReverseDepMap };
|
|
132
|
+
module.exports = { extractPythonDeps, extractTSDeps, extractRDeps, extractLuaDeps, buildReverseDepMap };
|
|
@@ -28,6 +28,7 @@ const EXTRACTORS = {
|
|
|
28
28
|
swift: require('./swift'),
|
|
29
29
|
dart: require('./dart'),
|
|
30
30
|
scala: require('./scala'),
|
|
31
|
+
lua: require('./lua'),
|
|
31
32
|
gdscript: require('./gdscript'),
|
|
32
33
|
r: require('./r'),
|
|
33
34
|
vue_sfc: require('./vue_sfc'),
|
|
@@ -78,6 +79,7 @@ const EXT_MAP = {
|
|
|
78
79
|
'.swift': 'swift',
|
|
79
80
|
'.dart': 'dart',
|
|
80
81
|
'.scala': 'scala', '.sc': 'scala',
|
|
82
|
+
'.lua': 'lua',
|
|
81
83
|
'.gd': 'gdscript',
|
|
82
84
|
'.r': 'r', '.R': 'r',
|
|
83
85
|
'.vue': 'vue_sfc',
|
|
@@ -4,7 +4,7 @@ const { capWithNotice } = require('../util/truncate');
|
|
|
4
4
|
|
|
5
5
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7
|
-
const PER_FILE_LIMIT =
|
|
7
|
+
const PER_FILE_LIMIT = 200;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract signatures from Dockerfiles.
|
|
@@ -4,10 +4,10 @@ const { capWithNotice } = require('../util/truncate');
|
|
|
4
4
|
|
|
5
5
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7
|
-
const PER_FILE_LIMIT =
|
|
7
|
+
const PER_FILE_LIMIT = 200;
|
|
8
8
|
|
|
9
9
|
// Ceilings disclose what they drop rather than truncating silently (#576).
|
|
10
|
-
const MEMBER_LIMIT =
|
|
10
|
+
const MEMBER_LIMIT = 120;
|
|
11
11
|
const ENUM_LIMIT = 24;
|
|
12
12
|
|
|
13
13
|
/**
|
package/src/extractors/go.js
CHANGED
|
@@ -1,11 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
3
|
const { lineAt, withAnchor } = require('./line-anchor');
|
|
4
|
-
const { capWithNotice } = require('../util/truncate');
|
|
4
|
+
const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
5
5
|
|
|
6
6
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
7
7
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
8
|
-
|
|
8
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
9
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
10
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
11
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
12
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
13
|
+
const PER_FILE_LIMIT = 200;
|
|
14
|
+
|
|
15
|
+
// Per-interface member ceiling, disclosed via capMembersWithNotice (#576).
|
|
16
|
+
const MEMBER_LIMIT = 120;
|
|
9
17
|
|
|
10
18
|
/**
|
|
11
19
|
* Extract signatures from Go source code.
|
|
@@ -41,7 +49,7 @@ function extract(src) {
|
|
|
41
49
|
const block = extractBlock(stripped, bodyStart);
|
|
42
50
|
sigs.push(hinted(withAnchor(`type ${m[1]} interface`, lineAt(stripped, m.index), lineAt(stripped, bodyStart + block.length)), m[1]));
|
|
43
51
|
for (const meth of extractInterfaceMethods(block)) {
|
|
44
|
-
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + meth.declIdx), lineAt(stripped, bodyStart + meth.endIdx)));
|
|
52
|
+
sigs.push(withAnchor(` ${meth.text}`, lineAt(stripped, bodyStart + (meth.declIdx || 0)), lineAt(stripped, bodyStart + (meth.endIdx || 0))));
|
|
45
53
|
}
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -59,7 +67,7 @@ function extract(src) {
|
|
|
59
67
|
|
|
60
68
|
function extractBlock(src, startIndex) {
|
|
61
69
|
let depth = 1, i = startIndex;
|
|
62
|
-
const end = Math.min(src.length, startIndex +
|
|
70
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
63
71
|
while (i < end && depth > 0) {
|
|
64
72
|
if (src[i] === '{') depth++;
|
|
65
73
|
else if (src[i] === '}') depth--;
|
|
@@ -79,7 +87,7 @@ function extractInterfaceMethods(block) {
|
|
|
79
87
|
endIdx: m.index + m[0].length,
|
|
80
88
|
});
|
|
81
89
|
}
|
|
82
|
-
return methods
|
|
90
|
+
return capMembersWithNotice(methods, MEMBER_LIMIT, 'methods');
|
|
83
91
|
}
|
|
84
92
|
|
|
85
93
|
function normalizeParams(params) {
|
package/src/extractors/html.js
CHANGED
|
@@ -4,7 +4,7 @@ const { capWithNotice } = require('../util/truncate');
|
|
|
4
4
|
|
|
5
5
|
// Ceiling sits above the default `maxSigsPerFile` so the configured budget
|
|
6
6
|
// governs output rather than a literal buried here, and omissions are disclosed (#576).
|
|
7
|
-
const PER_FILE_LIMIT =
|
|
7
|
+
const PER_FILE_LIMIT = 200;
|
|
8
8
|
|
|
9
9
|
/**
|
|
10
10
|
* Extract signatures from HTML files.
|
|
@@ -4,6 +4,10 @@ const { lineAt, withAnchor } = require('./line-anchor');
|
|
|
4
4
|
const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
5
5
|
const { stripComments, maskCode, readBalanced } = require('./scan');
|
|
6
6
|
|
|
7
|
+
// Class bodies are scanned to this many characters — guard against
|
|
8
|
+
// pathological input only; the old 4KB window silently hid members (#576).
|
|
9
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
10
|
+
|
|
7
11
|
/**
|
|
8
12
|
* Extract signatures from JavaScript source code.
|
|
9
13
|
* Top-level declarations and class members carry a `:start-end` line anchor
|
|
@@ -113,13 +117,13 @@ function extract(src) {
|
|
|
113
117
|
const anchored = anchors[i] ? withAnchor(s, anchors[i][0], anchors[i][1]) : s;
|
|
114
118
|
return docHintFor[i] ? `${anchored} # ${docHintFor[i]}` : anchored;
|
|
115
119
|
});
|
|
116
|
-
return capWithNotice(withAnchors,
|
|
120
|
+
return capWithNotice(withAnchors, 200, 'signatures');
|
|
117
121
|
}
|
|
118
122
|
|
|
119
123
|
function extractBlock(src, startIndex) {
|
|
120
124
|
let depth = 1;
|
|
121
125
|
let i = startIndex;
|
|
122
|
-
const end = Math.min(src.length, startIndex +
|
|
126
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
123
127
|
while (i < end && depth > 0) {
|
|
124
128
|
if (src[i] === '{') depth++;
|
|
125
129
|
else if (src[i] === '}') depth--;
|
|
@@ -154,7 +158,7 @@ function extractClassMembers(block, maskedBlock, returnHints) {
|
|
|
154
158
|
const retStr = formatReturnHint(returnHints.get(m[1]));
|
|
155
159
|
members.push({ text: `${isStatic}${isAsync}${m[1]}(${normalizeParams(params)})${retStr}`, start, end });
|
|
156
160
|
}
|
|
157
|
-
return capMembersWithNotice(members,
|
|
161
|
+
return capMembersWithNotice(members, 120, 'methods');
|
|
158
162
|
}
|
|
159
163
|
|
|
160
164
|
function buildReturnHints(src) {
|
package/src/extractors/kotlin.js
CHANGED
|
@@ -6,8 +6,13 @@ const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
|
6
6
|
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
7
7
|
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8
8
|
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
10
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
11
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
12
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
13
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
14
|
+
const MEMBER_LIMIT = 120;
|
|
15
|
+
const PER_FILE_LIMIT = 200;
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Extract signatures from Kotlin source code.
|
|
@@ -61,7 +66,7 @@ function extract(src) {
|
|
|
61
66
|
|
|
62
67
|
function extractBlock(src, startIndex) {
|
|
63
68
|
let depth = 1, i = startIndex;
|
|
64
|
-
const end = Math.min(src.length, startIndex +
|
|
69
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
65
70
|
while (i < end && depth > 0) {
|
|
66
71
|
if (src[i] === '{') depth++;
|
|
67
72
|
else if (src[i] === '}') depth--;
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { capWithNotice } = require('../util/truncate');
|
|
4
|
+
|
|
5
|
+
// Ceiling discloses what it drops rather than truncating silently (#583).
|
|
6
|
+
// Collection runs to completion so the marker reports the true overflow —
|
|
7
|
+
// stopping early made r.js report "+1 more" where 50 were hidden (#584).
|
|
8
|
+
const PER_FILE_LIMIT = 200;
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Extract signatures from Lua source code.
|
|
12
|
+
*
|
|
13
|
+
* Recognised constructs:
|
|
14
|
+
* - Global functions: `function name(args)`
|
|
15
|
+
* - Module-table functions: `function M.name(args)` / `function M:name(args)`
|
|
16
|
+
* - Local functions: `local function name(args)`
|
|
17
|
+
* - Assigned functions: `name = function(args)` / `M.name = function(args)`
|
|
18
|
+
* - Module imports: `local mod = require("mod")` as compact hints
|
|
19
|
+
* - LDoc-style doc comments (`---`) as first-sentence hints
|
|
20
|
+
*
|
|
21
|
+
* The extractor is regex-only and zero-dependency, matching SigMap's Tier-3
|
|
22
|
+
* language extractor style.
|
|
23
|
+
*
|
|
24
|
+
* @param {string} src - Raw file content
|
|
25
|
+
* @returns {string[]} Array of signature strings
|
|
26
|
+
*/
|
|
27
|
+
function extract(src) {
|
|
28
|
+
if (!src || typeof src !== 'string') return [];
|
|
29
|
+
const sigs = [];
|
|
30
|
+
const hints = collectDocHints(src);
|
|
31
|
+
const stripped = stripLuaComments(src);
|
|
32
|
+
const seen = new Set();
|
|
33
|
+
|
|
34
|
+
// local foo = require('bar.baz') — useful module-surface hint, capped low.
|
|
35
|
+
for (const m of stripped.matchAll(/^\s*(?:local\s+)?([A-Za-z_]\w*)\s*=\s*require\s*\(\s*['"]([A-Za-z0-9_.\/-]+)['"]\s*\)/gm)) {
|
|
36
|
+
pushUnique(sigs, seen, `require ${m[2]} as ${m[1]}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// local function name(args)
|
|
40
|
+
for (const m of stripped.matchAll(/^\s*local\s+function\s+([A-Za-z_]\w*)\s*\(([^)]*)\)/gm)) {
|
|
41
|
+
if (m[1].startsWith('_')) continue;
|
|
42
|
+
pushUnique(sigs, seen, `local function ${m[1]}(${normalizeParams(m[2])})${applyHint(hints, m[1])}`);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// function name(args), function M.name(args), function M:name(args)
|
|
46
|
+
for (const m of stripped.matchAll(/^\s*function\s+([A-Za-z_]\w*(?:(?:\.|:)[A-Za-z_]\w*)*)\s*\(([^)]*)\)/gm)) {
|
|
47
|
+
const name = m[1];
|
|
48
|
+
if (name.startsWith('_')) continue;
|
|
49
|
+
pushUnique(sigs, seen, `function ${name}(${normalizeParams(m[2])})${applyHint(hints, name)}`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// name = function(args), M.name = function(args), M:name = function(args)
|
|
53
|
+
for (const m of stripped.matchAll(/^\s*(?:local\s+)?([A-Za-z_]\w*(?:(?:\.|:)[A-Za-z_]\w*)*)\s*=\s*function\s*\(([^)]*)\)/gm)) {
|
|
54
|
+
const name = m[1];
|
|
55
|
+
if (name.startsWith('_')) continue;
|
|
56
|
+
pushUnique(sigs, seen, `${name} = function(${normalizeParams(m[2])})${applyHint(hints, name)}`);
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
return capWithNotice(sigs, PER_FILE_LIMIT, 'signatures');
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function pushUnique(out, seen, sig) {
|
|
63
|
+
if (!sig || seen.has(sig)) return;
|
|
64
|
+
seen.add(sig);
|
|
65
|
+
out.push(sig);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeParams(params) {
|
|
69
|
+
return String(params || '')
|
|
70
|
+
.replace(/--.*$/gm, '')
|
|
71
|
+
.split(',')
|
|
72
|
+
.map((p) => p.trim().replace(/\s+/g, ' '))
|
|
73
|
+
.filter(Boolean)
|
|
74
|
+
.join(', ');
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function applyHint(hints, name) {
|
|
78
|
+
const h = hints.get(name);
|
|
79
|
+
return h ? ` # ${h}` : '';
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Attach each contiguous `---` doc block to the next function-like declaration
|
|
84
|
+
* by its extracted symbol name.
|
|
85
|
+
*/
|
|
86
|
+
function collectDocHints(src) {
|
|
87
|
+
const hints = new Map();
|
|
88
|
+
const lines = src.split('\n');
|
|
89
|
+
let block = [];
|
|
90
|
+
for (const line of lines) {
|
|
91
|
+
const doc = line.match(/^\s*---\s?(.*)$/);
|
|
92
|
+
if (doc) {
|
|
93
|
+
block.push(doc[1]);
|
|
94
|
+
} else if (block.length > 0) {
|
|
95
|
+
const decl = line.match(/^\s*local\s+function\s+([A-Za-z_]\w*)\s*\(/)
|
|
96
|
+
|| line.match(/^\s*function\s+([A-Za-z_]\w*(?:(?:\.|:)[A-Za-z_]\w*)*)\s*\(/)
|
|
97
|
+
|| line.match(/^\s*(?:local\s+)?([A-Za-z_]\w*(?:(?:\.|:)[A-Za-z_]\w*)*)\s*=\s*function\s*\(/);
|
|
98
|
+
if (decl) {
|
|
99
|
+
const hint = firstDocSentence(block);
|
|
100
|
+
if (hint) hints.set(decl[1], hint);
|
|
101
|
+
}
|
|
102
|
+
block = [];
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return hints;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function firstDocSentence(block) {
|
|
109
|
+
for (const raw of block) {
|
|
110
|
+
const line = String(raw || '').trim();
|
|
111
|
+
if (!line || line.startsWith('@')) continue;
|
|
112
|
+
return line.replace(/\s+/g, ' ').slice(0, 60).replace(/[.,;:!?]+$/, '').trim();
|
|
113
|
+
}
|
|
114
|
+
return '';
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/** Strip Lua line and long comments while preserving strings enough for regex scans. */
|
|
118
|
+
function stripLuaComments(src) {
|
|
119
|
+
const out = src.split('');
|
|
120
|
+
const blank = (a, b) => { for (let i = a; i < b; i++) if (out[i] !== '\n') out[i] = ' '; };
|
|
121
|
+
let i = 0;
|
|
122
|
+
while (i < src.length) {
|
|
123
|
+
const ch = src[i];
|
|
124
|
+
if (ch === '"' || ch === "'") {
|
|
125
|
+
const quote = ch;
|
|
126
|
+
i++;
|
|
127
|
+
while (i < src.length) {
|
|
128
|
+
if (src[i] === '\\') { i += 2; continue; }
|
|
129
|
+
if (src[i] === quote) { i++; break; }
|
|
130
|
+
if (src[i] === '\n') break;
|
|
131
|
+
i++;
|
|
132
|
+
}
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
if (src.startsWith('--[[', i)) {
|
|
136
|
+
const end = src.indexOf(']]', i + 4);
|
|
137
|
+
blank(i, end === -1 ? src.length : end + 2);
|
|
138
|
+
i = end === -1 ? src.length : end + 2;
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (src.startsWith('--', i)) {
|
|
142
|
+
const end = src.indexOf('\n', i + 2);
|
|
143
|
+
blank(i, end === -1 ? src.length : end);
|
|
144
|
+
i = end === -1 ? src.length : end;
|
|
145
|
+
continue;
|
|
146
|
+
}
|
|
147
|
+
i++;
|
|
148
|
+
}
|
|
149
|
+
return out.join('');
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
module.exports = { extract };
|
package/src/extractors/php.js
CHANGED
|
@@ -6,8 +6,13 @@ const { capWithNotice, capMembersWithNotice } = require('../util/truncate');
|
|
|
6
6
|
// Ceilings sit above the default `maxSigsPerFile` so the configured budget
|
|
7
7
|
// governs output rather than a literal buried here, and omissions are disclosed
|
|
8
8
|
// — an undisclosed cap looks like a class that simply has eight methods (#576).
|
|
9
|
-
|
|
10
|
-
|
|
9
|
+
// Class bodies are scanned to this many characters. Real classes routinely
|
|
10
|
+
// run past the old 4KB scan window — truncating there silently hid every
|
|
11
|
+
// member after ~4000 chars AND anchored class end-lines short (#576). The
|
|
12
|
+
// ceiling only guards against pathological input (Java parity, #551).
|
|
13
|
+
const MAX_CLASS_BODY_CHARS = 200000;
|
|
14
|
+
const MEMBER_LIMIT = 120;
|
|
15
|
+
const PER_FILE_LIMIT = 200;
|
|
11
16
|
|
|
12
17
|
/**
|
|
13
18
|
* Extract signatures from PHP source code.
|
|
@@ -65,7 +70,7 @@ function extract(src) {
|
|
|
65
70
|
|
|
66
71
|
function extractBlock(src, startIndex) {
|
|
67
72
|
let depth = 1, i = startIndex;
|
|
68
|
-
const end = Math.min(src.length, startIndex +
|
|
73
|
+
const end = Math.min(src.length, startIndex + MAX_CLASS_BODY_CHARS);
|
|
69
74
|
while (i < end && depth > 0) {
|
|
70
75
|
if (src[i] === '{') depth++;
|
|
71
76
|
else if (src[i] === '}') depth--;
|