ucn 5.3.7 → 5.4.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/.claude/skills/ucn/SKILL.md +35 -3
- package/.claude/skills/ucn/references/commands.md +15 -1
- package/cli/index.js +4 -2
- package/core/account.js +4 -0
- package/core/analysis.js +80 -1
- package/core/cache.js +3 -1
- package/core/callers.js +21 -2
- package/core/execute.js +24 -4
- package/core/graph.js +6 -2
- package/core/output/analysis.js +5 -5
- package/core/output/doctor.js +1 -1
- package/core/output/lines.js +8 -2
- package/core/output/public.js +16 -4
- package/core/output/refactoring.js +4 -1
- package/core/output/reporting.js +1 -1
- package/core/output/search.js +6 -1
- package/core/project.js +5 -0
- package/core/registry.js +1 -1
- package/core/reporting.js +2 -0
- package/core/search.js +13 -2
- package/core/shared.js +13 -4
- package/core/verify.js +6 -1
- package/languages/c-family.js +9 -8
- package/languages/csharp.js +11 -10
- package/languages/go.js +8 -7
- package/languages/index.js +4 -0
- package/languages/java.js +3 -2
- package/languages/javascript.js +2 -1
- package/languages/python.js +11 -3
- package/languages/rust.js +3 -2
- package/languages/utils.js +51 -29
- package/package.json +2 -2
package/core/reporting.js
CHANGED
|
@@ -48,6 +48,7 @@ function getStats(index, options = {}) {
|
|
|
48
48
|
files: scopedFiles.length,
|
|
49
49
|
symbols: totalSymbols, // Total symbol count, not unique names
|
|
50
50
|
buildTime: index.buildTime,
|
|
51
|
+
buildTimeNote: 'Last index build, including discovery and graphs; excludes cache I/O and query execution. Reused when loading a cached index.',
|
|
51
52
|
byLanguage: {},
|
|
52
53
|
byType: {},
|
|
53
54
|
...(index.truncated && { truncated: index.truncated })
|
|
@@ -1044,6 +1045,7 @@ function orient(index, options = {}) {
|
|
|
1044
1045
|
files: stats.files,
|
|
1045
1046
|
symbols: stats.symbols,
|
|
1046
1047
|
buildTime: stats.buildTime,
|
|
1048
|
+
buildTimeNote: stats.buildTimeNote,
|
|
1047
1049
|
byLanguage: stats.byLanguage,
|
|
1048
1050
|
dirs,
|
|
1049
1051
|
hot: {
|
package/core/search.js
CHANGED
|
@@ -727,6 +727,7 @@ function structuralSearch(index, options = {}) {
|
|
|
727
727
|
// Auto-infer type: --receiver implies type=call
|
|
728
728
|
const type = options.type || (receiver ? 'call' : undefined);
|
|
729
729
|
const results = [];
|
|
730
|
+
const skippedTestFiles = new Set();
|
|
730
731
|
|
|
731
732
|
// Validate type if provided
|
|
732
733
|
if (type && !STRUCTURAL_TYPES.has(type)) {
|
|
@@ -753,7 +754,13 @@ function structuralSearch(index, options = {}) {
|
|
|
753
754
|
if (!rp.includes(options.file) && !rp.endsWith(options.file)) return false;
|
|
754
755
|
}
|
|
755
756
|
if ((options.exclude && options.exclude.length > 0) || options.in) {
|
|
756
|
-
if (!index.matchesFilters(fileEntry.relativePath, {
|
|
757
|
+
if (!index.matchesFilters(fileEntry.relativePath, { in: options.in })) return false;
|
|
758
|
+
if (!index.matchesFilters(fileEntry.relativePath, { exclude: options.exclude })) {
|
|
759
|
+
if (options.testExclude && !index.matchesFilters(fileEntry.relativePath, { exclude: options.testExclude })) {
|
|
760
|
+
skippedTestFiles.add(fileEntry.relativePath);
|
|
761
|
+
}
|
|
762
|
+
return false;
|
|
763
|
+
}
|
|
757
764
|
}
|
|
758
765
|
return true;
|
|
759
766
|
};
|
|
@@ -883,7 +890,10 @@ function structuralSearch(index, options = {}) {
|
|
|
883
890
|
// expression position — never "unused" (the deadcode
|
|
884
891
|
// twin of the bodyScopedName audit skip).
|
|
885
892
|
if (def.bodyScopedName) continue;
|
|
886
|
-
|
|
893
|
+
// buildCalleeIndex rebuilds the whole project. Reuse
|
|
894
|
+
// the eagerly built (or cache-loaded) index, including
|
|
895
|
+
// across every candidate in this operation.
|
|
896
|
+
if (!index.calleeIndex) index.buildCalleeIndex();
|
|
887
897
|
// A name whose every call site is its own recursion
|
|
888
898
|
// has zero callers (fix #253c — the deadcode
|
|
889
899
|
// carve-out, applied here). Class-kind names are
|
|
@@ -975,6 +985,7 @@ function structuralSearch(index, options = {}) {
|
|
|
975
985
|
}).filter(([, v]) => v !== undefined && v !== null)),
|
|
976
986
|
totalMatched: total,
|
|
977
987
|
shown: results.length,
|
|
988
|
+
filesSkipped: skippedTestFiles.size,
|
|
978
989
|
...(unused && {
|
|
979
990
|
unusedScope: 'callable-symbols-only',
|
|
980
991
|
unusedSafety: 'candidate-only; use deadcode before deletion',
|
package/core/shared.js
CHANGED
|
@@ -50,15 +50,22 @@ function codeUnitCompare(a, b) {
|
|
|
50
50
|
* Path-based test heuristic — matches the same patterns as `find`'s exclusion
|
|
51
51
|
* logic so that `about` and `find` agree on which files are de-emphasized.
|
|
52
52
|
*
|
|
53
|
-
*
|
|
54
|
-
*
|
|
53
|
+
* Uses language-specific filename conventions plus `test|tests|__tests__|__mocks__|fixture|mock`
|
|
54
|
+
* as path segments (with word boundaries on both sides). `spec` is a test
|
|
55
|
+
* marker only for languages whose test-file conventions include it.
|
|
55
56
|
*
|
|
56
57
|
* Complement to `isTestFile` (filename pattern check) — together they catch
|
|
57
58
|
* both `foo.test.js` (filename) AND `test/agent-benchmark.js` (directory).
|
|
58
59
|
*/
|
|
59
60
|
function isTestPath(rp) {
|
|
60
61
|
if (!rp) return false;
|
|
61
|
-
|
|
62
|
+
const language = detectLanguage(rp);
|
|
63
|
+
const { langTraits } = require('../languages');
|
|
64
|
+
const specConvention = langTraits(language)?.testFileCandidates?.('sample', '')
|
|
65
|
+
.some(candidate => candidate.includes('.spec'));
|
|
66
|
+
return isTestFile(rp, language) ||
|
|
67
|
+
/(^|[/._-])(test|tests|__tests__|__mocks__|fixture|mock)s?([/._-]|$)/i.test(rp) ||
|
|
68
|
+
(!!specConvention && /(^|[/._-])specs?([/._-]|$)/i.test(rp));
|
|
62
69
|
}
|
|
63
70
|
|
|
64
71
|
/**
|
|
@@ -109,7 +116,9 @@ function pickBestDefinition(matches, opts = {}) {
|
|
|
109
116
|
* Returns a new array with test patterns appended (deduplicating).
|
|
110
117
|
*/
|
|
111
118
|
function addTestExclusions(exclude) {
|
|
112
|
-
|
|
119
|
+
// Keep automatic test classification distinct from explicit substring
|
|
120
|
+
// exclusions: --exclude=spec deliberately excludes Python specs too.
|
|
121
|
+
const testPatterns = ['test files'];
|
|
113
122
|
const existing = new Set((exclude || []).map(e => e.toLowerCase()));
|
|
114
123
|
const additions = testPatterns.filter(p => !existing.has(p));
|
|
115
124
|
return [...(exclude || []), ...additions];
|
package/core/verify.js
CHANGED
|
@@ -808,6 +808,8 @@ function computePlanCallSites(index, name, def) {
|
|
|
808
808
|
expression: (call.content || '').trim(),
|
|
809
809
|
args: analysis.args,
|
|
810
810
|
argCount: analysis.argCount,
|
|
811
|
+
...(analysis.keywordArgNames && { keywordArgNames: analysis.keywordArgNames }),
|
|
812
|
+
...(analysis.positionalCount != null && { positionalCount: analysis.positionalCount }),
|
|
811
813
|
...(c.calledAs && { calledAs: c.calledAs }),
|
|
812
814
|
});
|
|
813
815
|
}
|
|
@@ -2158,7 +2160,10 @@ function plan(index, name, options = {}) {
|
|
|
2158
2160
|
} else if (options.defaultValue) {
|
|
2159
2161
|
suggestion = `Add argument: ${options.defaultValue} (no default parameter values in ${planFileEntry?.language || 'this language'})`;
|
|
2160
2162
|
} else {
|
|
2161
|
-
|
|
2163
|
+
const keywordCall = langTraits(planLang)?.keywordArguments && site.keywordArgNames?.length > 0;
|
|
2164
|
+
suggestion = keywordCall
|
|
2165
|
+
? `Add keyword argument: ${options.addParam}=${options.addParam} (replace the right-hand value with the intended expression; keep existing keyword arguments)`
|
|
2166
|
+
: `Add argument: ${options.addParam}`;
|
|
2162
2167
|
}
|
|
2163
2168
|
changes.push({
|
|
2164
2169
|
file: site.file,
|
package/languages/c-family.js
CHANGED
|
@@ -13,6 +13,7 @@ const { typeOrigin } = require('./type-evidence');
|
|
|
13
13
|
|
|
14
14
|
const {
|
|
15
15
|
traverseTree,
|
|
16
|
+
nodeTextWithoutComments,
|
|
16
17
|
traverseTreeCached,
|
|
17
18
|
nodeToLocation,
|
|
18
19
|
extractJSDocstring,
|
|
@@ -989,7 +990,7 @@ function paramTypeText(param, identity) {
|
|
|
989
990
|
const defaultValue = param.childForFieldName('default_value');
|
|
990
991
|
const end = defaultValue ? defaultValue.startIndex : param.endIndex;
|
|
991
992
|
if (identity.nameNode.startIndex < base || identity.nameNode.endIndex > end) return null;
|
|
992
|
-
const text = param.
|
|
993
|
+
const text = nodeTextWithoutComments(param).slice(0, end - base);
|
|
993
994
|
const typeText = (text.slice(0, identity.nameNode.startIndex - base) +
|
|
994
995
|
text.slice(identity.nameNode.endIndex - base))
|
|
995
996
|
.replace(/\s+/g, ' ')
|
|
@@ -1014,10 +1015,10 @@ function structuredParams(paramsNode) {
|
|
|
1014
1015
|
// their type text alone — the type must not double as both name and
|
|
1015
1016
|
// annotation, and `void *` must not collapse into the `(void)` form.
|
|
1016
1017
|
const info = {
|
|
1017
|
-
name: identity.name || param.
|
|
1018
|
+
name: identity.name || nodeTextWithoutComments(param).replace(/\s+/g, ' ').trim(),
|
|
1018
1019
|
};
|
|
1019
1020
|
if (typeNode && identity.name) {
|
|
1020
|
-
info.type = paramTypeText(param, identity) || typeNode
|
|
1021
|
+
info.type = paramTypeText(param, identity) || nodeTextWithoutComments(typeNode);
|
|
1021
1022
|
}
|
|
1022
1023
|
if (param.type === 'optional_parameter_declaration') info.optional = true;
|
|
1023
1024
|
let declaratorCursor = declarator;
|
|
@@ -1164,7 +1165,7 @@ function returnTypeOf(node) {
|
|
|
1164
1165
|
const descriptor = (current.namedChildren || []).find(child =>
|
|
1165
1166
|
child.type === 'type_descriptor') || current.namedChild(0);
|
|
1166
1167
|
const type = descriptor?.childForFieldName('type') || descriptor;
|
|
1167
|
-
return type
|
|
1168
|
+
return nodeTextWithoutComments(type) || null;
|
|
1168
1169
|
}
|
|
1169
1170
|
for (const child of current.namedChildren || []) {
|
|
1170
1171
|
const found = findTrailing(child);
|
|
@@ -1193,7 +1194,7 @@ function returnTypeOf(node) {
|
|
|
1193
1194
|
current = current.childForFieldName('declarator') ||
|
|
1194
1195
|
(current.namedChildren || []).find(child => child.type.endsWith('_declarator'));
|
|
1195
1196
|
}
|
|
1196
|
-
return stars > 0 ? `${typeNode
|
|
1197
|
+
return stars > 0 ? `${nodeTextWithoutComments(typeNode)} ${'*'.repeat(stars)}` : nodeTextWithoutComments(typeNode);
|
|
1197
1198
|
}
|
|
1198
1199
|
|
|
1199
1200
|
function memberFromNode(node, className, access, lines, mode) {
|
|
@@ -1209,7 +1210,7 @@ function memberFromNode(node, className, access, lines, mode) {
|
|
|
1209
1210
|
if (isConstructor && identity.name.startsWith('~')) modifiers.push('destructor');
|
|
1210
1211
|
return {
|
|
1211
1212
|
name: identity.name,
|
|
1212
|
-
params: paramsNode ? paramsNode.
|
|
1213
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\(|\)$/g, '').trim() : '...',
|
|
1213
1214
|
paramsStructured: structuredParams(paramsNode),
|
|
1214
1215
|
returnType: isConstructor ? null :
|
|
1215
1216
|
(identity.conversionType || returnTypeOf(node)),
|
|
@@ -1510,7 +1511,7 @@ function findFunctionsInTree(code, tree, mode, sourceLines = null) {
|
|
|
1510
1511
|
: null;
|
|
1511
1512
|
functions.push({
|
|
1512
1513
|
name: identity.name,
|
|
1513
|
-
params: paramsNode ? paramsNode.
|
|
1514
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\(|\)$/g, '').trim() : '...',
|
|
1514
1515
|
paramsStructured: structuredParams(paramsNode),
|
|
1515
1516
|
returnType: isConstructor ? null :
|
|
1516
1517
|
(identity.conversionType || returnTypeOf(node)),
|
|
@@ -1800,7 +1801,7 @@ function findMacrosInTree(tree, lines, parser) {
|
|
|
1800
1801
|
startLine,
|
|
1801
1802
|
endLine,
|
|
1802
1803
|
indent,
|
|
1803
|
-
params: paramsNode ? paramsNode.
|
|
1804
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\(|\)$/g, '').trim() : undefined,
|
|
1804
1805
|
paramsStructured: paramsNode
|
|
1805
1806
|
? (paramsNode.namedChildren || [])
|
|
1806
1807
|
.filter(child => child.type === 'identifier')
|
package/languages/csharp.js
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
const {
|
|
4
4
|
traverseTree,
|
|
5
|
+
nodeTextWithoutComments,
|
|
5
6
|
traverseTreeCached,
|
|
6
7
|
nodeToLocation,
|
|
7
8
|
extractJSDocstring,
|
|
@@ -127,7 +128,7 @@ function structuredParams(paramsNode) {
|
|
|
127
128
|
if (nameNode) {
|
|
128
129
|
recoveredParams.push({
|
|
129
130
|
name: nameNode.text,
|
|
130
|
-
...(typeNode && { type: typeNode
|
|
131
|
+
...(typeNode && { type: nodeTextWithoutComments(typeNode) }),
|
|
131
132
|
rest: true,
|
|
132
133
|
});
|
|
133
134
|
}
|
|
@@ -138,14 +139,14 @@ function structuredParams(paramsNode) {
|
|
|
138
139
|
const typeNode = param.childForFieldName('type');
|
|
139
140
|
if (!nameNode) continue;
|
|
140
141
|
const info = { name: nameNode.text };
|
|
141
|
-
if (typeNode) info.type = typeNode
|
|
142
|
+
if (typeNode) info.type = nodeTextWithoutComments(typeNode);
|
|
142
143
|
if (modifiersOf(param).includes('this')) info.extensionReceiver = true;
|
|
143
144
|
if (param.type === 'parameter_array') info.rest = true;
|
|
144
145
|
const value = param.childForFieldName('value') ||
|
|
145
146
|
param.namedChildren.find(child => child !== nameNode && child !== typeNode &&
|
|
146
|
-
!['attribute_list', 'modifier'].includes(child.type));
|
|
147
|
+
!['attribute_list', 'modifier', 'comment'].includes(child.type));
|
|
147
148
|
if (value) {
|
|
148
|
-
info.default = value
|
|
149
|
+
info.default = nodeTextWithoutComments(value);
|
|
149
150
|
info.optional = true;
|
|
150
151
|
}
|
|
151
152
|
params.push(info);
|
|
@@ -208,9 +209,9 @@ function memberFromNode(node, className, lines) {
|
|
|
208
209
|
const paramsStructured = structuredParams(paramsNode);
|
|
209
210
|
return {
|
|
210
211
|
name,
|
|
211
|
-
params: paramsNode ? paramsNode.
|
|
212
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\(|\)$/g, '').trim() : '...',
|
|
212
213
|
paramsStructured,
|
|
213
|
-
returnType: isConstructor ? null : returnNode
|
|
214
|
+
returnType: isConstructor ? null : nodeTextWithoutComments(returnNode).trim() || null,
|
|
214
215
|
startLine,
|
|
215
216
|
endLine,
|
|
216
217
|
indent,
|
|
@@ -263,9 +264,9 @@ function indexerMember(node, className, lines) {
|
|
|
263
264
|
const { startLine, endLine, indent } = nodeToLocation(node, lines);
|
|
264
265
|
return {
|
|
265
266
|
name: 'this[]',
|
|
266
|
-
params: paramsNode ? paramsNode.
|
|
267
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\[|\]$/g, '').trim() : '...',
|
|
267
268
|
paramsStructured: structuredParams(paramsNode),
|
|
268
|
-
returnType: typeNode
|
|
269
|
+
returnType: nodeTextWithoutComments(typeNode).trim() || null,
|
|
269
270
|
startLine,
|
|
270
271
|
endLine,
|
|
271
272
|
indent,
|
|
@@ -495,9 +496,9 @@ function findFunctions(code, parser) {
|
|
|
495
496
|
const modifiers = modifiersOf(node);
|
|
496
497
|
functions.push({
|
|
497
498
|
name: nameNode.text,
|
|
498
|
-
params: paramsNode ? paramsNode.
|
|
499
|
+
params: paramsNode ? nodeTextWithoutComments(paramsNode).replace(/^\(|\)$/g, '').trim() : '...',
|
|
499
500
|
paramsStructured: structuredParams(paramsNode),
|
|
500
|
-
returnType: returnNode
|
|
501
|
+
returnType: nodeTextWithoutComments(returnNode).trim() || null,
|
|
501
502
|
startLine,
|
|
502
503
|
endLine,
|
|
503
504
|
indent,
|
package/languages/go.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ReceiverTypeMap, typeOrigin } = require('./type-evidence');
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
traverseTree,
|
|
13
|
+
nodeTextWithoutComments,
|
|
13
14
|
traverseTreeCached,
|
|
14
15
|
nodeToLocation,
|
|
15
16
|
parseStructuredParams,
|
|
@@ -29,7 +30,7 @@ function parseTree(parser, code) {
|
|
|
29
30
|
function extractReturnType(node) {
|
|
30
31
|
const resultNode = node.childForFieldName('result');
|
|
31
32
|
if (resultNode) {
|
|
32
|
-
return resultNode.
|
|
33
|
+
return nodeTextWithoutComments(resultNode).trim() || null;
|
|
33
34
|
}
|
|
34
35
|
return null;
|
|
35
36
|
}
|
|
@@ -39,7 +40,7 @@ function extractReturnedFunctionResult(node) {
|
|
|
39
40
|
const resultNode = node.childForFieldName('result');
|
|
40
41
|
if (resultNode?.type !== 'function_type') return null;
|
|
41
42
|
const innerResult = resultNode.childForFieldName('result');
|
|
42
|
-
return innerResult
|
|
43
|
+
return nodeTextWithoutComments(innerResult).trim() || null;
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
/**
|
|
@@ -51,7 +52,7 @@ function extractGoParams(paramsNode) {
|
|
|
51
52
|
// unknown signatures in JSON output (fix #238; the shared
|
|
52
53
|
// utils.extractParams already had this fix).
|
|
53
54
|
if (!paramsNode) return '...';
|
|
54
|
-
const text = paramsNode
|
|
55
|
+
const text = nodeTextWithoutComments(paramsNode);
|
|
55
56
|
return text.replace(/^\(|\)$/g, '').trim();
|
|
56
57
|
}
|
|
57
58
|
|
|
@@ -115,7 +116,7 @@ function _processFunction(node, functions, processedRanges, lines) {
|
|
|
115
116
|
indent,
|
|
116
117
|
modifiers: isExported ? ['export'] : [],
|
|
117
118
|
isFunctionVariable: true,
|
|
118
|
-
...(resultNode
|
|
119
|
+
...(resultNode && { returnType: nodeTextWithoutComments(resultNode).trim() || null }),
|
|
119
120
|
});
|
|
120
121
|
}
|
|
121
122
|
return true;
|
|
@@ -491,11 +492,11 @@ function extractInterfaceMembers(interfaceNode, codeOrLines) {
|
|
|
491
492
|
} else if (sub.type === 'parameter_list') {
|
|
492
493
|
hasParams = true;
|
|
493
494
|
if (!paramsText) {
|
|
494
|
-
paramsText = sub.
|
|
495
|
+
paramsText = nodeTextWithoutComments(sub).slice(1, -1); // strip parens
|
|
495
496
|
paramsNode = sub;
|
|
496
497
|
} else {
|
|
497
498
|
// Second parameter_list is the return type tuple
|
|
498
|
-
returnType = sub
|
|
499
|
+
returnType = nodeTextWithoutComments(sub);
|
|
499
500
|
}
|
|
500
501
|
}
|
|
501
502
|
}
|
|
@@ -514,7 +515,7 @@ function extractInterfaceMembers(interfaceNode, codeOrLines) {
|
|
|
514
515
|
for (let j = 0; j < child.namedChildCount; j++) {
|
|
515
516
|
const sub = child.namedChild(j);
|
|
516
517
|
if (returnTypeNodes.has(sub.type) && sub.text !== nameText) {
|
|
517
|
-
returnType = sub
|
|
518
|
+
returnType = nodeTextWithoutComments(sub);
|
|
518
519
|
}
|
|
519
520
|
}
|
|
520
521
|
}
|
package/languages/index.js
CHANGED
|
@@ -144,6 +144,7 @@ const LANGUAGES = {
|
|
|
144
144
|
traits: {
|
|
145
145
|
...STRUCTURAL_TRAITS,
|
|
146
146
|
selfParam: ['this'],
|
|
147
|
+
storedPromises: true,
|
|
147
148
|
testFileCandidates: (base, ext) => [`${base}.test${ext}`, `${base}.spec${ext}`, `${base}.test.ts`, `${base}.test.js`, `${base}.spec.ts`, `${base}.spec.js`],
|
|
148
149
|
testDirs: ['__tests__'],
|
|
149
150
|
},
|
|
@@ -157,6 +158,7 @@ const LANGUAGES = {
|
|
|
157
158
|
traits: {
|
|
158
159
|
...STRUCTURAL_TRAITS,
|
|
159
160
|
selfParam: ['this'],
|
|
161
|
+
storedPromises: true,
|
|
160
162
|
testFileCandidates: (base, ext) => [`${base}.test${ext}`, `${base}.spec${ext}`, `${base}.test.ts`, `${base}.test.js`, `${base}.spec.ts`, `${base}.spec.js`],
|
|
161
163
|
testDirs: ['__tests__'],
|
|
162
164
|
},
|
|
@@ -170,6 +172,7 @@ const LANGUAGES = {
|
|
|
170
172
|
traits: {
|
|
171
173
|
...STRUCTURAL_TRAITS,
|
|
172
174
|
selfParam: ['this'],
|
|
175
|
+
storedPromises: true,
|
|
173
176
|
testFileCandidates: (base, ext) => [`${base}.test${ext}`, `${base}.spec${ext}`, `${base}.test.ts`, `${base}.test.js`, `${base}.spec.ts`, `${base}.spec.js`],
|
|
174
177
|
testDirs: ['__tests__'],
|
|
175
178
|
},
|
|
@@ -324,6 +327,7 @@ const LANGUAGES = {
|
|
|
324
327
|
traits: {
|
|
325
328
|
...STRUCTURAL_TRAITS,
|
|
326
329
|
selfParam: ['this'],
|
|
330
|
+
storedPromises: true,
|
|
327
331
|
testFileCandidates: (base, ext) => [`${base}.test${ext}`, `${base}.spec${ext}`],
|
|
328
332
|
},
|
|
329
333
|
}
|
package/languages/java.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ReceiverTypeMap, typeOrigin } = require('./type-evidence');
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
traverseTree,
|
|
13
|
+
nodeTextWithoutComments,
|
|
13
14
|
traverseTreeCached,
|
|
14
15
|
nodeToLocation,
|
|
15
16
|
parseStructuredParams,
|
|
@@ -32,7 +33,7 @@ function extractJavaParams(paramsNode) {
|
|
|
32
33
|
// unknown signatures in JSON output (fix #241; go/rust got this in #238,
|
|
33
34
|
// the shared utils.extractParams already had it).
|
|
34
35
|
if (!paramsNode) return '...';
|
|
35
|
-
const text = paramsNode
|
|
36
|
+
const text = nodeTextWithoutComments(paramsNode);
|
|
36
37
|
let params = text.replace(/^\(|\)$/g, '').trim();
|
|
37
38
|
return params;
|
|
38
39
|
}
|
|
@@ -201,7 +202,7 @@ function stripJavaString(text) {
|
|
|
201
202
|
function extractReturnType(node) {
|
|
202
203
|
const typeNode = node.childForFieldName('type');
|
|
203
204
|
if (typeNode) {
|
|
204
|
-
return typeNode
|
|
205
|
+
return nodeTextWithoutComments(typeNode);
|
|
205
206
|
}
|
|
206
207
|
return null;
|
|
207
208
|
}
|
package/languages/javascript.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ReceiverTypeMap, typeOrigin } = require('./type-evidence');
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
traverseTree,
|
|
13
|
+
nodeTextWithoutComments,
|
|
13
14
|
traverseTreeCached,
|
|
14
15
|
nodeToLocation,
|
|
15
16
|
extractParams,
|
|
@@ -34,7 +35,7 @@ function parseTree(parser, code) {
|
|
|
34
35
|
function extractReturnType(node) {
|
|
35
36
|
const returnTypeNode = node.childForFieldName('return_type');
|
|
36
37
|
if (returnTypeNode) {
|
|
37
|
-
let text = returnTypeNode.
|
|
38
|
+
let text = nodeTextWithoutComments(returnTypeNode).trim();
|
|
38
39
|
if (text.startsWith(':')) {
|
|
39
40
|
text = text.slice(1).trim();
|
|
40
41
|
}
|
package/languages/python.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ReceiverTypeMap, typeOrigin } = require('./type-evidence');
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
traverseTree,
|
|
13
|
+
nodeTextWithoutComments,
|
|
13
14
|
traverseTreeCached,
|
|
14
15
|
nodeToLocation,
|
|
15
16
|
parseStructuredParams,
|
|
@@ -32,7 +33,7 @@ function parseTree(parser, code) {
|
|
|
32
33
|
function extractReturnType(node) {
|
|
33
34
|
const returnTypeNode = node.childForFieldName('return_type');
|
|
34
35
|
if (returnTypeNode) {
|
|
35
|
-
let text = returnTypeNode.
|
|
36
|
+
let text = nodeTextWithoutComments(returnTypeNode).trim();
|
|
36
37
|
if (text.startsWith('->')) {
|
|
37
38
|
text = text.slice(2).trim();
|
|
38
39
|
}
|
|
@@ -129,7 +130,7 @@ function extractPythonParams(paramsNode) {
|
|
|
129
130
|
// unknown signatures in JSON output (fix #241; go/rust got this in #238,
|
|
130
131
|
// the shared utils.extractParams already had it).
|
|
131
132
|
if (!paramsNode) return '...';
|
|
132
|
-
const text = paramsNode
|
|
133
|
+
const text = nodeTextWithoutComments(paramsNode);
|
|
133
134
|
let params = text.replace(/^\(|\)$/g, '').trim();
|
|
134
135
|
return params;
|
|
135
136
|
}
|
|
@@ -2804,7 +2805,14 @@ function findCallsInCode(code, parser) {
|
|
|
2804
2805
|
const argsNode = node.childForFieldName('arguments');
|
|
2805
2806
|
if (argsNode) {
|
|
2806
2807
|
for (let i = 0; i < argsNode.namedChildCount; i++) {
|
|
2807
|
-
const
|
|
2808
|
+
const rawArg = argsNode.namedChild(i);
|
|
2809
|
+
const arg = rawArg.type === 'keyword_argument'
|
|
2810
|
+
? rawArg.childForFieldName('value') : rawArg;
|
|
2811
|
+
if (!arg) continue;
|
|
2812
|
+
// Bare keyword values already belong to the reference
|
|
2813
|
+
// inventory/rename path; only extend the member-value
|
|
2814
|
+
// callback model to match its positional counterpart.
|
|
2815
|
+
if (rawArg.type === 'keyword_argument' && arg.type !== 'attribute') continue;
|
|
2808
2816
|
if (arg.type === 'identifier' && !PYTHON_SKIP.has(arg.text) && !nonCallableNames.has(arg.text)) {
|
|
2809
2817
|
calls.push({
|
|
2810
2818
|
name: arg.text,
|
package/languages/rust.js
CHANGED
|
@@ -10,6 +10,7 @@ const { ReceiverTypeMap, typeOrigin } = require('./type-evidence');
|
|
|
10
10
|
|
|
11
11
|
const {
|
|
12
12
|
traverseTree,
|
|
13
|
+
nodeTextWithoutComments,
|
|
13
14
|
traverseTreeCached,
|
|
14
15
|
nodeToLocation,
|
|
15
16
|
parseStructuredParams,
|
|
@@ -128,7 +129,7 @@ function declarationTrees(code, parser) {
|
|
|
128
129
|
function extractReturnType(node) {
|
|
129
130
|
const returnTypeNode = node.childForFieldName('return_type');
|
|
130
131
|
if (returnTypeNode) {
|
|
131
|
-
let text = returnTypeNode.
|
|
132
|
+
let text = nodeTextWithoutComments(returnTypeNode).trim();
|
|
132
133
|
if (text.startsWith('->')) {
|
|
133
134
|
text = text.slice(2).trim();
|
|
134
135
|
}
|
|
@@ -198,7 +199,7 @@ function extractRustParams(paramsNode) {
|
|
|
198
199
|
// unknown signatures in JSON output (fix #238; the shared
|
|
199
200
|
// utils.extractParams already had this fix).
|
|
200
201
|
if (!paramsNode) return '...';
|
|
201
|
-
const text = paramsNode
|
|
202
|
+
const text = nodeTextWithoutComments(paramsNode);
|
|
202
203
|
return text.replace(/^\(|\)$/g, '').trim();
|
|
203
204
|
}
|
|
204
205
|
|