ucn 3.7.8 → 3.7.9
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/core/project.js +20 -5
- package/package.json +1 -1
- package/test/parser.test.js +26 -0
package/core/project.js
CHANGED
|
@@ -3206,7 +3206,7 @@ class ProjectIndex {
|
|
|
3206
3206
|
sharedCallees: []
|
|
3207
3207
|
};
|
|
3208
3208
|
|
|
3209
|
-
// 1. Same file functions
|
|
3209
|
+
// 1. Same file functions (sorted by proximity to target)
|
|
3210
3210
|
const fileEntry = this.files.get(def.file);
|
|
3211
3211
|
if (fileEntry) {
|
|
3212
3212
|
for (const sym of fileEntry.symbols) {
|
|
@@ -3218,6 +3218,10 @@ class ProjectIndex {
|
|
|
3218
3218
|
});
|
|
3219
3219
|
}
|
|
3220
3220
|
}
|
|
3221
|
+
// Sort by distance from target function (nearest first)
|
|
3222
|
+
related.sameFile.sort((a, b) =>
|
|
3223
|
+
Math.abs(a.line - def.startLine) - Math.abs(b.line - def.startLine)
|
|
3224
|
+
);
|
|
3221
3225
|
}
|
|
3222
3226
|
|
|
3223
3227
|
// 2. Similar names (shared prefix/suffix, camelCase similarity)
|
|
@@ -4097,14 +4101,25 @@ class ProjectIndex {
|
|
|
4097
4101
|
const language = detectLanguage(call.file);
|
|
4098
4102
|
if (!language) return { args: null, argCount: 0 };
|
|
4099
4103
|
|
|
4100
|
-
const parser = getParser(language);
|
|
4101
|
-
if (!parser) return { args: null, argCount: 0 };
|
|
4102
|
-
|
|
4103
4104
|
// Use tree cache to avoid re-parsing the same file in batch operations
|
|
4104
4105
|
let tree = this._treeCache?.get(call.file);
|
|
4105
4106
|
if (!tree) {
|
|
4106
4107
|
const content = this._readFile(call.file);
|
|
4107
|
-
|
|
4108
|
+
// HTML files need special handling: parse script blocks as JS
|
|
4109
|
+
if (language === 'html') {
|
|
4110
|
+
const htmlModule = getLanguageModule('html');
|
|
4111
|
+
const htmlParser = getParser('html');
|
|
4112
|
+
const jsParser = getParser('javascript');
|
|
4113
|
+
if (!htmlParser || !jsParser) return { args: null, argCount: 0 };
|
|
4114
|
+
const blocks = htmlModule.extractScriptBlocks(content, htmlParser);
|
|
4115
|
+
if (blocks.length === 0) return { args: null, argCount: 0 };
|
|
4116
|
+
const virtualJS = htmlModule.buildVirtualJSContent(content, blocks);
|
|
4117
|
+
tree = safeParse(jsParser, virtualJS);
|
|
4118
|
+
} else {
|
|
4119
|
+
const parser = getParser(language);
|
|
4120
|
+
if (!parser) return { args: null, argCount: 0 };
|
|
4121
|
+
tree = safeParse(parser, content);
|
|
4122
|
+
}
|
|
4108
4123
|
if (!tree) return { args: null, argCount: 0 };
|
|
4109
4124
|
if (!this._treeCache) this._treeCache = new Map();
|
|
4110
4125
|
this._treeCache.set(call.file, tree);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "ucn",
|
|
3
|
-
"version": "3.7.
|
|
3
|
+
"version": "3.7.9",
|
|
4
4
|
"description": "Universal Code Navigator — AST-based call graph analysis for AI agents. Find callers, trace impact, detect dead code across JS/TS, Python, Go, Rust, Java, and HTML. CLI, MCP server, and agent skill.",
|
|
5
5
|
"main": "index.js",
|
|
6
6
|
"bin": {
|
package/test/parser.test.js
CHANGED
|
@@ -12871,6 +12871,32 @@ function unusedFn() { return 0; }
|
|
|
12871
12871
|
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
12872
12872
|
});
|
|
12873
12873
|
|
|
12874
|
+
it('verify/impact analyzeCallSite works for HTML inline scripts', () => {
|
|
12875
|
+
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ucn-html-verify-'));
|
|
12876
|
+
fs.writeFileSync(path.join(tmpDir, 'game.html'), `<html><body>
|
|
12877
|
+
<script>
|
|
12878
|
+
function checkCollision(objA, objB, threshX, threshZ) { return true; }
|
|
12879
|
+
function update() {
|
|
12880
|
+
var hitbox = { x: 1, z: 2 };
|
|
12881
|
+
if (checkCollision(p, player, hitbox.x, hitbox.z)) { return; }
|
|
12882
|
+
}
|
|
12883
|
+
</script>
|
|
12884
|
+
</body></html>`);
|
|
12885
|
+
fs.writeFileSync(path.join(tmpDir, 'package.json'), '{"name": "test"}');
|
|
12886
|
+
|
|
12887
|
+
const { ProjectIndex } = require('../core/project');
|
|
12888
|
+
const index = new ProjectIndex(tmpDir);
|
|
12889
|
+
index.build();
|
|
12890
|
+
|
|
12891
|
+
const result = index.verify('checkCollision');
|
|
12892
|
+
assert.ok(result.found);
|
|
12893
|
+
assert.strictEqual(result.totalCalls, 1);
|
|
12894
|
+
assert.strictEqual(result.valid, 1, `Expected 1 valid call, got ${result.valid} valid, ${result.uncertain} uncertain`);
|
|
12895
|
+
assert.strictEqual(result.uncertain, 0, 'dot-access args should not be uncertain');
|
|
12896
|
+
|
|
12897
|
+
fs.rmSync(tmpDir, { recursive: true, force: true });
|
|
12898
|
+
});
|
|
12899
|
+
|
|
12874
12900
|
it('findCallers detects callers from HTML event handlers', () => {
|
|
12875
12901
|
const tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'ucn-html-callers-'));
|
|
12876
12902
|
fs.writeFileSync(path.join(tmpDir, 'page.html'), `<html><body>
|