ucn 3.1.8 → 3.3.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.
Potentially problematic release.
This version of ucn might be problematic. Click here for more details.
- package/.claude/skills/ucn/SKILL.md +113 -48
- package/README.md +159 -29
- package/cli/index.js +147 -137
- package/core/discovery.js +1 -2
- package/core/imports.js +157 -331
- package/core/output.js +129 -147
- package/core/project.js +484 -220
- package/languages/go.js +21 -10
- package/languages/java.js +25 -9
- package/languages/javascript.js +56 -37
- package/languages/python.js +39 -10
- package/languages/rust.js +36 -8
- package/package.json +1 -1
- package/test/parser.test.js +967 -7
- package/test/reliability-test-prompt.md +58 -0
package/core/output.js
CHANGED
|
@@ -195,47 +195,11 @@ function printDefinition(def, relativePath) {
|
|
|
195
195
|
*/
|
|
196
196
|
function formatTocJson(data) {
|
|
197
197
|
return JSON.stringify({
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
byFile: data.byFile.map(f => ({
|
|
204
|
-
file: f.file,
|
|
205
|
-
language: f.language,
|
|
206
|
-
lines: f.lines,
|
|
207
|
-
functions: f.functions.map(fn => ({
|
|
208
|
-
name: fn.name,
|
|
209
|
-
params: fn.params, // FULL params
|
|
210
|
-
paramsStructured: fn.paramsStructured || [],
|
|
211
|
-
startLine: fn.startLine,
|
|
212
|
-
endLine: fn.endLine,
|
|
213
|
-
modifiers: fn.modifiers || [],
|
|
214
|
-
...(fn.returnType && { returnType: fn.returnType }),
|
|
215
|
-
...(fn.generics && { generics: fn.generics }),
|
|
216
|
-
...(fn.docstring && { docstring: fn.docstring }),
|
|
217
|
-
...(fn.isArrow && { isArrow: true }),
|
|
218
|
-
...(fn.isGenerator && { isGenerator: true })
|
|
219
|
-
})),
|
|
220
|
-
classes: f.classes.map(c => ({
|
|
221
|
-
name: c.name,
|
|
222
|
-
type: c.type,
|
|
223
|
-
startLine: c.startLine,
|
|
224
|
-
endLine: c.endLine,
|
|
225
|
-
modifiers: c.modifiers || [],
|
|
226
|
-
members: c.members || [],
|
|
227
|
-
...(c.extends && { extends: c.extends }),
|
|
228
|
-
...(c.implements && { implements: c.implements }),
|
|
229
|
-
...(c.generics && { generics: c.generics }),
|
|
230
|
-
...(c.docstring && { docstring: c.docstring })
|
|
231
|
-
})),
|
|
232
|
-
state: f.state.map(s => ({
|
|
233
|
-
name: s.name,
|
|
234
|
-
startLine: s.startLine,
|
|
235
|
-
endLine: s.endLine
|
|
236
|
-
}))
|
|
237
|
-
}))
|
|
238
|
-
}, null, 2);
|
|
198
|
+
meta: data.meta || { complete: true, skipped: 0, dynamicImports: 0, uncertain: 0 },
|
|
199
|
+
totals: data.totals,
|
|
200
|
+
summary: data.summary,
|
|
201
|
+
files: data.files
|
|
202
|
+
});
|
|
239
203
|
}
|
|
240
204
|
|
|
241
205
|
/**
|
|
@@ -243,22 +207,25 @@ function formatTocJson(data) {
|
|
|
243
207
|
*/
|
|
244
208
|
function formatSymbolJson(symbols, query) {
|
|
245
209
|
return JSON.stringify({
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
210
|
+
meta: { complete: true, skipped: 0, dynamicImports: 0, uncertain: 0 },
|
|
211
|
+
data: {
|
|
212
|
+
query,
|
|
213
|
+
count: symbols.length,
|
|
214
|
+
results: symbols.map(s => ({
|
|
215
|
+
name: s.name,
|
|
216
|
+
type: s.type,
|
|
217
|
+
file: s.relativePath || s.file,
|
|
218
|
+
startLine: s.startLine,
|
|
219
|
+
endLine: s.endLine,
|
|
220
|
+
...(s.params && { params: s.params }), // FULL params
|
|
221
|
+
...(s.paramsStructured && { paramsStructured: s.paramsStructured }),
|
|
222
|
+
...(s.returnType && { returnType: s.returnType }),
|
|
223
|
+
...(s.modifiers && { modifiers: s.modifiers }),
|
|
224
|
+
...(s.usageCount !== undefined && { usageCount: s.usageCount }),
|
|
225
|
+
...(s.usageCounts !== undefined && { usageCounts: s.usageCounts })
|
|
226
|
+
}))
|
|
227
|
+
}
|
|
228
|
+
});
|
|
262
229
|
}
|
|
263
230
|
|
|
264
231
|
/**
|
|
@@ -282,85 +249,95 @@ function formatUsagesJson(usages, name) {
|
|
|
282
249
|
});
|
|
283
250
|
|
|
284
251
|
return JSON.stringify({
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
252
|
+
meta: { complete: true, skipped: 0, dynamicImports: 0, uncertain: 0 },
|
|
253
|
+
data: {
|
|
254
|
+
symbol: name,
|
|
255
|
+
definitionCount: definitions.length,
|
|
256
|
+
callCount: calls.length,
|
|
257
|
+
importCount: imports.length,
|
|
258
|
+
referenceCount: references.length,
|
|
259
|
+
totalUsages: refs.length,
|
|
260
|
+
definitions: definitions.map(d => ({
|
|
261
|
+
file: d.relativePath || d.file,
|
|
262
|
+
line: d.line,
|
|
263
|
+
signature: d.signature || null, // FULL signature
|
|
264
|
+
type: d.type || null,
|
|
265
|
+
...(d.returnType && { returnType: d.returnType }),
|
|
266
|
+
...(d.before && d.before.length > 0 && { before: d.before }),
|
|
267
|
+
...(d.after && d.after.length > 0 && { after: d.after })
|
|
268
|
+
})),
|
|
269
|
+
calls: calls.map(formatUsage),
|
|
270
|
+
imports: imports.map(formatUsage),
|
|
271
|
+
references: references.map(formatUsage)
|
|
272
|
+
}
|
|
273
|
+
});
|
|
304
274
|
}
|
|
305
275
|
|
|
306
276
|
/**
|
|
307
277
|
* Format context (callers + callees) as JSON
|
|
308
278
|
*/
|
|
309
279
|
function formatContextJson(context) {
|
|
280
|
+
const meta = context.meta || { complete: true, skipped: 0, dynamicImports: 0, uncertain: 0 };
|
|
310
281
|
// Handle struct/interface types differently
|
|
311
282
|
if (context.type && ['struct', 'interface', 'type'].includes(context.type)) {
|
|
312
283
|
const callers = context.callers || [];
|
|
313
284
|
const methods = context.methods || [];
|
|
314
285
|
return JSON.stringify({
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
286
|
+
meta,
|
|
287
|
+
data: {
|
|
288
|
+
type: context.type,
|
|
289
|
+
name: context.name,
|
|
290
|
+
file: context.file,
|
|
291
|
+
startLine: context.startLine,
|
|
292
|
+
endLine: context.endLine,
|
|
293
|
+
methodCount: methods.length,
|
|
294
|
+
usageCount: callers.length,
|
|
295
|
+
methods: methods.map(m => ({
|
|
296
|
+
name: m.name,
|
|
297
|
+
file: m.file,
|
|
298
|
+
line: m.line,
|
|
299
|
+
params: m.params,
|
|
300
|
+
returnType: m.returnType,
|
|
301
|
+
receiver: m.receiver
|
|
302
|
+
})),
|
|
303
|
+
usages: callers.map(c => ({
|
|
304
|
+
file: c.relativePath || c.file,
|
|
305
|
+
line: c.line,
|
|
306
|
+
expression: c.content,
|
|
307
|
+
callerName: c.callerName
|
|
308
|
+
})),
|
|
309
|
+
...(context.warnings && { warnings: context.warnings })
|
|
310
|
+
}
|
|
311
|
+
});
|
|
338
312
|
}
|
|
339
313
|
|
|
340
314
|
// Standard function/method context
|
|
341
315
|
const callers = context.callers || [];
|
|
342
316
|
const callees = context.callees || [];
|
|
343
317
|
return JSON.stringify({
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
318
|
+
meta,
|
|
319
|
+
data: {
|
|
320
|
+
function: context.function,
|
|
321
|
+
file: context.file,
|
|
322
|
+
callerCount: callers.length,
|
|
323
|
+
calleeCount: callees.length,
|
|
324
|
+
callers: callers.map(c => ({
|
|
325
|
+
file: c.relativePath || c.file,
|
|
326
|
+
line: c.line,
|
|
327
|
+
expression: c.content, // FULL expression
|
|
328
|
+
callerName: c.callerName
|
|
329
|
+
})),
|
|
330
|
+
callees: callees.map(c => ({
|
|
331
|
+
name: c.name,
|
|
332
|
+
type: c.type,
|
|
333
|
+
file: c.relativePath || c.file,
|
|
334
|
+
line: c.startLine,
|
|
335
|
+
params: c.params, // FULL params
|
|
336
|
+
weight: c.weight || 'normal' // Dependency weight: core, setup, utility
|
|
337
|
+
})),
|
|
338
|
+
...(context.warnings && { warnings: context.warnings })
|
|
339
|
+
}
|
|
340
|
+
});
|
|
364
341
|
}
|
|
365
342
|
|
|
366
343
|
/**
|
|
@@ -440,29 +417,33 @@ function formatGraphJson(graph) {
|
|
|
440
417
|
* Includes function + all dependencies
|
|
441
418
|
*/
|
|
442
419
|
function formatSmartJson(result) {
|
|
420
|
+
const meta = result.meta || { complete: true, skipped: 0, dynamicImports: 0, uncertain: 0 };
|
|
443
421
|
return JSON.stringify({
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
422
|
+
meta,
|
|
423
|
+
data: {
|
|
424
|
+
target: {
|
|
425
|
+
name: result.target.name,
|
|
426
|
+
file: result.target.file,
|
|
427
|
+
startLine: result.target.startLine,
|
|
428
|
+
endLine: result.target.endLine,
|
|
429
|
+
params: result.target.params,
|
|
430
|
+
returnType: result.target.returnType,
|
|
431
|
+
code: result.target.code
|
|
432
|
+
},
|
|
433
|
+
dependencies: result.dependencies.map(d => ({
|
|
434
|
+
name: d.name,
|
|
435
|
+
type: d.type,
|
|
436
|
+
file: d.file,
|
|
437
|
+
startLine: d.startLine,
|
|
438
|
+
endLine: d.endLine,
|
|
439
|
+
params: d.params,
|
|
440
|
+
weight: d.weight, // core, setup, utility
|
|
441
|
+
callCount: d.callCount,
|
|
442
|
+
code: d.code
|
|
443
|
+
})),
|
|
444
|
+
types: result.types || []
|
|
445
|
+
}
|
|
446
|
+
});
|
|
466
447
|
}
|
|
467
448
|
|
|
468
449
|
// ============================================================================
|
|
@@ -891,10 +872,14 @@ function formatImpact(impact) {
|
|
|
891
872
|
}
|
|
892
873
|
}
|
|
893
874
|
if (fileGroup.count > 10) {
|
|
894
|
-
lines.push(` ... and ${fileGroup.count - 10} more`);
|
|
875
|
+
lines.push(` ... and ${fileGroup.count - 10} more in this file`);
|
|
895
876
|
}
|
|
896
877
|
}
|
|
897
878
|
|
|
879
|
+
if (impact.totalCallSites > 10) {
|
|
880
|
+
lines.push(`\nShowing up to 10 call sites per file. Use "ucn . usages ${impact.function}" to see all references.`);
|
|
881
|
+
}
|
|
882
|
+
|
|
898
883
|
return lines.join('\n');
|
|
899
884
|
}
|
|
900
885
|
|
|
@@ -1132,10 +1117,8 @@ function formatAbout(about, options = {}) {
|
|
|
1132
1117
|
|
|
1133
1118
|
// Warnings (show early for visibility)
|
|
1134
1119
|
if (about.warnings && about.warnings.length > 0) {
|
|
1135
|
-
lines.push('');
|
|
1136
|
-
lines.push('⚠️ WARNINGS:');
|
|
1137
1120
|
for (const w of about.warnings) {
|
|
1138
|
-
lines.push(` ${w.message}`);
|
|
1121
|
+
lines.push(` Note: ${w.message}`);
|
|
1139
1122
|
}
|
|
1140
1123
|
}
|
|
1141
1124
|
|
|
@@ -1215,9 +1198,8 @@ function formatAbout(about, options = {}) {
|
|
|
1215
1198
|
// Completeness warnings
|
|
1216
1199
|
if (about.completeness && about.completeness.warnings && about.completeness.warnings.length > 0) {
|
|
1217
1200
|
lines.push('');
|
|
1218
|
-
lines.push('⚠ COMPLETENESS:');
|
|
1219
1201
|
for (const w of about.completeness.warnings) {
|
|
1220
|
-
lines.push(`
|
|
1202
|
+
lines.push(`Note: ${w.message}`);
|
|
1221
1203
|
}
|
|
1222
1204
|
}
|
|
1223
1205
|
|