ucn 3.7.17 → 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 +380 -421
- 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 +181 -315
- package/package.json +2 -2
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
|
|
@@ -86,7 +89,9 @@ const flags = {
|
|
|
86
89
|
// Regex search mode (default: ON; --no-regex to force plain text)
|
|
87
90
|
regex: args.includes('--no-regex') ? false : undefined,
|
|
88
91
|
// Stats: per-function line counts
|
|
89
|
-
functions: args.includes('--functions')
|
|
92
|
+
functions: args.includes('--functions'),
|
|
93
|
+
// Class: max lines to show (0 = no limit)
|
|
94
|
+
maxLines: parseInt(args.find(a => a.startsWith('--max-lines='))?.split('=')[1] || '0') || null
|
|
90
95
|
};
|
|
91
96
|
|
|
92
97
|
// Handle --file flag with space
|
|
@@ -106,7 +111,8 @@ const knownFlags = new Set([
|
|
|
106
111
|
'--depth', '--direction', '--add-param', '--remove-param', '--rename-to',
|
|
107
112
|
'--default', '--top', '--no-follow-symlinks',
|
|
108
113
|
'--base', '--staged',
|
|
109
|
-
'--regex', '--no-regex', '--functions'
|
|
114
|
+
'--regex', '--no-regex', '--functions',
|
|
115
|
+
'--max-lines'
|
|
110
116
|
]);
|
|
111
117
|
|
|
112
118
|
// Handle help flag
|
|
@@ -180,14 +186,8 @@ function printOutput(result, jsonFn, textFn) {
|
|
|
180
186
|
// MAIN
|
|
181
187
|
// ============================================================================
|
|
182
188
|
|
|
183
|
-
// All valid commands -
|
|
184
|
-
const COMMANDS =
|
|
185
|
-
'toc', 'find', 'usages', 'fn', 'class', 'lines', 'search', 'typedef', 'api',
|
|
186
|
-
'context', 'smart', 'about', 'impact', 'trace', 'related', 'example', 'expand',
|
|
187
|
-
'tests', 'verify', 'plan', 'deadcode', 'stats', 'stacktrace', 'stack',
|
|
188
|
-
'imports', 'what-imports', 'exporters', 'who-imports', 'graph', 'file-exports', 'what-exports',
|
|
189
|
-
'diff-impact'
|
|
190
|
-
]);
|
|
189
|
+
// All valid commands - derived from canonical registry
|
|
190
|
+
const COMMANDS = getCliCommandSet();
|
|
191
191
|
|
|
192
192
|
function main() {
|
|
193
193
|
// Determine target and command based on positional args
|
|
@@ -357,16 +357,15 @@ function runFileCommand(filePath, command, arg) {
|
|
|
357
357
|
const projectRoot = findProjectRoot(path.dirname(filePath));
|
|
358
358
|
|
|
359
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;
|
|
360
361
|
let effectiveArg = arg;
|
|
361
|
-
if ((
|
|
362
|
-
|
|
363
|
-
command === 'graph' || command === 'file-exports' ||
|
|
364
|
-
command === 'what-exports') && !arg) {
|
|
362
|
+
if ((fileCanonical === 'imports' || fileCanonical === 'exporters' ||
|
|
363
|
+
fileCanonical === 'fileExports' || fileCanonical === 'graph') && !arg) {
|
|
365
364
|
effectiveArg = filePath;
|
|
366
365
|
}
|
|
367
366
|
|
|
368
367
|
// For stats/deadcode, no arg needed
|
|
369
|
-
if (
|
|
368
|
+
if (fileCanonical === 'stats' || fileCanonical === 'deadcode') {
|
|
370
369
|
effectiveArg = arg; // may be undefined, that's ok
|
|
371
370
|
}
|
|
372
371
|
|
|
@@ -697,10 +696,17 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
697
696
|
}
|
|
698
697
|
}
|
|
699
698
|
|
|
700
|
-
|
|
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
|
+
|
|
701
706
|
case 'toc': {
|
|
702
|
-
const
|
|
703
|
-
|
|
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, {
|
|
704
710
|
detailedHint: 'Add --detailed to list all functions, or "ucn . about <name>" for full details on a symbol',
|
|
705
711
|
uncertainHint: 'use --include-uncertain to include all'
|
|
706
712
|
}));
|
|
@@ -708,15 +714,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
708
714
|
}
|
|
709
715
|
|
|
710
716
|
case 'find': {
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
file: flags.file,
|
|
715
|
-
exact: flags.exact,
|
|
716
|
-
exclude: findExclude,
|
|
717
|
-
in: flags.in
|
|
718
|
-
});
|
|
719
|
-
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,
|
|
720
720
|
r => output.formatSymbolJson(r, arg),
|
|
721
721
|
r => { printSymbols(r, arg, { depth: flags.depth, top: flags.top, all: flags.all }); }
|
|
722
722
|
);
|
|
@@ -724,15 +724,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
724
724
|
}
|
|
725
725
|
|
|
726
726
|
case 'usages': {
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
codeOnly: flags.codeOnly,
|
|
731
|
-
context: flags.context,
|
|
732
|
-
exclude: usagesExclude,
|
|
733
|
-
in: flags.in
|
|
734
|
-
});
|
|
735
|
-
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,
|
|
736
730
|
r => output.formatUsagesJson(r, arg),
|
|
737
731
|
r => output.formatUsages(r, arg)
|
|
738
732
|
);
|
|
@@ -740,9 +734,9 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
740
734
|
}
|
|
741
735
|
|
|
742
736
|
case 'example': {
|
|
743
|
-
|
|
744
|
-
|
|
745
|
-
printOutput(
|
|
737
|
+
const { ok, result, error } = execute(index, 'example', { name: arg });
|
|
738
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
739
|
+
printOutput(result,
|
|
746
740
|
r => output.formatExampleJson(r, arg),
|
|
747
741
|
r => output.formatExample(r, arg)
|
|
748
742
|
);
|
|
@@ -750,17 +744,8 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
750
744
|
}
|
|
751
745
|
|
|
752
746
|
case 'context': {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
includeMethods: flags.includeMethods,
|
|
756
|
-
includeUncertain: flags.includeUncertain,
|
|
757
|
-
file: flags.file,
|
|
758
|
-
exclude: flags.exclude
|
|
759
|
-
});
|
|
760
|
-
if (!ctx) {
|
|
761
|
-
console.log(`Symbol "${arg}" not found.`);
|
|
762
|
-
break;
|
|
763
|
-
}
|
|
747
|
+
const { ok, result: ctx, error } = execute(index, 'context', { name: arg, ...flags });
|
|
748
|
+
if (!ok) { console.log(error); break; }
|
|
764
749
|
if (flags.json) {
|
|
765
750
|
console.log(output.formatContextJson(ctx));
|
|
766
751
|
} else {
|
|
@@ -822,27 +807,18 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
822
807
|
}
|
|
823
808
|
|
|
824
809
|
case 'smart': {
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
includeUncertain: flags.includeUncertain
|
|
831
|
-
});
|
|
832
|
-
if (smart) {
|
|
833
|
-
printOutput(smart, output.formatSmartJson, r => output.formatSmart(r, {
|
|
834
|
-
uncertainHint: 'use --include-uncertain to include all'
|
|
835
|
-
}));
|
|
836
|
-
} else {
|
|
837
|
-
console.error(`Function "${arg}" not found`);
|
|
838
|
-
}
|
|
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
|
+
}));
|
|
839
815
|
break;
|
|
840
816
|
}
|
|
841
817
|
|
|
842
818
|
case 'about': {
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
printOutput(
|
|
819
|
+
const { ok, result, error } = execute(index, 'about', { name: arg, ...flags });
|
|
820
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
821
|
+
printOutput(result,
|
|
846
822
|
output.formatAboutJson,
|
|
847
823
|
r => output.formatAbout(r, { expand: flags.expand, root: index.root, depth: flags.depth })
|
|
848
824
|
);
|
|
@@ -850,63 +826,51 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
850
826
|
}
|
|
851
827
|
|
|
852
828
|
case 'impact': {
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
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);
|
|
856
832
|
break;
|
|
857
833
|
}
|
|
858
834
|
|
|
859
835
|
case 'plan': {
|
|
860
|
-
|
|
861
|
-
if (!
|
|
862
|
-
|
|
863
|
-
process.exit(1);
|
|
864
|
-
}
|
|
865
|
-
const planResult = index.plan(arg, {
|
|
866
|
-
addParam: flags.addParam,
|
|
867
|
-
removeParam: flags.removeParam,
|
|
868
|
-
renameTo: flags.renameTo,
|
|
869
|
-
defaultValue: flags.defaultValue,
|
|
870
|
-
file: flags.file
|
|
871
|
-
});
|
|
872
|
-
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);
|
|
873
839
|
break;
|
|
874
840
|
}
|
|
875
841
|
|
|
876
842
|
case 'trace': {
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
const traceResult = index.trace(arg, { depth: traceDepth, file: flags.file, all: flags.all || depthExplicit, includeMethods: flags.includeMethods, includeUncertain: flags.includeUncertain });
|
|
881
|
-
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);
|
|
882
846
|
break;
|
|
883
847
|
}
|
|
884
848
|
|
|
885
|
-
case 'stacktrace':
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
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);
|
|
890
853
|
break;
|
|
891
854
|
}
|
|
892
855
|
|
|
893
856
|
case 'verify': {
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
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);
|
|
897
860
|
break;
|
|
898
861
|
}
|
|
899
862
|
|
|
900
863
|
case 'related': {
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
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 }));
|
|
904
867
|
break;
|
|
905
868
|
}
|
|
906
869
|
|
|
870
|
+
// ── Commands staying in adapter (complex I/O) ───────────────────
|
|
871
|
+
|
|
907
872
|
case 'fn': {
|
|
908
873
|
requireArg(arg, 'Usage: ucn . fn <name>');
|
|
909
|
-
// Support comma-separated names for bulk extraction
|
|
910
874
|
if (arg.includes(',')) {
|
|
911
875
|
const fnNames = arg.split(',').map(n => n.trim()).filter(Boolean);
|
|
912
876
|
for (let i = 0; i < fnNames.length; i++) {
|
|
@@ -925,149 +889,149 @@ function runProjectCommand(rootDir, command, arg) {
|
|
|
925
889
|
break;
|
|
926
890
|
}
|
|
927
891
|
|
|
928
|
-
case '
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
|
|
932
|
-
|
|
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,
|
|
933
913
|
r => output.formatImportsJson(r, arg),
|
|
934
914
|
r => output.formatImports(r, arg)
|
|
935
915
|
);
|
|
936
916
|
break;
|
|
937
917
|
}
|
|
938
918
|
|
|
939
|
-
case 'exporters':
|
|
940
|
-
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
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,
|
|
944
923
|
r => output.formatExportersJson(r, arg),
|
|
945
924
|
r => output.formatExporters(r, arg)
|
|
946
925
|
);
|
|
947
926
|
break;
|
|
948
927
|
}
|
|
949
928
|
|
|
950
|
-
case '
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
printOutput(
|
|
954
|
-
r =>
|
|
955
|
-
r => output.
|
|
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)
|
|
956
935
|
);
|
|
957
936
|
break;
|
|
958
937
|
}
|
|
959
938
|
|
|
960
|
-
case '
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
printOutput(
|
|
964
|
-
r =>
|
|
965
|
-
|
|
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 })
|
|
966
949
|
);
|
|
967
950
|
break;
|
|
968
951
|
}
|
|
969
952
|
|
|
970
|
-
|
|
971
|
-
const api = index.api(arg); // arg is optional file path
|
|
972
|
-
printOutput(api,
|
|
973
|
-
r => output.formatApiJson(r, arg),
|
|
974
|
-
r => output.formatApi(r, arg)
|
|
975
|
-
);
|
|
976
|
-
break;
|
|
977
|
-
}
|
|
953
|
+
// ── Remaining commands ──────────────────────────────────────────
|
|
978
954
|
|
|
979
|
-
case '
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
r =>
|
|
985
|
-
r => output.formatFileExports(r, arg)
|
|
955
|
+
case 'typedef': {
|
|
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,
|
|
959
|
+
r => output.formatTypedefJson(r, arg),
|
|
960
|
+
r => output.formatTypedef(r, arg)
|
|
986
961
|
);
|
|
987
962
|
break;
|
|
988
963
|
}
|
|
989
964
|
|
|
990
|
-
case '
|
|
991
|
-
const
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
in: flags.in || subdirScope
|
|
997
|
-
});
|
|
998
|
-
printOutput(deadcodeResults,
|
|
999
|
-
output.formatDeadcodeJson,
|
|
1000
|
-
r => output.formatDeadcode(r, { top: flags.top })
|
|
965
|
+
case 'tests': {
|
|
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,
|
|
969
|
+
r => output.formatTestsJson(r, arg),
|
|
970
|
+
r => output.formatTests(r, arg)
|
|
1001
971
|
);
|
|
1002
972
|
break;
|
|
1003
973
|
}
|
|
1004
974
|
|
|
1005
|
-
case '
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
r => JSON.stringify({
|
|
1012
|
-
root: path.relative(index.root, r.root),
|
|
1013
|
-
nodes: r.nodes.map(n => ({ file: n.relativePath, depth: n.depth })),
|
|
1014
|
-
edges: r.edges.map(e => ({ from: path.relative(index.root, e.from), to: path.relative(index.root, e.to) }))
|
|
1015
|
-
}, null, 2),
|
|
1016
|
-
r => output.formatGraph(r, { showAll: flags.all || flags.depth !== undefined, maxDepth: graphDepth, file: arg })
|
|
975
|
+
case 'api': {
|
|
976
|
+
const { ok, result, error } = execute(index, 'api', { file: arg });
|
|
977
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
978
|
+
printOutput(result,
|
|
979
|
+
r => output.formatApiJson(r, arg),
|
|
980
|
+
r => output.formatApi(r, arg)
|
|
1017
981
|
);
|
|
1018
982
|
break;
|
|
1019
983
|
}
|
|
1020
984
|
|
|
1021
985
|
case 'search': {
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
printOutput(searchResults,
|
|
986
|
+
const { ok, result, error } = execute(index, 'search', { term: arg, ...flags });
|
|
987
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
988
|
+
printOutput(result,
|
|
1026
989
|
r => output.formatSearchJson(r, arg),
|
|
1027
990
|
r => output.formatSearch(r, arg)
|
|
1028
991
|
);
|
|
1029
992
|
break;
|
|
1030
993
|
}
|
|
1031
994
|
|
|
1032
|
-
case '
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
printLines(fileContent.split('\n'), arg);
|
|
995
|
+
case 'deadcode': {
|
|
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,
|
|
999
|
+
output.formatDeadcodeJson,
|
|
1000
|
+
r => output.formatDeadcode(r, {
|
|
1001
|
+
top: flags.top,
|
|
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
|
|
1004
|
+
})
|
|
1005
|
+
);
|
|
1044
1006
|
break;
|
|
1045
1007
|
}
|
|
1046
1008
|
|
|
1047
1009
|
case 'stats': {
|
|
1048
|
-
const
|
|
1049
|
-
|
|
1010
|
+
const { ok, result, error } = execute(index, 'stats', { functions: flags.functions });
|
|
1011
|
+
if (!ok) { console.error(error); process.exit(1); }
|
|
1012
|
+
printOutput(result,
|
|
1050
1013
|
output.formatStatsJson,
|
|
1051
1014
|
r => output.formatStats(r, { top: flags.top })
|
|
1052
1015
|
);
|
|
1053
1016
|
break;
|
|
1054
1017
|
}
|
|
1055
1018
|
|
|
1056
|
-
case '
|
|
1057
|
-
const
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
file: flags.file
|
|
1061
|
-
});
|
|
1062
|
-
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);
|
|
1063
1023
|
break;
|
|
1064
1024
|
}
|
|
1065
1025
|
|
|
1066
1026
|
default:
|
|
1067
|
-
console.error(`Unknown command: ${
|
|
1027
|
+
console.error(`Unknown command: ${canonical}`);
|
|
1068
1028
|
printUsage();
|
|
1069
1029
|
process.exit(1);
|
|
1070
1030
|
}
|
|
1031
|
+
} catch (e) {
|
|
1032
|
+
console.error(`Error: ${e.message}`);
|
|
1033
|
+
process.exit(1);
|
|
1034
|
+
}
|
|
1071
1035
|
}
|
|
1072
1036
|
|
|
1073
1037
|
function extractFunctionFromProject(index, name, overrideFlags) {
|
|
@@ -1162,6 +1126,45 @@ function extractClassFromProject(index, name, overrideFlags) {
|
|
|
1162
1126
|
// Use index data directly instead of re-parsing the file
|
|
1163
1127
|
const code = fs.readFileSync(match.file, 'utf-8');
|
|
1164
1128
|
const codeLines = code.split('\n');
|
|
1129
|
+
const classLineCount = match.endLine - match.startLine + 1;
|
|
1130
|
+
|
|
1131
|
+
// Large class summary (>200 lines) when no --max-lines specified
|
|
1132
|
+
if (classLineCount > 200 && !f.maxLines) {
|
|
1133
|
+
if (f.json) {
|
|
1134
|
+
const extracted = codeLines.slice(match.startLine - 1, match.endLine);
|
|
1135
|
+
const clsCode = cleanHtmlScriptTags(extracted, detectLanguage(match.file)).join('\n');
|
|
1136
|
+
console.log(JSON.stringify({ ...match, code: clsCode }, null, 2));
|
|
1137
|
+
} else {
|
|
1138
|
+
const lines = [];
|
|
1139
|
+
lines.push(`${match.relativePath}:${match.startLine}`);
|
|
1140
|
+
lines.push(`${output.lineRange(match.startLine, match.endLine)} ${output.formatClassSignature(match)}`);
|
|
1141
|
+
lines.push('\u2500'.repeat(60));
|
|
1142
|
+
const methods = index.findMethodsForType(match.name);
|
|
1143
|
+
if (methods.length > 0) {
|
|
1144
|
+
lines.push(`\nMethods (${methods.length}):`);
|
|
1145
|
+
for (const m of methods) {
|
|
1146
|
+
lines.push(` ${output.formatFunctionSignature(m)} [line ${m.startLine}]`);
|
|
1147
|
+
}
|
|
1148
|
+
}
|
|
1149
|
+
lines.push(`\nClass is ${classLineCount} lines. Use --max-lines=N to see source, or "fn <method>" for individual methods.`);
|
|
1150
|
+
console.log(lines.join('\n'));
|
|
1151
|
+
}
|
|
1152
|
+
return;
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
// Truncated source with --max-lines
|
|
1156
|
+
if (f.maxLines && classLineCount > f.maxLines) {
|
|
1157
|
+
const truncated = codeLines.slice(match.startLine - 1, match.startLine - 1 + f.maxLines);
|
|
1158
|
+
const truncatedCode = cleanHtmlScriptTags(truncated, detectLanguage(match.file)).join('\n');
|
|
1159
|
+
if (f.json) {
|
|
1160
|
+
console.log(JSON.stringify({ ...match, code: truncatedCode, truncated: true, totalLines: classLineCount }, null, 2));
|
|
1161
|
+
} else {
|
|
1162
|
+
console.log(output.formatClass(match, truncatedCode));
|
|
1163
|
+
console.log(`\n... showing ${f.maxLines} of ${classLineCount} lines`);
|
|
1164
|
+
}
|
|
1165
|
+
return;
|
|
1166
|
+
}
|
|
1167
|
+
|
|
1165
1168
|
const extracted = codeLines.slice(match.startLine - 1, match.endLine);
|
|
1166
1169
|
const clsCode = cleanHtmlScriptTags(extracted, detectLanguage(match.file)).join('\n');
|
|
1167
1170
|
|
|
@@ -1699,6 +1702,8 @@ UNDERSTAND CODE (UCN's strength - semantic analysis)
|
|
|
1699
1702
|
smart <name> Function + all dependencies inline
|
|
1700
1703
|
impact <name> What breaks if changed (call sites grouped by file)
|
|
1701
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
|
|
1702
1707
|
|
|
1703
1708
|
═══════════════════════════════════════════════════════════════════════════════
|
|
1704
1709
|
FIND CODE
|
|
@@ -1732,7 +1737,6 @@ REFACTORING HELPERS
|
|
|
1732
1737
|
verify <name> Check all call sites match signature
|
|
1733
1738
|
diff-impact What changed in git diff and who calls it (--base, --staged)
|
|
1734
1739
|
deadcode Find unused functions/classes
|
|
1735
|
-
related <name> Find similar functions (same file, shared deps)
|
|
1736
1740
|
|
|
1737
1741
|
═══════════════════════════════════════════════════════════════════════════════
|
|
1738
1742
|
OTHER
|
|
@@ -1741,7 +1745,6 @@ OTHER
|
|
|
1741
1745
|
typedef <name> Find type definitions
|
|
1742
1746
|
stats Project statistics (--functions for per-function line counts)
|
|
1743
1747
|
stacktrace <text> Parse stack trace, show code at each frame (alias: stack)
|
|
1744
|
-
example <name> Best usage example with context
|
|
1745
1748
|
|
|
1746
1749
|
Common Flags:
|
|
1747
1750
|
--file <pattern> Filter by file path (e.g., --file=routes)
|
|
@@ -1766,6 +1769,8 @@ Common Flags:
|
|
|
1766
1769
|
--calls-only Only show call/test-case matches (tests)
|
|
1767
1770
|
--case-sensitive Case-sensitive text search (search)
|
|
1768
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)
|
|
1769
1774
|
--no-cache Disable caching
|
|
1770
1775
|
--clear-cache Clear cache before running
|
|
1771
1776
|
--base=<ref> Git ref for diff-impact (default: HEAD)
|
|
@@ -1792,6 +1797,7 @@ function runInteractive(rootDir) {
|
|
|
1792
1797
|
console.log('Building index...');
|
|
1793
1798
|
const index = new ProjectIndex(rootDir);
|
|
1794
1799
|
index.build(null, { quiet: true });
|
|
1800
|
+
const iExpandCache = new ExpandCache({ maxSize: 20 });
|
|
1795
1801
|
console.log(`Index ready: ${index.files.size} files, ${index.symbols.size} symbols`);
|
|
1796
1802
|
console.log('Type commands (e.g., "find parseFile", "about main", "toc")');
|
|
1797
1803
|
console.log('Type "help" for commands, "quit" to exit\n');
|
|
@@ -1874,7 +1880,8 @@ Flags can be added per-command: context myFunc --include-methods
|
|
|
1874
1880
|
const iflags = parseInteractiveFlags(flagTokens);
|
|
1875
1881
|
|
|
1876
1882
|
try {
|
|
1877
|
-
|
|
1883
|
+
const iCanonical = resolveCommand(command, 'cli') || command;
|
|
1884
|
+
executeInteractiveCommand(index, iCanonical, arg, iflags, iExpandCache);
|
|
1878
1885
|
} catch (e) {
|
|
1879
1886
|
console.error(`Error: ${e.message}`);
|
|
1880
1887
|
}
|
|
@@ -1902,6 +1909,7 @@ function parseInteractiveFlags(tokens) {
|
|
|
1902
1909
|
includeUncertain: tokens.includes('--include-uncertain'),
|
|
1903
1910
|
includeMethods: tokens.includes('--include-methods=false') ? false : tokens.includes('--include-methods') ? true : undefined,
|
|
1904
1911
|
detailed: tokens.includes('--detailed'),
|
|
1912
|
+
topLevel: tokens.includes('--top-level'),
|
|
1905
1913
|
all: tokens.includes('--all'),
|
|
1906
1914
|
exact: tokens.includes('--exact'),
|
|
1907
1915
|
callsOnly: tokens.includes('--calls-only'),
|
|
@@ -1925,339 +1933,290 @@ function parseInteractiveFlags(tokens) {
|
|
|
1925
1933
|
};
|
|
1926
1934
|
}
|
|
1927
1935
|
|
|
1928
|
-
function executeInteractiveCommand(index, command, arg, iflags = {}) {
|
|
1936
|
+
function executeInteractiveCommand(index, command, arg, iflags = {}, cache = null) {
|
|
1929
1937
|
switch (command) {
|
|
1930
|
-
case 'toc': {
|
|
1931
|
-
const toc = index.getToc({ detailed: iflags.detailed });
|
|
1932
|
-
console.log(output.formatToc(toc, {
|
|
1933
|
-
detailedHint: 'Add --detailed to list all functions, or "about <name>" for full details on a symbol'
|
|
1934
|
-
}));
|
|
1935
|
-
break;
|
|
1936
|
-
}
|
|
1937
1938
|
|
|
1938
|
-
|
|
1939
|
+
// ── Special commands (complex I/O, stay in adapter) ──────────────
|
|
1940
|
+
|
|
1941
|
+
case 'fn': {
|
|
1939
1942
|
if (!arg) {
|
|
1940
|
-
console.log('Usage:
|
|
1943
|
+
console.log('Usage: fn <name>[,name2,...] [--file=<pattern>]');
|
|
1941
1944
|
return;
|
|
1942
1945
|
}
|
|
1943
|
-
|
|
1944
|
-
if (
|
|
1945
|
-
|
|
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
|
+
}
|
|
1946
1953
|
} else {
|
|
1947
|
-
|
|
1954
|
+
extractFunctionFromProject(index, arg, iflags);
|
|
1948
1955
|
}
|
|
1949
1956
|
break;
|
|
1950
1957
|
}
|
|
1951
1958
|
|
|
1952
|
-
case '
|
|
1959
|
+
case 'class': {
|
|
1953
1960
|
if (!arg) {
|
|
1954
|
-
console.log('Usage:
|
|
1961
|
+
console.log('Usage: class <name> [--file=<pattern>]');
|
|
1955
1962
|
return;
|
|
1956
1963
|
}
|
|
1957
|
-
|
|
1958
|
-
console.log(output.formatAbout(aboutResult, { expand: iflags.expand, root: index.root, showAll: iflags.all }));
|
|
1964
|
+
extractClassFromProject(index, arg, iflags);
|
|
1959
1965
|
break;
|
|
1960
1966
|
}
|
|
1961
1967
|
|
|
1962
|
-
case '
|
|
1963
|
-
if (!arg) {
|
|
1964
|
-
console.log('Usage:
|
|
1968
|
+
case 'lines': {
|
|
1969
|
+
if (!arg || !iflags.file) {
|
|
1970
|
+
console.log('Usage: lines <range> --file=<file>');
|
|
1971
|
+
return;
|
|
1972
|
+
}
|
|
1973
|
+
const filePath = index.findFile(iflags.file);
|
|
1974
|
+
if (!filePath) {
|
|
1975
|
+
console.log(`File not found: ${iflags.file}`);
|
|
1965
1976
|
return;
|
|
1966
1977
|
}
|
|
1967
|
-
const
|
|
1968
|
-
|
|
1978
|
+
const fileContent = fs.readFileSync(filePath, 'utf-8');
|
|
1979
|
+
printLines(fileContent.split('\n'), arg);
|
|
1969
1980
|
break;
|
|
1970
1981
|
}
|
|
1971
1982
|
|
|
1972
|
-
case '
|
|
1983
|
+
case 'expand': {
|
|
1973
1984
|
if (!arg) {
|
|
1974
|
-
console.log('Usage:
|
|
1985
|
+
console.log('Usage: expand <number>');
|
|
1986
|
+
return;
|
|
1987
|
+
}
|
|
1988
|
+
const expandNum = parseInt(arg, 10);
|
|
1989
|
+
if (isNaN(expandNum)) {
|
|
1990
|
+
console.log(`Invalid item number: "${arg}"`);
|
|
1975
1991
|
return;
|
|
1976
1992
|
}
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
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);
|
|
1980
2006
|
} else {
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
|
|
1987
|
-
|
|
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);
|
|
1988
2019
|
}
|
|
1989
2020
|
break;
|
|
1990
2021
|
}
|
|
1991
2022
|
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
console.log(output.formatSmart(smart, {
|
|
2000
|
-
uncertainHint: 'use --include-uncertain to include all'
|
|
2001
|
-
}));
|
|
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}"`);
|
|
2002
2030
|
} else {
|
|
2003
|
-
|
|
2031
|
+
printSymbols(result, arg, { top: iflags.top });
|
|
2004
2032
|
}
|
|
2005
2033
|
break;
|
|
2006
2034
|
}
|
|
2007
2035
|
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
|
|
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);
|
|
2012
2051
|
}
|
|
2013
|
-
const impactResult = index.impact(arg, { file: iflags.file });
|
|
2014
|
-
console.log(output.formatImpact(impactResult));
|
|
2015
2052
|
break;
|
|
2016
2053
|
}
|
|
2017
2054
|
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
}
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
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
|
+
}));
|
|
2026
2065
|
break;
|
|
2027
2066
|
}
|
|
2028
2067
|
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
}
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
if (i > 0) console.log('\n' + '═'.repeat(60) + '\n');
|
|
2039
|
-
extractFunctionFromProject(index, fnNames[i], iflags);
|
|
2040
|
-
}
|
|
2041
|
-
} else {
|
|
2042
|
-
extractFunctionFromProject(index, arg, iflags);
|
|
2043
|
-
}
|
|
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
|
+
}));
|
|
2044
2077
|
break;
|
|
2045
2078
|
}
|
|
2046
2079
|
|
|
2047
|
-
case '
|
|
2048
|
-
|
|
2049
|
-
|
|
2050
|
-
|
|
2051
|
-
}
|
|
2052
|
-
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 }));
|
|
2053
2084
|
break;
|
|
2054
2085
|
}
|
|
2055
2086
|
|
|
2056
|
-
case '
|
|
2057
|
-
|
|
2058
|
-
|
|
2059
|
-
|
|
2060
|
-
|
|
2061
|
-
|
|
2062
|
-
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
}
|
|
2066
|
-
|
|
2067
|
-
|
|
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));
|
|
2068
2114
|
break;
|
|
2069
2115
|
}
|
|
2070
2116
|
|
|
2071
2117
|
case 'graph': {
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
return;
|
|
2075
|
-
}
|
|
2118
|
+
const { ok, result, error } = execute(index, 'graph', { file: arg, ...iflags });
|
|
2119
|
+
if (!ok) { console.log(error); return; }
|
|
2076
2120
|
const graphDepth = iflags.depth ? parseInt(iflags.depth) : 2;
|
|
2077
|
-
|
|
2078
|
-
const graphResult = index.graph(arg, { direction: graphDirection, maxDepth: graphDepth });
|
|
2079
|
-
console.log(output.formatGraph(graphResult, { showAll: iflags.all, maxDepth: graphDepth }));
|
|
2121
|
+
console.log(output.formatGraph(result, { showAll: iflags.all || !!iflags.depth, maxDepth: graphDepth, file: arg }));
|
|
2080
2122
|
break;
|
|
2081
2123
|
}
|
|
2082
2124
|
|
|
2083
|
-
case '
|
|
2084
|
-
|
|
2085
|
-
if (!
|
|
2086
|
-
|
|
2087
|
-
return;
|
|
2088
|
-
}
|
|
2089
|
-
const fileExports = index.fileExports(arg);
|
|
2090
|
-
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));
|
|
2091
2129
|
break;
|
|
2092
2130
|
}
|
|
2093
2131
|
|
|
2094
|
-
case 'imports':
|
|
2095
|
-
|
|
2096
|
-
if (!
|
|
2097
|
-
|
|
2098
|
-
return;
|
|
2099
|
-
}
|
|
2100
|
-
const imports = index.imports(arg);
|
|
2101
|
-
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));
|
|
2102
2136
|
break;
|
|
2103
2137
|
}
|
|
2104
2138
|
|
|
2105
|
-
case 'exporters':
|
|
2106
|
-
|
|
2107
|
-
if (!
|
|
2108
|
-
|
|
2109
|
-
return;
|
|
2110
|
-
}
|
|
2111
|
-
const exporters = index.exporters(arg);
|
|
2112
|
-
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));
|
|
2113
2143
|
break;
|
|
2114
2144
|
}
|
|
2115
2145
|
|
|
2116
2146
|
case 'tests': {
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
}
|
|
2121
|
-
const tests = index.tests(arg, { callsOnly: iflags.callsOnly });
|
|
2122
|
-
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));
|
|
2123
2150
|
break;
|
|
2124
2151
|
}
|
|
2125
2152
|
|
|
2126
2153
|
case 'search': {
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
}
|
|
2131
|
-
const results = index.search(arg, { codeOnly: iflags.codeOnly, caseSensitive: iflags.caseSensitive, context: iflags.context, exclude: iflags.exclude, in: iflags.in, regex: iflags.regex });
|
|
2132
|
-
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));
|
|
2133
2157
|
break;
|
|
2134
2158
|
}
|
|
2135
2159
|
|
|
2136
2160
|
case 'typedef': {
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
}
|
|
2141
|
-
const types = index.typedef(arg);
|
|
2142
|
-
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));
|
|
2143
2164
|
break;
|
|
2144
2165
|
}
|
|
2145
2166
|
|
|
2146
2167
|
case 'api': {
|
|
2147
|
-
const
|
|
2148
|
-
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 || '.'));
|
|
2149
2171
|
break;
|
|
2150
2172
|
}
|
|
2151
2173
|
|
|
2152
|
-
case '
|
|
2153
|
-
const
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
file: iflags.file
|
|
2157
|
-
});
|
|
2158
|
-
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));
|
|
2159
2178
|
break;
|
|
2160
2179
|
}
|
|
2161
2180
|
|
|
2162
2181
|
case 'stats': {
|
|
2163
|
-
const
|
|
2164
|
-
console.log(
|
|
2165
|
-
|
|
2166
|
-
}
|
|
2167
|
-
|
|
2168
|
-
case 'expand': {
|
|
2169
|
-
if (!arg) {
|
|
2170
|
-
console.log('Usage: expand <number>');
|
|
2171
|
-
return;
|
|
2172
|
-
}
|
|
2173
|
-
const expandNum = parseInt(arg, 10);
|
|
2174
|
-
if (isNaN(expandNum)) {
|
|
2175
|
-
console.log(`Invalid item number: "${arg}"`);
|
|
2176
|
-
return;
|
|
2177
|
-
}
|
|
2178
|
-
const cached = loadExpandableItems(index.root);
|
|
2179
|
-
if (!cached || !cached.items || cached.items.length === 0) {
|
|
2180
|
-
console.log('No expandable items. Run context first.');
|
|
2181
|
-
return;
|
|
2182
|
-
}
|
|
2183
|
-
const expandMatch = cached.items.find(i => i.num === expandNum);
|
|
2184
|
-
if (!expandMatch) {
|
|
2185
|
-
console.log(`Item ${expandNum} not found. Available: 1-${cached.items.length}`);
|
|
2186
|
-
return;
|
|
2187
|
-
}
|
|
2188
|
-
printExpandedItem(expandMatch, cached.root || index.root);
|
|
2189
|
-
break;
|
|
2190
|
-
}
|
|
2191
|
-
|
|
2192
|
-
case 'deadcode': {
|
|
2193
|
-
const deadResult = index.deadcode({
|
|
2194
|
-
includeExported: iflags.includeExported,
|
|
2195
|
-
includeDecorated: iflags.includeDecorated,
|
|
2196
|
-
includeTests: iflags.includeTests,
|
|
2197
|
-
exclude: iflags.exclude,
|
|
2198
|
-
in: iflags.in
|
|
2199
|
-
});
|
|
2200
|
-
console.log(output.formatDeadcode(deadResult, { top: iflags.top }));
|
|
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 }));
|
|
2201
2185
|
break;
|
|
2202
2186
|
}
|
|
2203
2187
|
|
|
2204
2188
|
case 'related': {
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
}
|
|
2209
|
-
const relResult = index.related(arg, { file: iflags.file, all: iflags.all });
|
|
2210
|
-
console.log(output.formatRelated(relResult, { showAll: iflags.all }));
|
|
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 }));
|
|
2211
2192
|
break;
|
|
2212
2193
|
}
|
|
2213
2194
|
|
|
2214
2195
|
case 'example': {
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
}
|
|
2219
|
-
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));
|
|
2220
2199
|
break;
|
|
2221
2200
|
}
|
|
2222
2201
|
|
|
2223
2202
|
case 'plan': {
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
}
|
|
2228
|
-
if (!iflags.addParam && !iflags.removeParam && !iflags.renameTo) {
|
|
2229
|
-
console.log('Plan requires an operation: --add-param, --remove-param, or --rename-to');
|
|
2230
|
-
return;
|
|
2231
|
-
}
|
|
2232
|
-
const planResult = index.plan(arg, {
|
|
2233
|
-
addParam: iflags.addParam,
|
|
2234
|
-
removeParam: iflags.removeParam,
|
|
2235
|
-
renameTo: iflags.renameTo,
|
|
2236
|
-
defaultValue: iflags.defaultValue,
|
|
2237
|
-
file: iflags.file
|
|
2238
|
-
});
|
|
2239
|
-
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));
|
|
2240
2206
|
break;
|
|
2241
2207
|
}
|
|
2242
2208
|
|
|
2243
2209
|
case 'verify': {
|
|
2244
|
-
|
|
2245
|
-
|
|
2246
|
-
|
|
2247
|
-
}
|
|
2248
|
-
const verifyResult = index.verify(arg, { file: iflags.file });
|
|
2249
|
-
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));
|
|
2250
2213
|
break;
|
|
2251
2214
|
}
|
|
2252
2215
|
|
|
2253
|
-
case 'stacktrace':
|
|
2254
|
-
|
|
2255
|
-
if (!
|
|
2256
|
-
|
|
2257
|
-
return;
|
|
2258
|
-
}
|
|
2259
|
-
const stackResult = index.parseStackTrace(arg);
|
|
2260
|
-
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));
|
|
2261
2220
|
break;
|
|
2262
2221
|
}
|
|
2263
2222
|
|