193 lines
6.2 KiB
Plaintext
193 lines
6.2 KiB
Plaintext
// cell query — Semantic queries across packages.
|
|
//
|
|
// Usage:
|
|
// cell query <name> Find all references to <name>
|
|
// cell query <name> --top Top-level references only
|
|
// cell query <name> --fn Inside-function references only
|
|
// cell query <name> --channels Show <name>.<prop> usage summary
|
|
// cell query --decl <name> Find declarations of <name>
|
|
// cell query --decl <name> --fn Only function declarations
|
|
// cell query --intrinsic <name> 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] [<name>] [<package>]")
|
|
log.console("")
|
|
log.console("Semantic queries across packages.")
|
|
log.console("")
|
|
log.console("Commands:")
|
|
log.console(" <name> Find all references to <name>")
|
|
log.console(" <name> --top Top-level references only")
|
|
log.console(" <name> --fn Inside-function references only")
|
|
log.console(" <name> --channels Show <name>.<prop> usage summary")
|
|
log.console(" --decl <name> Find declarations of <name>")
|
|
log.console(" --decl <name> --fn Only function declarations")
|
|
log.console(" --intrinsic <name> 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()
|