123 lines
3.1 KiB
Plaintext
123 lines
3.1 KiB
Plaintext
// cell why - Show reverse dependencies for a package
|
|
|
|
var shop = use('internal/shop')
|
|
var pkg = use('package')
|
|
|
|
if (!args || length(args) < 1) {
|
|
log.console("Usage: cell why <package>")
|
|
$stop()
|
|
}
|
|
|
|
var target = args[0]
|
|
log.console("Searching for '" + target + "'...")
|
|
|
|
var target_clean = target
|
|
if (starts_with(target_clean, '/')) target_clean = text(target_clean, 1)
|
|
|
|
var found = false
|
|
|
|
// DFS to find paths
|
|
// current_pkg: canonical path of current package (null for root)
|
|
// stack: array of {alias, pkg} leading to current_pkg
|
|
|
|
function search_deps(current_pkg, stack) {
|
|
var deps = pkg.dependencies(current_pkg)
|
|
var aliases = sort(array(deps))
|
|
var i = 0
|
|
var alias = null
|
|
var locator = null
|
|
var parsed = null
|
|
var canon = null
|
|
var locator_clean = null
|
|
var match = false
|
|
var node = null
|
|
var new_stack = null
|
|
var cycle = false
|
|
var j = 0
|
|
|
|
for (i = 0; i < length(aliases); i++) {
|
|
alias = aliases[i]
|
|
locator = deps[alias]
|
|
parsed = shop.parse_package(locator)
|
|
if (!parsed) continue
|
|
|
|
canon = parsed.path
|
|
|
|
locator_clean = locator
|
|
if (search(locator, '@') != null) locator_clean = array(locator, '@')[0]
|
|
|
|
// Check if match
|
|
// 1. Alias matches
|
|
// 2. Package name matches
|
|
// 3. Canonical path matches (exact or clean)
|
|
// 4. Locator matches (exact or clean)
|
|
match = (alias == target) ||
|
|
(parsed.name == target) ||
|
|
(canon == target) ||
|
|
(canon == target_clean) ||
|
|
(locator == target) ||
|
|
(locator_clean == target)
|
|
|
|
node = { alias: alias, pkg: canon, locator: locator }
|
|
new_stack = stack.concat([node])
|
|
|
|
if (match) {
|
|
found = true
|
|
print_stack(new_stack)
|
|
// Don't recurse if we found the target in this branch
|
|
continue
|
|
}
|
|
|
|
// Recurse if not seen in current stack (cycle detection)
|
|
cycle = false
|
|
for (j = 0; j < length(stack); j++) {
|
|
if (stack[j].pkg == canon) {
|
|
cycle = true
|
|
break
|
|
}
|
|
}
|
|
|
|
if (!cycle) {
|
|
search_deps(canon, new_stack)
|
|
}
|
|
}
|
|
}
|
|
|
|
function print_stack(stack) {
|
|
// Calculate max width for alignment if needed, but simple tree is fine
|
|
var output = "project"
|
|
var i = 0
|
|
var node = null
|
|
var indent = null
|
|
var j = 0
|
|
var info = null
|
|
log.console(output)
|
|
|
|
for (i = 0; i < length(stack); i++) {
|
|
node = stack[i]
|
|
indent = ""
|
|
for (j = 0; j <= i; j++) indent += " "
|
|
|
|
info = node.locator
|
|
if (node.alias != parsed_name(node.locator)) {
|
|
// info += " (aliased as " + node.alias + ")"
|
|
}
|
|
|
|
log.console(indent + "-> " + node.alias + " (" + info + ")")
|
|
}
|
|
log.console("")
|
|
}
|
|
|
|
function parsed_name(locator) {
|
|
var parsed = shop.parse_package(locator)
|
|
return parsed ? parsed.name : ""
|
|
}
|
|
|
|
search_deps(null, [])
|
|
|
|
if (!found) {
|
|
log.console("Package '" + target + "' not found in dependency tree.")
|
|
}
|
|
|
|
$stop()
|