// cell query — Semantic queries across packages. // // Usage: // cell query Find all references to // cell query --top Top-level references only // cell query --fn Inside-function references only // cell query --channels Show . usage summary // cell query --decl Find declarations of // cell query --decl --fn Only function declarations // cell query --intrinsic Find intrinsic usage // cell query --excess-args Find call sites with >4 args // cell query --help var shop = use('internal/shop') var analyze_mod = use('analyze') var fd = use('fd') var mode = null var name = null var scope_filter = null var kind_filter = null var pkg_filter = null var show_help = false var i = 0 for (i = 0; i < length(args); i++) { if (args[i] == '--top') { scope_filter = "top" } else if (args[i] == '--fn') { if (mode == "decl") { kind_filter = "fn" } else { scope_filter = "fn" } } else if (args[i] == '--channels') { mode = "channels" } else if (args[i] == '--intrinsic') { mode = "intrinsic" if (i + 1 < length(args) && !starts_with(args[i + 1], '-')) { name = args[i + 1] i = i + 1 } else { log.error('--intrinsic requires a name') mode = "error" } } else if (args[i] == '--decl') { mode = "decl" if (i + 1 < length(args) && !starts_with(args[i + 1], '-')) { name = args[i + 1] i = i + 1 } else { log.error('--decl requires a name') mode = "error" } } else if (args[i] == '--excess-args') { mode = "excess_args" } else if (args[i] == '--help' || args[i] == '-h') { show_help = true } else if (!starts_with(args[i], '-')) { if (name == null && mode == null) { name = args[i] mode = "refs" } else { pkg_filter = args[i] } } } // --channels requires a name from positional arg if (mode == "channels" && name == null) { log.error('--channels requires a name (e.g., cell query log --channels)') mode = "error" } var all_files = null var files = [] var j = 0 var idx = null var hits = null var hit = null var k = 0 var ch_result = null var props = null var prop = null var parts = null // Use return pattern to avoid closure-over-object issue with disruption. var safe_index = function(path) { return shop.index_file(path) } disruption { return null } if (show_help) { log.console("Usage: cell query [options] [] []") log.console("") log.console("Semantic queries across packages.") log.console("") log.console("Commands:") log.console(" Find all references to ") log.console(" --top Top-level references only") log.console(" --fn Inside-function references only") log.console(" --channels Show . usage summary") log.console(" --decl Find declarations of ") log.console(" --decl --fn Only function declarations") log.console(" --intrinsic Find intrinsic usage") log.console(" --excess-args Find call sites with >4 args") log.console("") log.console("Without a package argument, searches all installed packages.") } else if (mode == null || mode == "error") { if (mode != "error") { log.error('Specify a name or --decl/--intrinsic/--excess-args. Use --help for usage.') } } else { all_files = shop.all_script_paths() if (pkg_filter != null) { for (j = 0; j < length(all_files); j++) { if (all_files[j].package == pkg_filter) { files[] = all_files[j] } } } else { files = all_files } for (j = 0; j < length(files); j++) { idx = safe_index(files[j].full_path) if (idx == null) continue if (mode == "refs") { hits = analyze_mod.find_refs(idx, name, scope_filter) if (hits != null && length(hits) > 0) { for (k = 0; k < length(hits); k++) { hit = hits[k] if (hit.span != null) { if (hit.enclosing != null) { log.console(`${files[j].package}:${files[j].rel_path}:${text(hit.span.from_row)}:${text(hit.span.from_col)}: ${hit.name} (in: ${hit.enclosing})`) } else { log.console(`${files[j].package}:${files[j].rel_path}:${text(hit.span.from_row)}:${text(hit.span.from_col)}: ${hit.name} (top-level)`) } } } } } else if (mode == "channels") { ch_result = analyze_mod.channels(idx, name) if (ch_result != null && ch_result.summary != null) { props = array(ch_result.summary) if (length(props) > 0) { parts = [] for (k = 0; k < length(props); k++) { prop = props[k] parts[] = `${prop}(${text(ch_result.summary[prop])})` } log.console(`${files[j].package}:${files[j].rel_path}: ${text(parts, " ")}`) } } } else if (mode == "intrinsic") { hits = analyze_mod.find_intrinsic(idx, name) if (hits != null && length(hits) > 0) { for (k = 0; k < length(hits); k++) { hit = hits[k] if (hit.span != null) { log.console(`${files[j].package}:${files[j].rel_path}:${text(hit.span.from_row)}:${text(hit.span.from_col)}: ${hit.name}`) } } } } else if (mode == "decl") { hits = analyze_mod.find_decls(idx, name, kind_filter) if (hits != null && length(hits) > 0) { for (k = 0; k < length(hits); k++) { hit = hits[k] if (hit.decl_span != null) { log.console(`${files[j].package}:${files[j].rel_path}:${text(hit.decl_span.from_row)}:${text(hit.decl_span.from_col)}: ${hit.kind} ${hit.name}`) } } } } else if (mode == "excess_args") { hits = analyze_mod.excess_args(idx) if (hits != null && length(hits) > 0) { for (k = 0; k < length(hits); k++) { hit = hits[k] if (hit.span != null) { log.console(`${files[j].package}:${files[j].rel_path}:${text(hit.span.from_row)}:${text(hit.span.from_col)}: ${hit.callee}() called with ${text(hit.args_count)} args (max 4)`) } } } } } } $stop()