var shop = use('internal/shop') var pkg = use('package') if (!args || length(args) < 1) { log.console("Usage: cell why ") $stop() return } 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(current_pkg, stack) { var deps = pkg.dependencies(current_pkg) // Sort for consistent output var aliases = sort(array(deps)) for (var i = 0; i < length(aliases); i++) { var alias = aliases[i] var locator = deps[alias] var parsed = shop.parse_package(locator) if (!parsed) continue var canon = parsed.path var 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) var match = (alias == target) || (parsed.name == target) || (canon == target) || (canon == target_clean) || (locator == target) || (locator_clean == target) var node = { alias: alias, pkg: canon, locator: locator } var 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) var cycle = false for (var j = 0; j < length(stack); j++) { if (stack[j].pkg == canon) { cycle = true break } } if (!cycle) { search(canon, new_stack) } } } function print_stack(stack) { // Calculate max width for alignment if needed, but simple tree is fine var output = "project" log.console(output) for (var i = 0; i < length(stack); i++) { var node = stack[i] var indent = "" for (var j = 0; j <= i; j++) indent += " " var 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(null, []) if (!found) { log.console("Package '" + target + "' not found in dependency tree.") } $stop()