From c5bf4b3091b296f8cc7e810cfbf14e6864982a5b Mon Sep 17 00:00:00 2001 From: Emily Marigold Klassen <760204+forivall@users.noreply.github.com> Date: Wed, 17 Apr 2024 11:17:14 -0700 Subject: [PATCH] =?UTF-8?q?=F0=9F=A4=96=20Merge=20PR=20#69373=20[@npmcli/a?= =?UTF-8?q?rborist]=20Add=20inventory=20query=20types=20by=20@forivall?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- types/npmcli__arborist/index.d.ts | 44 +++++++++++++-- .../npmcli__arborist-tests.ts | 54 ++++++++++++++++++- types/npmcli__arborist/package.json | 1 + 3 files changed, 93 insertions(+), 6 deletions(-) diff --git a/types/npmcli__arborist/index.d.ts b/types/npmcli__arborist/index.d.ts index c5468a3ca599e1..b708e02aa46981 100644 --- a/types/npmcli__arborist/index.d.ts +++ b/types/npmcli__arborist/index.d.ts @@ -1,3 +1,5 @@ +/// + import { LockDependency, PackageLock as _PackageLock } from "@npm/types"; import { PackageJson } from "@npmcli/package-json"; import { EventEmitter } from "events"; @@ -217,9 +219,14 @@ declare namespace Arborist { /** Errors encountered while parsing package.json or version specifiers. */ errors: Error[]; - /** If this is a Link, this is the node it */ + /** If this is a Link, this is the node it links to */ target: Node; + overridden?: boolean; + + /** When overrides are used, this is the virtual root */ + sourceReference?: Node; + /** Identify the node that will be returned when code in this package runs `require(name)` */ resolve(name: string): Node; @@ -228,12 +235,16 @@ declare namespace Arborist { querySelectorAll(query: string): Promise; toJSON(): Node; + + explain(seen?: Node[]): Explanation; } class Link extends Node { isLink: true; } + type DependencyProblem = "DETACHED" | "MISSING" | "PEER LOCAL" | "INVALID"; + /** * Edge objects represent a dependency relationship a package node to the * point in the tree where the dependency will be loaded. As nodes are @@ -262,6 +273,8 @@ declare namespace Arborist { to: Node; /** True if `edge.to` satisfies the specifier. */ valid: boolean; + invalid: boolean; + missing: boolean; /** * A string indicating the type of error if there is a problem, or `null` * if it's valid. Values, in order of precedence: @@ -276,8 +289,10 @@ declare namespace Arborist { * means that the dependency is not a peer. * * `INVALID` Indicates that the dependency does not satisfy `edge.spec`. */ - error: "DETACHED" | "MISSING" | "PEER LOCAL" | "INVALID" | null; + error: DependencyProblem | null; reload(hard?: boolean): void; + + explain(seen?: Node[]): Explanation; } interface AuditReport extends Map { @@ -400,8 +415,8 @@ declare namespace Arborist { filter(fn: (node: Node) => boolean): Generator; add(node: Node): void; delete(node: Node): void; - query(key: string, val: Node): Set; - query(key: string, val?: never): Set; + query(key: string, val: string | undefined): Set; + query(key: string): IterableIterator; has(node: Node): boolean; set?(k: never, v: never): never; } @@ -430,6 +445,27 @@ declare namespace Arborist { stdout: string; stderr: string; } + interface DependencyExplanation { + type: string | null; + name: string; + spec: string; + rawSpec?: string; + overridden?: boolean; + bundled?: boolean; + error?: DependencyProblem; + from?: Node; + } + interface Explanation { + name: string; + version: string; + errors?: Error[]; + package?: PackageJson; + whileInstalling?: { name: string; version: string; path: string }; + location?: string; + isWorkspace?: boolean; + dependents?: DependencyExplanation[]; + linksIn?: DependencyExplanation[]; + } } export = Arborist; diff --git a/types/npmcli__arborist/npmcli__arborist-tests.ts b/types/npmcli__arborist/npmcli__arborist-tests.ts index f373b1eeb2b109..67326b763d8353 100644 --- a/types/npmcli__arborist/npmcli__arborist-tests.ts +++ b/types/npmcli__arborist/npmcli__arborist-tests.ts @@ -36,7 +36,7 @@ arb.reify({ arb.loadActual().then(async tree => { // query all production dependencies const results = await tree.querySelectorAll(".prod"); - console.log(results); + results; // $ExpectType Node[] }); // iterative @@ -45,5 +45,55 @@ arb.loadActual().then(async tree => { const results = await tree.querySelectorAll("#react:not(:deduped)"); // query the deduped react for git deps const deps = await results[0].querySelectorAll(":type(git)"); - console.log(deps); + deps; // $ExpectType Node[] }); + +async function why(spec: string) { + const tree = await arb.loadActual(); + const nodesSet = tree.inventory.query("packageName", spec); + const nodes: Arborist.Node[] = []; + nodesSet.forEach((node) => { + nodes.push(node); + }); + + const expls = []; + for (const node of nodes) { + const { extraneous, dev, optional, devOptional, peer, inBundle, overridden } = node; + const explRaw = node.explain(); + const expl = explRaw as + & typeof explRaw + & ( + | { + extraneous: true; + dev?: never; + optional?: never; + devOptional?: never; + peer?: never; + bundled?: never; + overridden?: never; + } + | { + extraneous?: false; + dev: boolean; + optional: boolean; + devOptional: boolean; + peer: boolean; + bundled: boolean; + overridden: boolean; + } + ); + if (extraneous) { + expl.extraneous = true; + } else { + expl.dev = dev; + expl.optional = optional; + expl.devOptional = devOptional; + expl.peer = peer; + expl.bundled = inBundle; + expl.overridden = overridden; + } + expls.push(expl); + } + return expls; +} +why("lodash"); diff --git a/types/npmcli__arborist/package.json b/types/npmcli__arborist/package.json index 99058ab8751a5a..7d032c9a7ef41a 100644 --- a/types/npmcli__arborist/package.json +++ b/types/npmcli__arborist/package.json @@ -8,6 +8,7 @@ "dependencies": { "@npm/types": "*", "@types/cacache": "*", + "@types/node": "*", "@types/npmcli__package-json": "*", "@types/pacote": "*" },