ucn 3.7.18 → 3.7.19
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 +5 -0
- package/cli/index.js +332 -428
- package/core/execute.js +376 -0
- package/core/expand-cache.js +162 -0
- package/core/project.js +11 -6
- package/core/registry.js +166 -0
- package/languages/utils.js +2 -2
- package/mcp/server.js +153 -315
- package/package.json +1 -1
package/cli/index.js
CHANGED
|
@@ -13,9 +13,12 @@ const path = require('path');
|
|
|
13
13
|
const { parse, parseFile, extractFunction, extractClass, cleanHtmlScriptTags, detectLanguage, isSupported } = require('../core/parser');
|
|
14
14
|
const { getParser, getLanguageModule } = require('../languages');
|
|
15
15
|
const { ProjectIndex } = require('../core/project');
|
|
16
|
-
const { expandGlob, findProjectRoot
|
|
16
|
+
const { expandGlob, findProjectRoot } = require('../core/discovery');
|
|
17
17
|
const output = require('../core/output');
|
|
18
|
-
const { pickBestDefinition
|
|
18
|
+
const { pickBestDefinition } = require('../core/shared');
|
|
19
|
+
const { getCliCommandSet, resolveCommand } = require('../core/registry');
|
|
20
|
+
const { execute } = require('../core/execute');
|
|
21
|
+
const { ExpandCache, renderExpandItem } = require('../core/expand-cache');
|
|
19
22
|
|
|
20
23
|
// ============================================================================
|
|
21
24
|
// ARGUMENT PARSING
|
|
@@ -183,14 +186,8 @@ function printOutput(result, jsonFn, textFn) {
|
|
|
183
186
|
// MAIN
|
|
184
187
|
// ============================================================================
|
|
185
188
|
|
|
186
|
-
// All valid commands -
|
|
187
|
-
const COMMANDS =
|
|
188
|
-
'toc', 'find', 'usages', 'fn', 'class', 'lines', 'search', 'typedef', 'api',
|
|
189
|
-
'context', 'smart', 'about', 'impact', 'trace', 'related', 'example', 'expand',
|
|
190
|
-
'tests', 'verify', 'plan', 'deadcode', 'stats', 'stacktrace', 'stack',
|
|
191
|
-
'imports', 'what-imports', 'exporters', 'who-imports', 'graph', 'file-exports', 'what-exports',
|
|
192
|
-
'diff-impact'
|
|
193
|
-
]);
|
|
189
|
+
// All valid commands - derived from canonical registry
|
|
190
|
+
const COMMANDS = getCliCommandSet();
|
|
194
191
|
|
|
195
192
|
function main() {
|
|
196
193
|
// Determine target and command based on positional args
|
|
@@ -360,16 +357,15 @@ function runFileCommand(filePath, command, arg) {
|
|
|
360
357
|
const projectRoot = findProjectRoot(path.dirname(filePath));
|
|
361
358
|
|
|
362
359
|
// For file-specific commands (imports/exporters/graph), use the target file as arg if no arg given
|
|
360
|
+
const fileCanonical = resolveCommand(command, 'cli') || command;
|
|
363
361
|
let effectiveArg = arg;
|
|
364
|
-
if ((
|
|
365
|
-
|
|
366
|
-
command === 'graph' || command === 'file-exports' ||
|
|
367
|
-
command === 'what-exports') && !arg) {
|
|
362
|
+
if ((fileCanonical === 'imports' || fileCanonical === 'exporters' ||
|
|
363
|
+
fileCanonical === 'fileExports' || fileCanonical === 'graph') && !arg) {
|
|
368
364
|
effectiveArg = filePath;
|
|
369
365
|
}
|
|
370
366
|
|
|
371
367
|
// For stats/deadcode, no arg needed
|
|
372
|
-
if (
|
|
368
|
+
if (fileCanonical === 'stats' || fileCanonical === 'deadcode') {
|
|
373
369
|
effectiveArg = arg; // may be undefined, that's ok
|
|
374
370
|
}
|
|
375
371
|
|
|
@@ -700,10 +696,17 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
700
696
|
}
|
|
701
697
|
}
|
|
702
698
|
|
|
703
|
-
|
|
699
|
+
try {
|
|
700
|
+
// Resolve CLI aliases to canonical command names — dispatch on canonical
|
|
701
|
+
const canonical = resolveCommand(command, 'cli') || command;
|
|
702
|
+
|
|
703
|
+
switch (canonical) {
|
|
704
|
+
// ── Commands using shared executor ───────────────────────────────
|
|
705
|
+
|
|
704
706
|
case 'toc': {
|
|
705
|
-
const
|
|
706
|
-
|
|
707
|
+
const { ok, result, error } = execute(index, 'toc', flags);
|
|
708
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
709
|
+
printOutput(result, output.formatTocJson, r => output.formatToc(r, {
|
|
707
710
|
detailedHint: 'Add --detailed to list all functions, or "ucn . about <name>" for full details on a symbol',
|
|
708
711
|
uncertainHint: 'use --include-uncertain to include all'
|
|
709
712
|
}));
|
|
@@ -711,15 +714,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
711
714
|
}
|
|
712
715
|
|
|
713
716
|
case 'find': {
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
file: flags.file,
|
|
718
|
-
exact: flags.exact,
|
|
719
|
-
exclude: findExclude,
|
|
720
|
-
in: flags.in
|
|
721
|
-
});
|
|
722
|
-
printOutput(found,
|
|
717
|
+
const { ok, result, error } = execute(index, 'find', { name: arg, ...flags });
|
|
718
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
719
|
+
printOutput(result,
|
|
723
720
|
r => output.formatSymbolJson(r, arg),
|
|
724
721
|
r => { printSymbols(r, arg, { depth: flags.depth, top: flags.top, all: flags.all }); }
|
|
725
722
|
);
|
|
@@ -727,15 +724,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
727
724
|
}
|
|
728
725
|
|
|
729
726
|
case 'usages': {
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
codeOnly: flags.codeOnly,
|
|
734
|
-
context: flags.context,
|
|
735
|
-
exclude: usagesExclude,
|
|
736
|
-
in: flags.in
|
|
737
|
-
});
|
|
738
|
-
printOutput(usages,
|
|
727
|
+
const { ok, result, error } = execute(index, 'usages', { name: arg, ...flags });
|
|
728
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
729
|
+
printOutput(result,
|
|
739
730
|
r => output.formatUsagesJson(r, arg),
|
|
740
731
|
r => output.formatUsages(r, arg)
|
|
741
732
|
);
|
|
@@ -743,9 +734,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
743
734
|
}
|
|
744
735
|
|
|
745
736
|
case 'example': {
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
printOutput(
|
|
737
|
+
const { ok, result, error } = execute(index, 'example', { name: arg });
|
|
738
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
739
|
+
printOutput(result,
|
|
749
740
|
r => output.formatExampleJson(r, arg),
|
|
750
741
|
r => output.formatExample(r, arg)
|
|
751
742
|
);
|
|
@@ -753,17 +744,8 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
753
744
|
}
|
|
754
745
|
|
|
755
746
|
case 'context': {
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
includeMethods: flags.includeMethods,
|
|
759
|
-
includeUncertain: flags.includeUncertain,
|
|
760
|
-
file: flags.file,
|
|
761
|
-
exclude: flags.exclude
|
|
762
|
-
});
|
|
763
|
-
if (!ctx) {
|
|
764
|
-
console.log(`Symbol "${arg}" not found.`);
|
|
765
|
-
break;
|
|
766
|
-
}
|
|
747
|
+
const { ok, result: ctx, error } = execute(index, 'context', { name: arg, ...flags });
|
|
748
|
+
if (!ok) { console.log(error); break; }
|
|
767
749
|
if (flags.json) {
|
|
768
750
|
console.log(output.formatContextJson(ctx));
|
|
769
751
|
} else {
|
|
@@ -825,27 +807,18 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
825
807
|
}
|
|
826
808
|
|
|
827
809
|
case 'smart': {
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
includeUncertain: flags.includeUncertain
|
|
834
|
-
});
|
|
835
|
-
if (smart) {
|
|
836
|
-
printOutput(smart, output.formatSmartJson, r => output.formatSmart(r, {
|
|
837
|
-
uncertainHint: 'use --include-uncertain to include all'
|
|
838
|
-
}));
|
|
839
|
-
} else {
|
|
840
|
-
console.error(`Function "${arg}" not found`);
|
|
841
|
-
}
|
|
810
|
+
const { ok, result, error } = execute(index, 'smart', { name: arg, ...flags });
|
|
811
|
+
if (!ok) { console.error(error); break; }
|
|
812
|
+
printOutput(result, output.formatSmartJson, r => output.formatSmart(r, {
|
|
813
|
+
uncertainHint: 'use --include-uncertain to include all'
|
|
814
|
+
}));
|
|
842
815
|
break;
|
|
843
816
|
}
|
|
844
817
|
|
|
845
818
|
case 'about': {
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
printOutput(
|
|
819
|
+
const { ok, result, error } = execute(index, 'about', { name: arg, ...flags });
|
|
820
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
821
|
+
printOutput(result,
|
|
849
822
|
output.formatAboutJson,
|
|
850
823
|
r => output.formatAbout(r, { expand: flags.expand, root: index.root, depth: flags.depth })
|
|
851
824
|
);
|
|
@@ -853,63 +826,51 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
853
826
|
}
|
|
854
827
|
|
|
855
828
|
case 'impact': {
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
printOutput(
|
|
829
|
+
const { ok, result, error } = execute(index, 'impact', { name: arg, ...flags });
|
|
830
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
831
|
+
printOutput(result, output.formatImpactJson, output.formatImpact);
|
|
859
832
|
break;
|
|
860
833
|
}
|
|
861
834
|
|
|
862
835
|
case 'plan': {
|
|
863
|
-
|
|
864
|
-
if (!
|
|
865
|
-
|
|
866
|
-
process.exit(1);
|
|
867
|
-
}
|
|
868
|
-
const planResult = index.plan(arg, {
|
|
869
|
-
addParam: flags.addParam,
|
|
870
|
-
removeParam: flags.removeParam,
|
|
871
|
-
renameTo: flags.renameTo,
|
|
872
|
-
defaultValue: flags.defaultValue,
|
|
873
|
-
file: flags.file
|
|
874
|
-
});
|
|
875
|
-
printOutput(planResult, output.formatPlanJson, output.formatPlan);
|
|
836
|
+
const { ok, result, error } = execute(index, 'plan', { name: arg, ...flags });
|
|
837
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
838
|
+
printOutput(result, output.formatPlanJson, output.formatPlan);
|
|
876
839
|
break;
|
|
877
840
|
}
|
|
878
841
|
|
|
879
842
|
case 'trace': {
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
const traceResult = index.trace(arg, { depth: traceDepth, file: flags.file, all: flags.all || depthExplicit, includeMethods: flags.includeMethods, includeUncertain: flags.includeUncertain });
|
|
884
|
-
printOutput(traceResult, output.formatTraceJson, output.formatTrace);
|
|
843
|
+
const { ok, result, error } = execute(index, 'trace', { name: arg, ...flags });
|
|
844
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
845
|
+
printOutput(result, output.formatTraceJson, output.formatTrace);
|
|
885
846
|
break;
|
|
886
847
|
}
|
|
887
848
|
|
|
888
|
-
case 'stacktrace':
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
printOutput(stackResult, output.formatStackTraceJson, output.formatStackTrace);
|
|
849
|
+
case 'stacktrace': {
|
|
850
|
+
const { ok, result, error } = execute(index, 'stacktrace', { stack: arg });
|
|
851
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
852
|
+
printOutput(result, output.formatStackTraceJson, output.formatStackTrace);
|
|
893
853
|
break;
|
|
894
854
|
}
|
|
895
855
|
|
|
896
856
|
case 'verify': {
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
printOutput(
|
|
857
|
+
const { ok, result, error } = execute(index, 'verify', { name: arg, file: flags.file });
|
|
858
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
859
|
+
printOutput(result, output.formatVerifyJson, output.formatVerify);
|
|
900
860
|
break;
|
|
901
861
|
}
|
|
902
862
|
|
|
903
863
|
case 'related': {
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
printOutput(
|
|
864
|
+
const { ok, result, error } = execute(index, 'related', { name: arg, ...flags });
|
|
865
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
866
|
+
printOutput(result, output.formatRelatedJson, r => output.formatRelated(r, { showAll: flags.all, top: flags.top }));
|
|
907
867
|
break;
|
|
908
868
|
}
|
|
909
869
|
|
|
870
|
+
// ── Commands staying in adapter (complex I/O) ───────────────────
|
|
871
|
+
|
|
910
872
|
case 'fn': {
|
|
911
873
|
requireArg(arg, 'Usage: ucn . fn <name>');
|
|
912
|
-
// Support comma-separated names for bulk extraction
|
|
913
874
|
if (arg.includes(',')) {
|
|
914
875
|
const fnNames = arg.split(',').map(n => n.trim()).filter(Boolean);
|
|
915
876
|
for (let i = 0; i < fnNames.length; i++) {
|
|
@@ -928,32 +889,73 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
928
889
|
break;
|
|
929
890
|
}
|
|
930
891
|
|
|
931
|
-
case '
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
892
|
+
case 'lines': {
|
|
893
|
+
if (!arg || !flags.file) {
|
|
894
|
+
console.error('Usage: ucn . lines <range> --file <path>');
|
|
895
|
+
process.exit(1);
|
|
896
|
+
}
|
|
897
|
+
const filePath = index.findFile(flags.file);
|
|
898
|
+
if (!filePath) {
|
|
899
|
+
console.error(`File not found: ${flags.file}`);
|
|
900
|
+
process.exit(1);
|
|
901
|
+
}
|
|
902
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
903
|
+
printLines(fileContent.split('\n'), arg);
|
|
904
|
+
break;
|
|
905
|
+
}
|
|
906
|
+
|
|
907
|
+
// ── File dependency commands ────────────────────────────────────
|
|
908
|
+
|
|
909
|
+
case 'imports': {
|
|
910
|
+
const { ok, result, error } = execute(index, 'imports', { file: arg });
|
|
911
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
912
|
+
printOutput(result,
|
|
936
913
|
r => output.formatImportsJson(r, arg),
|
|
937
914
|
r => output.formatImports(r, arg)
|
|
938
915
|
);
|
|
939
916
|
break;
|
|
940
917
|
}
|
|
941
918
|
|
|
942
|
-
case 'exporters':
|
|
943
|
-
|
|
944
|
-
|
|
945
|
-
|
|
946
|
-
printOutput(exporters,
|
|
919
|
+
case 'exporters': {
|
|
920
|
+
const { ok, result, error } = execute(index, 'exporters', { file: arg });
|
|
921
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
922
|
+
printOutput(result,
|
|
947
923
|
r => output.formatExportersJson(r, arg),
|
|
948
924
|
r => output.formatExporters(r, arg)
|
|
949
925
|
);
|
|
950
926
|
break;
|
|
951
927
|
}
|
|
952
928
|
|
|
929
|
+
case 'fileExports': {
|
|
930
|
+
const { ok, result, error } = execute(index, 'fileExports', { file: arg });
|
|
931
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
932
|
+
printOutput(result,
|
|
933
|
+
r => JSON.stringify({ file: arg, exports: r }, null, 2),
|
|
934
|
+
r => output.formatFileExports(r, arg)
|
|
935
|
+
);
|
|
936
|
+
break;
|
|
937
|
+
}
|
|
938
|
+
|
|
939
|
+
case 'graph': {
|
|
940
|
+
const { ok, result, error } = execute(index, 'graph', { file: arg, direction: flags.direction, depth: flags.depth, all: flags.all });
|
|
941
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
942
|
+
printOutput(result,
|
|
943
|
+
r => JSON.stringify({
|
|
944
|
+
root: path.relative(index.root, r.root),
|
|
945
|
+
nodes: r.nodes.map(n => ({ file: n.relativePath, depth: n.depth })),
|
|
946
|
+
edges: r.edges.map(e => ({ from: path.relative(index.root, e.from), to: path.relative(index.root, e.to) }))
|
|
947
|
+
}, null, 2),
|
|
948
|
+
r => output.formatGraph(r, { showAll: flags.all || flags.depth !== undefined, maxDepth: flags.depth ?? 2, file: arg })
|
|
949
|
+
);
|
|
950
|
+
break;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
// ── Remaining commands ──────────────────────────────────────────
|
|
954
|
+
|
|
953
955
|
case 'typedef': {
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
printOutput(
|
|
956
|
+
const { ok, result, error } = execute(index, 'typedef', { name: arg, exact: flags.exact });
|
|
957
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
958
|
+
printOutput(result,
|
|
957
959
|
r => output.formatTypedefJson(r, arg),
|
|
958
960
|
r => output.formatTypedef(r, arg)
|
|
959
961
|
);
|
|
@@ -961,9 +963,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
961
963
|
}
|
|
962
964
|
|
|
963
965
|
case 'tests': {
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
printOutput(
|
|
966
|
+
const { ok, result, error } = execute(index, 'tests', { name: arg, callsOnly: flags.callsOnly });
|
|
967
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
968
|
+
printOutput(result,
|
|
967
969
|
r => output.formatTestsJson(r, arg),
|
|
968
970
|
r => output.formatTests(r, arg)
|
|
969
971
|
);
|
|
@@ -971,110 +973,65 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
971
973
|
}
|
|
972
974
|
|
|
973
975
|
case 'api': {
|
|
974
|
-
const
|
|
975
|
-
|
|
976
|
+
const { ok, result, error } = execute(index, 'api', { file: arg });
|
|
977
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
978
|
+
printOutput(result,
|
|
976
979
|
r => output.formatApiJson(r, arg),
|
|
977
980
|
r => output.formatApi(r, arg)
|
|
978
981
|
);
|
|
979
982
|
break;
|
|
980
983
|
}
|
|
981
984
|
|
|
982
|
-
case '
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
r =>
|
|
988
|
-
r => output.formatFileExports(r, arg)
|
|
985
|
+
case 'search': {
|
|
986
|
+
const { ok, result, error } = execute(index, 'search', { term: arg, ...flags });
|
|
987
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
988
|
+
printOutput(result,
|
|
989
|
+
r => output.formatSearchJson(r, arg),
|
|
990
|
+
r => output.formatSearch(r, arg)
|
|
989
991
|
);
|
|
990
992
|
break;
|
|
991
993
|
}
|
|
992
994
|
|
|
993
995
|
case 'deadcode': {
|
|
994
|
-
const
|
|
995
|
-
|
|
996
|
-
|
|
997
|
-
includeTests: flags.includeTests,
|
|
998
|
-
exclude: flags.exclude,
|
|
999
|
-
in: flags.in || subdirScope
|
|
1000
|
-
});
|
|
1001
|
-
printOutput(deadcodeResults,
|
|
996
|
+
const { ok, result, error } = execute(index, 'deadcode', { ...flags, in: flags.in || subdirScope });
|
|
997
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
998
|
+
printOutput(result,
|
|
1002
999
|
output.formatDeadcodeJson,
|
|
1003
1000
|
r => output.formatDeadcode(r, {
|
|
1004
1001
|
top: flags.top,
|
|
1005
|
-
decoratedHint: !flags.includeDecorated &&
|
|
1006
|
-
exportedHint: !flags.includeExported &&
|
|
1002
|
+
decoratedHint: !flags.includeDecorated && result.excludedDecorated > 0 ? `${result.excludedDecorated} decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.` : undefined,
|
|
1003
|
+
exportedHint: !flags.includeExported && result.excludedExported > 0 ? `${result.excludedExported} exported symbol(s) excluded (all have callers). Use --include-exported to audit them.` : undefined
|
|
1007
1004
|
})
|
|
1008
1005
|
);
|
|
1009
1006
|
break;
|
|
1010
1007
|
}
|
|
1011
1008
|
|
|
1012
|
-
case 'graph': {
|
|
1013
|
-
requireArg(arg, 'Usage: ucn . graph <file>');
|
|
1014
|
-
const graphDepth = flags.depth ?? 2; // Default to 2 for cleaner output
|
|
1015
|
-
const graphDirection = flags.direction || 'both';
|
|
1016
|
-
const graphResult = index.graph(arg, { direction: graphDirection, maxDepth: graphDepth });
|
|
1017
|
-
printOutput(graphResult,
|
|
1018
|
-
r => JSON.stringify({
|
|
1019
|
-
root: path.relative(index.root, r.root),
|
|
1020
|
-
nodes: r.nodes.map(n => ({ file: n.relativePath, depth: n.depth })),
|
|
1021
|
-
edges: r.edges.map(e => ({ from: path.relative(index.root, e.from), to: path.relative(index.root, e.to) }))
|
|
1022
|
-
}, null, 2),
|
|
1023
|
-
r => output.formatGraph(r, { showAll: flags.all || flags.depth !== undefined, maxDepth: graphDepth, file: arg })
|
|
1024
|
-
);
|
|
1025
|
-
break;
|
|
1026
|
-
}
|
|
1027
|
-
|
|
1028
|
-
case 'search': {
|
|
1029
|
-
requireArg(arg, 'Usage: ucn . search <term>');
|
|
1030
|
-
const searchExclude = flags.includeTests ? flags.exclude : addTestExclusions(flags.exclude);
|
|
1031
|
-
const searchResults = index.search(arg, { codeOnly: flags.codeOnly, context: flags.context, caseSensitive: flags.caseSensitive, exclude: searchExclude, in: flags.in, regex: flags.regex });
|
|
1032
|
-
printOutput(searchResults,
|
|
1033
|
-
r => output.formatSearchJson(r, arg),
|
|
1034
|
-
r => output.formatSearch(r, arg)
|
|
1035
|
-
);
|
|
1036
|
-
break;
|
|
1037
|
-
}
|
|
1038
|
-
|
|
1039
|
-
case 'lines': {
|
|
1040
|
-
if (!arg || !flags.file) {
|
|
1041
|
-
console.error('Usage: ucn . lines <range> --file <path>');
|
|
1042
|
-
process.exit(1);
|
|
1043
|
-
}
|
|
1044
|
-
const filePath = index.findFile(flags.file);
|
|
1045
|
-
if (!filePath) {
|
|
1046
|
-
console.error(`File not found: ${flags.file}`);
|
|
1047
|
-
process.exit(1);
|
|
1048
|
-
}
|
|
1049
|
-
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
1050
|
-
printLines(fileContent.split('\n'), arg);
|
|
1051
|
-
break;
|
|
1052
|
-
}
|
|
1053
|
-
|
|
1054
1009
|
case 'stats': {
|
|
1055
|
-
const
|
|
1056
|
-
|
|
1010
|
+
const { ok, result, error } = execute(index, 'stats', { functions: flags.functions });
|
|
1011
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
1012
|
+
printOutput(result,
|
|
1057
1013
|
output.formatStatsJson,
|
|
1058
1014
|
r => output.formatStats(r, { top: flags.top })
|
|
1059
1015
|
);
|
|
1060
1016
|
break;
|
|
1061
1017
|
}
|
|
1062
1018
|
|
|
1063
|
-
case '
|
|
1064
|
-
const
|
|
1065
|
-
|
|
1066
|
-
|
|
1067
|
-
file: flags.file
|
|
1068
|
-
});
|
|
1069
|
-
printOutput(diffResult, output.formatDiffImpactJson, output.formatDiffImpact);
|
|
1019
|
+
case 'diffImpact': {
|
|
1020
|
+
const { ok, result, error } = execute(index, 'diffImpact', { base: flags.base, staged: flags.staged, file: flags.file });
|
|
1021
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
1022
|
+
printOutput(result, output.formatDiffImpactJson, output.formatDiffImpact);
|
|
1070
1023
|
break;
|
|
1071
1024
|
}
|
|
1072
1025
|
|
|
1073
1026
|
default:
|
|
1074
|
-
console.error(`Unknown command: ${
|
|
1027
|
+
console.error(`Unknown command: ${canonical}`);
|
|
1075
1028
|
printUsage();
|
|
1076
1029
|
process.exit(1);
|
|
1077
1030
|
}
|
|
1031
|
+
} catch (e) {
|
|
1032
|
+
console.error(`Error: ${e.message}`);
|
|
1033
|
+
process.exit(1);
|
|
1034
|
+
}
|
|
1078
1035
|
}
|
|
1079
1036
|
|
|
1080
1037
|
function extractFunctionFromProject(index, name, overrideFlags) {
|
|
@@ -1745,6 +1702,8 @@ UNDERSTAND CODE (UCN's strength - semantic analysis)
|
|
|
1745
1702
|
smart <name> Function + all dependencies inline
|
|
1746
1703
|
impact <name> What breaks if changed (call sites grouped by file)
|
|
1747
1704
|
trace <name> Call tree visualization (--depth=N expands all children)
|
|
1705
|
+
related <name> Find similar functions (same file, shared deps)
|
|
1706
|
+
example <name> Best usage example with context
|
|
1748
1707
|
|
|
1749
1708
|
═══════════════════════════════════════════════════════════════════════════════
|
|
1750
1709
|
FIND CODE
|
|
@@ -1778,7 +1737,6 @@ REFACTORING HELPERS
|
|
|
1778
1737
|
verify <name> Check all call sites match signature
|
|
1779
1738
|
diff-impact What changed in git diff and who calls it (--base, --staged)
|
|
1780
1739
|
deadcode Find unused functions/classes
|
|
1781
|
-
related <name> Find similar functions (same file, shared deps)
|
|
1782
1740
|
|
|
1783
1741
|
═══════════════════════════════════════════════════════════════════════════════
|
|
1784
1742
|
OTHER
|
|
@@ -1787,7 +1745,6 @@ OTHER
|
|
|
1787
1745
|
typedef <name> Find type definitions
|
|
1788
1746
|
stats Project statistics (--functions for per-function line counts)
|
|
1789
1747
|
stacktrace <text> Parse stack trace, show code at each frame (alias: stack)
|
|
1790
|
-
example <name> Best usage example with context
|
|
1791
1748
|
|
|
1792
1749
|
Common Flags:
|
|
1793
1750
|
--file <pattern> Filter by file path (e.g., --file=routes)
|
|
@@ -1812,6 +1769,8 @@ Common Flags:
|
|
|
1812
1769
|
--calls-only Only show call/test-case matches (tests)
|
|
1813
1770
|
--case-sensitive Case-sensitive text search (search)
|
|
1814
1771
|
--detailed List all symbols in toc (compact by default)
|
|
1772
|
+
--top-level Show only top-level functions in toc
|
|
1773
|
+
--max-lines=N Max source lines for class (large classes show summary)
|
|
1815
1774
|
--no-cache Disable caching
|
|
1816
1775
|
--clear-cache Clear cache before running
|
|
1817
1776
|
--base=<ref> Git ref for diff-impact (default: HEAD)
|
|
@@ -1838,6 +1797,7 @@ function runInteractive(rootDir) {
|
|
|
1838
1797
|
console.log('Building index...');
|
|
1839
1798
|
const index = new ProjectIndex(rootDir);
|
|
1840
1799
|
index.build(null, { quiet: true });
|
|
1800
|
+
const iExpandCache = new ExpandCache({ maxSize: 20 });
|
|
1841
1801
|
console.log(`Index ready: ${index.files.size} files, ${index.symbols.size} symbols`);
|
|
1842
1802
|
console.log('Type commands (e.g., "find parseFile", "about main", "toc")');
|
|
1843
1803
|
console.log('Type "help" for commands, "quit" to exit\n');
|
|
@@ -1920,7 +1880,8 @@ Flags can be added per-command: context myFunc --include-methods
|
|
|
1920
1880
|
const iflags = parseInteractiveFlags(flagTokens);
|
|
1921
1881
|
|
|
1922
1882
|
try {
|
|
1923
|
-
|
|
1883
|
+
const iCanonical = resolveCommand(command, 'cli') || command;
|
|
1884
|
+
executeInteractiveCommand(index, iCanonical, arg, iflags, iExpandCache);
|
|
1924
1885
|
} catch (e) {
|
|
1925
1886
|
console.error(`Error: ${e.message}`);
|
|
1926
1887
|
}
|
|
@@ -1972,347 +1933,290 @@ function parseInteractiveFlags(tokens) {
|
|
|
1972
1933
|
};
|
|
1973
1934
|
}
|
|
1974
1935
|
|
|
1975
|
-
function executeInteractiveCommand(index, command, arg, iflags = {}) {
|
|
1936
|
+
function executeInteractiveCommand(index, command, arg, iflags = {}, cache = null) {
|
|
1976
1937
|
switch (command) {
|
|
1977
|
-
case 'toc': {
|
|
1978
|
-
const toc = index.getToc({ detailed: iflags.detailed, topLevel: iflags.topLevel, all: iflags.all, top: iflags.top });
|
|
1979
|
-
console.log(output.formatToc(toc, {
|
|
1980
|
-
detailedHint: 'Add --detailed to list all functions, or "about <name>" for full details on a symbol',
|
|
1981
|
-
uncertainHint: 'use --include-uncertain to include all'
|
|
1982
|
-
}));
|
|
1983
|
-
break;
|
|
1984
|
-
}
|
|
1985
1938
|
|
|
1986
|
-
|
|
1939
|
+
// ── Special commands (complex I/O, stay in adapter) ──────────────
|
|
1940
|
+
|
|
1941
|
+
case 'fn': {
|
|
1987
1942
|
if (!arg) {
|
|
1988
|
-
console.log('Usage:
|
|
1943
|
+
console.log('Usage: fn <name>[,name2,...] [--file=<pattern>]');
|
|
1989
1944
|
return;
|
|
1990
1945
|
}
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1946
|
+
// Support comma-separated names for bulk extraction
|
|
1947
|
+
if (arg.includes(',')) {
|
|
1948
|
+
const fnNames = arg.split(',').map(n => n.trim()).filter(Boolean);
|
|
1949
|
+
for (let i = 0; i < fnNames.length; i++) {
|
|
1950
|
+
if (i > 0) console.log('\n' + '═'.repeat(60) + '\n');
|
|
1951
|
+
extractFunctionFromProject(index, fnNames[i], iflags);
|
|
1952
|
+
}
|
|
1995
1953
|
} else {
|
|
1996
|
-
|
|
1954
|
+
extractFunctionFromProject(index, arg, iflags);
|
|
1997
1955
|
}
|
|
1998
1956
|
break;
|
|
1999
1957
|
}
|
|
2000
1958
|
|
|
2001
|
-
case '
|
|
1959
|
+
case 'class': {
|
|
2002
1960
|
if (!arg) {
|
|
2003
|
-
console.log('Usage:
|
|
1961
|
+
console.log('Usage: class <name> [--file=<pattern>]');
|
|
2004
1962
|
return;
|
|
2005
1963
|
}
|
|
2006
|
-
|
|
2007
|
-
console.log(output.formatAbout(aboutResult, { expand: iflags.expand, root: index.root, showAll: iflags.all }));
|
|
1964
|
+
extractClassFromProject(index, arg, iflags);
|
|
2008
1965
|
break;
|
|
2009
1966
|
}
|
|
2010
1967
|
|
|
2011
|
-
case '
|
|
2012
|
-
if (!arg) {
|
|
2013
|
-
console.log('Usage:
|
|
1968
|
+
case 'lines': {
|
|
1969
|
+
if (!arg || !iflags.file) {
|
|
1970
|
+
console.log('Usage: lines <range> --file=<file>');
|
|
2014
1971
|
return;
|
|
2015
1972
|
}
|
|
2016
|
-
const
|
|
2017
|
-
|
|
2018
|
-
|
|
1973
|
+
const filePath = index.findFile(iflags.file);
|
|
1974
|
+
if (!filePath) {
|
|
1975
|
+
console.log(`File not found: ${iflags.file}`);
|
|
1976
|
+
return;
|
|
1977
|
+
}
|
|
1978
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
1979
|
+
printLines(fileContent.split('\n'), arg);
|
|
2019
1980
|
break;
|
|
2020
1981
|
}
|
|
2021
1982
|
|
|
2022
|
-
case '
|
|
1983
|
+
case 'expand': {
|
|
2023
1984
|
if (!arg) {
|
|
2024
|
-
console.log('Usage:
|
|
1985
|
+
console.log('Usage: expand <number>');
|
|
2025
1986
|
return;
|
|
2026
1987
|
}
|
|
2027
|
-
const
|
|
2028
|
-
if (
|
|
2029
|
-
console.log(`
|
|
1988
|
+
const expandNum = parseInt(arg, 10);
|
|
1989
|
+
if (isNaN(expandNum)) {
|
|
1990
|
+
console.log(`Invalid item number: "${arg}"`);
|
|
1991
|
+
return;
|
|
1992
|
+
}
|
|
1993
|
+
if (cache) {
|
|
1994
|
+
const { match, itemCount } = cache.lookup(index.root, expandNum);
|
|
1995
|
+
if (!match && itemCount === 0) {
|
|
1996
|
+
console.log('No expandable items. Run context first.');
|
|
1997
|
+
return;
|
|
1998
|
+
}
|
|
1999
|
+
if (!match) {
|
|
2000
|
+
console.log(`Item ${expandNum} not found. Available: 1-${itemCount}`);
|
|
2001
|
+
return;
|
|
2002
|
+
}
|
|
2003
|
+
const rendered = renderExpandItem(match, index.root);
|
|
2004
|
+
if (!rendered.ok) { console.log(rendered.error); return; }
|
|
2005
|
+
console.log(rendered.text);
|
|
2030
2006
|
} else {
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2007
|
+
// Fallback to file-based cache (CLI one-shot)
|
|
2008
|
+
const cached = loadExpandableItems(index.root);
|
|
2009
|
+
if (!cached || !cached.items || cached.items.length === 0) {
|
|
2010
|
+
console.log('No expandable items. Run context first.');
|
|
2011
|
+
return;
|
|
2012
|
+
}
|
|
2013
|
+
const expandMatch = cached.items.find(i => i.num === expandNum);
|
|
2014
|
+
if (!expandMatch) {
|
|
2015
|
+
console.log(`Item ${expandNum} not found. Available: 1-${cached.items.length}`);
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
printExpandedItem(expandMatch, cached.root || index.root);
|
|
2038
2019
|
}
|
|
2039
2020
|
break;
|
|
2040
2021
|
}
|
|
2041
2022
|
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
}
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
console.log(output.formatSmart(smart, {
|
|
2050
|
-
uncertainHint: 'use --include-uncertain to include all'
|
|
2051
|
-
}));
|
|
2023
|
+
// ── find: uses printSymbols (interactive-only formatter) ─────────
|
|
2024
|
+
|
|
2025
|
+
case 'find': {
|
|
2026
|
+
const { ok, result, error } = execute(index, 'find', { name: arg, ...iflags });
|
|
2027
|
+
if (!ok) { console.log(error); return; }
|
|
2028
|
+
if (result.length === 0) {
|
|
2029
|
+
console.log(`No symbols found for "${arg}"`);
|
|
2052
2030
|
} else {
|
|
2053
|
-
|
|
2031
|
+
printSymbols(result, arg, { top: iflags.top });
|
|
2054
2032
|
}
|
|
2055
2033
|
break;
|
|
2056
2034
|
}
|
|
2057
2035
|
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2036
|
+
// ── context: needs expandable items cache ────────────────────────
|
|
2037
|
+
|
|
2038
|
+
case 'context': {
|
|
2039
|
+
const { ok, result, error } = execute(index, 'context', { name: arg, ...iflags });
|
|
2040
|
+
if (!ok) { console.log(error); return; }
|
|
2041
|
+
const { text, expandable } = output.formatContext(result, {
|
|
2042
|
+
methodsHint: 'Note: obj.method() calls excluded — use --include-methods to include them',
|
|
2043
|
+
expandHint: 'Use "expand <N>" to see code for item N',
|
|
2044
|
+
uncertainHint: 'use --include-uncertain to include all'
|
|
2045
|
+
});
|
|
2046
|
+
console.log(text);
|
|
2047
|
+
if (cache) {
|
|
2048
|
+
cache.save(index.root, arg, iflags.file, expandable);
|
|
2049
|
+
} else {
|
|
2050
|
+
saveExpandableItems(expandable, index.root);
|
|
2062
2051
|
}
|
|
2063
|
-
const impactResult = index.impact(arg, { file: iflags.file, exclude: iflags.exclude });
|
|
2064
|
-
console.log(output.formatImpact(impactResult));
|
|
2065
2052
|
break;
|
|
2066
2053
|
}
|
|
2067
2054
|
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
}
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
|
|
2055
|
+
// ── deadcode: needs result fields for hint construction ──────────
|
|
2056
|
+
|
|
2057
|
+
case 'deadcode': {
|
|
2058
|
+
const { ok, result, error } = execute(index, 'deadcode', iflags);
|
|
2059
|
+
if (!ok) { console.log(error); return; }
|
|
2060
|
+
console.log(output.formatDeadcode(result, {
|
|
2061
|
+
top: iflags.top,
|
|
2062
|
+
decoratedHint: !iflags.includeDecorated && result.excludedDecorated > 0 ? `${result.excludedDecorated} decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.` : undefined,
|
|
2063
|
+
exportedHint: !iflags.includeExported && result.excludedExported > 0 ? `${result.excludedExported} exported symbol(s) excluded (all have callers). Use --include-exported to audit them.` : undefined
|
|
2064
|
+
}));
|
|
2076
2065
|
break;
|
|
2077
2066
|
}
|
|
2078
2067
|
|
|
2079
|
-
|
|
2080
|
-
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
}
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
|
|
2088
|
-
if (i > 0) console.log('\n' + '═'.repeat(60) + '\n');
|
|
2089
|
-
extractFunctionFromProject(index, fnNames[i], iflags);
|
|
2090
|
-
}
|
|
2091
|
-
} else {
|
|
2092
|
-
extractFunctionFromProject(index, arg, iflags);
|
|
2093
|
-
}
|
|
2068
|
+
// ── Standard commands routed through execute() ───────────────────
|
|
2069
|
+
|
|
2070
|
+
case 'toc': {
|
|
2071
|
+
const { ok, result, error } = execute(index, 'toc', iflags);
|
|
2072
|
+
if (!ok) { console.log(error); return; }
|
|
2073
|
+
console.log(output.formatToc(result, {
|
|
2074
|
+
detailedHint: 'Add --detailed to list all functions, or "about <name>" for full details on a symbol',
|
|
2075
|
+
uncertainHint: 'use --include-uncertain to include all'
|
|
2076
|
+
}));
|
|
2094
2077
|
break;
|
|
2095
2078
|
}
|
|
2096
2079
|
|
|
2097
|
-
case '
|
|
2098
|
-
|
|
2099
|
-
|
|
2100
|
-
|
|
2101
|
-
}
|
|
2102
|
-
extractClassFromProject(index, arg, iflags);
|
|
2080
|
+
case 'about': {
|
|
2081
|
+
const { ok, result, error } = execute(index, 'about', { name: arg, ...iflags });
|
|
2082
|
+
if (!ok) { console.log(error); return; }
|
|
2083
|
+
console.log(output.formatAbout(result, { expand: iflags.expand, root: index.root, showAll: iflags.all }));
|
|
2103
2084
|
break;
|
|
2104
2085
|
}
|
|
2105
2086
|
|
|
2106
|
-
case '
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
}
|
|
2116
|
-
|
|
2117
|
-
|
|
2087
|
+
case 'usages': {
|
|
2088
|
+
const { ok, result, error } = execute(index, 'usages', { name: arg, ...iflags });
|
|
2089
|
+
if (!ok) { console.log(error); return; }
|
|
2090
|
+
console.log(output.formatUsages(result, arg));
|
|
2091
|
+
break;
|
|
2092
|
+
}
|
|
2093
|
+
|
|
2094
|
+
case 'smart': {
|
|
2095
|
+
const { ok, result, error } = execute(index, 'smart', { name: arg, ...iflags });
|
|
2096
|
+
if (!ok) { console.log(error); return; }
|
|
2097
|
+
console.log(output.formatSmart(result, {
|
|
2098
|
+
uncertainHint: 'use --include-uncertain to include all'
|
|
2099
|
+
}));
|
|
2100
|
+
break;
|
|
2101
|
+
}
|
|
2102
|
+
|
|
2103
|
+
case 'impact': {
|
|
2104
|
+
const { ok, result, error } = execute(index, 'impact', { name: arg, ...iflags });
|
|
2105
|
+
if (!ok) { console.log(error); return; }
|
|
2106
|
+
console.log(output.formatImpact(result));
|
|
2107
|
+
break;
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
case 'trace': {
|
|
2111
|
+
const { ok, result, error } = execute(index, 'trace', { name: arg, ...iflags });
|
|
2112
|
+
if (!ok) { console.log(error); return; }
|
|
2113
|
+
console.log(output.formatTrace(result));
|
|
2118
2114
|
break;
|
|
2119
2115
|
}
|
|
2120
2116
|
|
|
2121
2117
|
case 'graph': {
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
return;
|
|
2125
|
-
}
|
|
2118
|
+
const { ok, result, error } = execute(index, 'graph', { file: arg, ...iflags });
|
|
2119
|
+
if (!ok) { console.log(error); return; }
|
|
2126
2120
|
const graphDepth = iflags.depth ? parseInt(iflags.depth) : 2;
|
|
2127
|
-
|
|
2128
|
-
const graphResult = index.graph(arg, { direction: graphDirection, maxDepth: graphDepth });
|
|
2129
|
-
console.log(output.formatGraph(graphResult, { showAll: iflags.all || !!iflags.depth, maxDepth: graphDepth, file: arg }));
|
|
2121
|
+
console.log(output.formatGraph(result, { showAll: iflags.all || !!iflags.depth, maxDepth: graphDepth, file: arg }));
|
|
2130
2122
|
break;
|
|
2131
2123
|
}
|
|
2132
2124
|
|
|
2133
|
-
case '
|
|
2134
|
-
|
|
2135
|
-
if (!
|
|
2136
|
-
|
|
2137
|
-
return;
|
|
2138
|
-
}
|
|
2139
|
-
const fileExports = index.fileExports(arg);
|
|
2140
|
-
console.log(output.formatFileExports(fileExports, arg));
|
|
2125
|
+
case 'fileExports': {
|
|
2126
|
+
const { ok, result, error } = execute(index, 'fileExports', { file: arg });
|
|
2127
|
+
if (!ok) { console.log(error); return; }
|
|
2128
|
+
console.log(output.formatFileExports(result, arg));
|
|
2141
2129
|
break;
|
|
2142
2130
|
}
|
|
2143
2131
|
|
|
2144
|
-
case 'imports':
|
|
2145
|
-
|
|
2146
|
-
if (!
|
|
2147
|
-
|
|
2148
|
-
return;
|
|
2149
|
-
}
|
|
2150
|
-
const imports = index.imports(arg);
|
|
2151
|
-
console.log(output.formatImports(imports, arg));
|
|
2132
|
+
case 'imports': {
|
|
2133
|
+
const { ok, result, error } = execute(index, 'imports', { file: arg });
|
|
2134
|
+
if (!ok) { console.log(error); return; }
|
|
2135
|
+
console.log(output.formatImports(result, arg));
|
|
2152
2136
|
break;
|
|
2153
2137
|
}
|
|
2154
2138
|
|
|
2155
|
-
case 'exporters':
|
|
2156
|
-
|
|
2157
|
-
if (!
|
|
2158
|
-
|
|
2159
|
-
return;
|
|
2160
|
-
}
|
|
2161
|
-
const exporters = index.exporters(arg);
|
|
2162
|
-
console.log(output.formatExporters(exporters, arg));
|
|
2139
|
+
case 'exporters': {
|
|
2140
|
+
const { ok, result, error } = execute(index, 'exporters', { file: arg });
|
|
2141
|
+
if (!ok) { console.log(error); return; }
|
|
2142
|
+
console.log(output.formatExporters(result, arg));
|
|
2163
2143
|
break;
|
|
2164
2144
|
}
|
|
2165
2145
|
|
|
2166
2146
|
case 'tests': {
|
|
2167
|
-
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
}
|
|
2171
|
-
const tests = index.tests(arg, { callsOnly: iflags.callsOnly });
|
|
2172
|
-
console.log(output.formatTests(tests, arg));
|
|
2147
|
+
const { ok, result, error } = execute(index, 'tests', { name: arg, ...iflags });
|
|
2148
|
+
if (!ok) { console.log(error); return; }
|
|
2149
|
+
console.log(output.formatTests(result, arg));
|
|
2173
2150
|
break;
|
|
2174
2151
|
}
|
|
2175
2152
|
|
|
2176
2153
|
case 'search': {
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
}
|
|
2181
|
-
const searchExclude = iflags.includeTests ? iflags.exclude : addTestExclusions(iflags.exclude);
|
|
2182
|
-
const results = index.search(arg, { codeOnly: iflags.codeOnly, caseSensitive: iflags.caseSensitive, context: iflags.context, exclude: searchExclude, in: iflags.in, regex: iflags.regex });
|
|
2183
|
-
console.log(output.formatSearch(results, arg));
|
|
2154
|
+
const { ok, result, error } = execute(index, 'search', { term: arg, ...iflags });
|
|
2155
|
+
if (!ok) { console.log(error); return; }
|
|
2156
|
+
console.log(output.formatSearch(result, arg));
|
|
2184
2157
|
break;
|
|
2185
2158
|
}
|
|
2186
2159
|
|
|
2187
2160
|
case 'typedef': {
|
|
2188
|
-
|
|
2189
|
-
|
|
2190
|
-
|
|
2191
|
-
}
|
|
2192
|
-
const types = index.typedef(arg, { exact: iflags.exact });
|
|
2193
|
-
console.log(output.formatTypedef(types, arg));
|
|
2161
|
+
const { ok, result, error } = execute(index, 'typedef', { name: arg, ...iflags });
|
|
2162
|
+
if (!ok) { console.log(error); return; }
|
|
2163
|
+
console.log(output.formatTypedef(result, arg));
|
|
2194
2164
|
break;
|
|
2195
2165
|
}
|
|
2196
2166
|
|
|
2197
2167
|
case 'api': {
|
|
2198
|
-
const
|
|
2199
|
-
console.log(
|
|
2168
|
+
const { ok, result, error } = execute(index, 'api', { file: arg });
|
|
2169
|
+
if (!ok) { console.log(error); return; }
|
|
2170
|
+
console.log(output.formatApi(result, arg || '.'));
|
|
2200
2171
|
break;
|
|
2201
2172
|
}
|
|
2202
2173
|
|
|
2203
|
-
case '
|
|
2204
|
-
const
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
file: iflags.file
|
|
2208
|
-
});
|
|
2209
|
-
console.log(output.formatDiffImpact(diffResult));
|
|
2174
|
+
case 'diffImpact': {
|
|
2175
|
+
const { ok, result, error } = execute(index, 'diffImpact', iflags);
|
|
2176
|
+
if (!ok) { console.log(error); return; }
|
|
2177
|
+
console.log(output.formatDiffImpact(result));
|
|
2210
2178
|
break;
|
|
2211
2179
|
}
|
|
2212
2180
|
|
|
2213
2181
|
case 'stats': {
|
|
2214
|
-
const
|
|
2215
|
-
console.log(
|
|
2216
|
-
|
|
2217
|
-
}
|
|
2218
|
-
|
|
2219
|
-
case 'expand': {
|
|
2220
|
-
if (!arg) {
|
|
2221
|
-
console.log('Usage: expand <number>');
|
|
2222
|
-
return;
|
|
2223
|
-
}
|
|
2224
|
-
const expandNum = parseInt(arg, 10);
|
|
2225
|
-
if (isNaN(expandNum)) {
|
|
2226
|
-
console.log(`Invalid item number: "${arg}"`);
|
|
2227
|
-
return;
|
|
2228
|
-
}
|
|
2229
|
-
const cached = loadExpandableItems(index.root);
|
|
2230
|
-
if (!cached || !cached.items || cached.items.length === 0) {
|
|
2231
|
-
console.log('No expandable items. Run context first.');
|
|
2232
|
-
return;
|
|
2233
|
-
}
|
|
2234
|
-
const expandMatch = cached.items.find(i => i.num === expandNum);
|
|
2235
|
-
if (!expandMatch) {
|
|
2236
|
-
console.log(`Item ${expandNum} not found. Available: 1-${cached.items.length}`);
|
|
2237
|
-
return;
|
|
2238
|
-
}
|
|
2239
|
-
printExpandedItem(expandMatch, cached.root || index.root);
|
|
2240
|
-
break;
|
|
2241
|
-
}
|
|
2242
|
-
|
|
2243
|
-
case 'deadcode': {
|
|
2244
|
-
const deadResult = index.deadcode({
|
|
2245
|
-
includeExported: iflags.includeExported,
|
|
2246
|
-
includeDecorated: iflags.includeDecorated,
|
|
2247
|
-
includeTests: iflags.includeTests,
|
|
2248
|
-
exclude: iflags.exclude,
|
|
2249
|
-
in: iflags.in
|
|
2250
|
-
});
|
|
2251
|
-
console.log(output.formatDeadcode(deadResult, {
|
|
2252
|
-
top: iflags.top,
|
|
2253
|
-
decoratedHint: !iflags.includeDecorated && deadResult.excludedDecorated > 0 ? `${deadResult.excludedDecorated} decorated/annotated symbol(s) hidden (framework-registered). Use --include-decorated to include them.` : undefined,
|
|
2254
|
-
exportedHint: !iflags.includeExported && deadResult.excludedExported > 0 ? `${deadResult.excludedExported} exported symbol(s) excluded (all have callers). Use --include-exported to audit them.` : undefined
|
|
2255
|
-
}));
|
|
2182
|
+
const { ok, result, error } = execute(index, 'stats', iflags);
|
|
2183
|
+
if (!ok) { console.log(error); return; }
|
|
2184
|
+
console.log(output.formatStats(result, { top: iflags.top }));
|
|
2256
2185
|
break;
|
|
2257
2186
|
}
|
|
2258
2187
|
|
|
2259
2188
|
case 'related': {
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
}
|
|
2264
|
-
const relResult = index.related(arg, { file: iflags.file, top: iflags.top, all: iflags.all });
|
|
2265
|
-
console.log(output.formatRelated(relResult, { showAll: iflags.all, top: iflags.top }));
|
|
2189
|
+
const { ok, result, error } = execute(index, 'related', { name: arg, ...iflags });
|
|
2190
|
+
if (!ok) { console.log(error); return; }
|
|
2191
|
+
console.log(output.formatRelated(result, { showAll: iflags.all, top: iflags.top }));
|
|
2266
2192
|
break;
|
|
2267
2193
|
}
|
|
2268
2194
|
|
|
2269
2195
|
case 'example': {
|
|
2270
|
-
|
|
2271
|
-
|
|
2272
|
-
|
|
2273
|
-
}
|
|
2274
|
-
console.log(output.formatExample(index.example(arg), arg));
|
|
2196
|
+
const { ok, result, error } = execute(index, 'example', { name: arg });
|
|
2197
|
+
if (!ok) { console.log(error); return; }
|
|
2198
|
+
console.log(output.formatExample(result, arg));
|
|
2275
2199
|
break;
|
|
2276
2200
|
}
|
|
2277
2201
|
|
|
2278
2202
|
case 'plan': {
|
|
2279
|
-
|
|
2280
|
-
|
|
2281
|
-
|
|
2282
|
-
}
|
|
2283
|
-
if (!iflags.addParam && !iflags.removeParam && !iflags.renameTo) {
|
|
2284
|
-
console.log('Plan requires an operation: --add-param, --remove-param, or --rename-to');
|
|
2285
|
-
return;
|
|
2286
|
-
}
|
|
2287
|
-
const planResult = index.plan(arg, {
|
|
2288
|
-
addParam: iflags.addParam,
|
|
2289
|
-
removeParam: iflags.removeParam,
|
|
2290
|
-
renameTo: iflags.renameTo,
|
|
2291
|
-
defaultValue: iflags.defaultValue,
|
|
2292
|
-
file: iflags.file
|
|
2293
|
-
});
|
|
2294
|
-
console.log(output.formatPlan(planResult));
|
|
2203
|
+
const { ok, result, error } = execute(index, 'plan', { name: arg, ...iflags });
|
|
2204
|
+
if (!ok) { console.log(error); return; }
|
|
2205
|
+
console.log(output.formatPlan(result));
|
|
2295
2206
|
break;
|
|
2296
2207
|
}
|
|
2297
2208
|
|
|
2298
2209
|
case 'verify': {
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
}
|
|
2303
|
-
const verifyResult = index.verify(arg, { file: iflags.file });
|
|
2304
|
-
console.log(output.formatVerify(verifyResult));
|
|
2210
|
+
const { ok, result, error } = execute(index, 'verify', { name: arg, ...iflags });
|
|
2211
|
+
if (!ok) { console.log(error); return; }
|
|
2212
|
+
console.log(output.formatVerify(result));
|
|
2305
2213
|
break;
|
|
2306
2214
|
}
|
|
2307
2215
|
|
|
2308
|
-
case 'stacktrace':
|
|
2309
|
-
|
|
2310
|
-
if (!
|
|
2311
|
-
|
|
2312
|
-
return;
|
|
2313
|
-
}
|
|
2314
|
-
const stackResult = index.parseStackTrace(arg);
|
|
2315
|
-
console.log(output.formatStackTrace(stackResult));
|
|
2216
|
+
case 'stacktrace': {
|
|
2217
|
+
const { ok, result, error } = execute(index, 'stacktrace', { stack: arg });
|
|
2218
|
+
if (!ok) { console.log(error); return; }
|
|
2219
|
+
console.log(output.formatStackTrace(result));
|
|
2316
2220
|
break;
|
|
2317
2221
|
}
|
|
2318
2222
|
|