依赖选择器语法和查询

依赖选择器语法和查询

选择命令行版本:

描述

🌐 Description

[npm query](/cli/v9/commands/npm-query) 命令引入了一种新的依赖选择器语法(参考并遵循了 CSS Selectors 4 规范 的许多方面),它可以:

🌐 The npm query command exposes a new dependency selector syntax (informed by & respecting many aspects of the CSS Selectors 4 Spec) which:

  • 使用健壮的对象模型、元数据和选择器语法标准化依赖图的形状和查询
  • 利用 CSS 中现有的已知语言语法和运算符来广泛访问不同的包信息
  • 解锁回答有关依赖、它们的关系和关联元数据的复杂、多方面问题的能力
  • 整合 npm 中类似查询命令的冗余逻辑(例如 npm fundnpm lsnpm outdatednpm audit ...)

依赖选择器语法 v1.0.0

🌐 Dependency Selector Syntax v1.0.0

概述

🌐 Overview:

  • 没有“类型”或“标签”选择器(例如 div, h1, a)作为依赖/目标,Node 是唯一可以查询的类型
  • 术语“依赖”是指在由 Arborist 返回的 tree 中找到的任何 Node

组合器

🌐 Combinators

  • > 直系后代/子女
  • 任意后代/子节点
  • ~ 兄弟姐妹

选择器

🌐 Selectors

  • * 通用选择器
  • #<name> 依赖选择器(等同于 [name="..."]
  • #<name>@<version>(相当于[name=<name>]:semver(<version>)
  • , 选择器列表分隔符
  • . 依赖类型选择器
  • : 伪选择器

依赖类型选择器

🌐 Dependency Type Selectors

  • .prod 依赖在 package.jsondependencies 部分中被发现,或者是该依赖的子项
  • .dev 依赖在 package.jsondevDependencies 部分中被发现,或者是该依赖的子项
  • .optional 依赖出现在 package.jsonoptionalDependencies 部分,或在 package.jsonpeerDependenciesMeta 部分中的条目中设置了 "optional": true,或是该依赖的子项
  • package.jsonpeerDependencies 部分中发现了 .peer 依赖
  • package.jsonworkspaces 部分发现 .workspace 依赖
  • .bundled 依赖在 package.jsonbundleDependencies 部分中被发现,或者是该依赖的子项

伪选择器

🌐 Pseudo Selectors

  • :not(<selector>)
  • :has(<selector>)
  • :is(<selector list>)
  • :root 匹配根节点/依赖
  • :scope 匹配了其查询的节点/依赖
  • :empty 当一个依赖没有依赖时
  • :private 当一个依赖是私有时
  • :link 当一个依赖被链接时(例如,工作区或手动 linked 的包)
  • :deduped 当一个依赖被去重时(请注意,这并不总意味着该依赖已提升到 node_modules 根目录)
  • :overridden 当一个依赖被覆盖时
  • :extraneous 当存在依赖但未被定义为任何节点的依赖时
  • :invalid 当依赖版本超出其上级指定范围时
  • :missing 当在磁盘上未找到依赖时
  • :semver(<spec>, [selector], [function]) 匹配有效的 node-semver 版本或范围到选择器
  • :path(<path>) glob 匹配,基于相对于项目的依赖路径
  • :type(<type>) 基于当前已认可的类型
  • :outdated(<type>) 当依赖过时时

:semver(<spec>, [selector], [function])

:semver() 伪选择器允许使用 semver 方法比较每个节点的 package.json 字段。它最多接受 3 个参数,除了第一个参数之外,其余参数都是可选的。

🌐 The :semver() pseudo selector allows comparing fields from each node's package.json using semver methods. It accepts up to 3 parameters, all but the first of which are optional.

  • spec 是一个语义化版本或版本范围
  • selector 每个节点的属性选择器(默认 [version]
  • function 是一个用于应用的语义化版本方法,可选值为:satisfiesintersectssubsetgtgtegtrltlteltreqneq 或特殊函数 infer(默认 infer

当使用特殊的 infer 函数时,会比较 spec 和节点的实际值。如果两者都是版本号,则根据 semver.valid() 使用 eq。如果两者都是范围值,则根据 !semver.valid() 使用 intersects。如果两者的类型混合,则使用 satisfies

🌐 When the special infer function is used the spec and the actual value from the node are compared. If both are versions, according to semver.valid(), eq is used. If both values are ranges, according to !semver.valid(), intersects is used. If the values are mixed types satisfies is used.

一些例子:

🌐 Some examples:

  • :semver(^1.0.0) 返回每个其 version 被提供的范围 ^1.0.0 满足的节点
  • :semver(16.0.0, :attr(engines, [node])) 返回每个具有满足版本 16.0.0engines.node 属性的节点
  • :semver(1.0.0, [version], lt)每个version小于1.0.0的节点

:outdated(<type>)

:outdated 伪选择器从注册表中检索数据,并返回关于哪些依赖已过时的信息。类型参数可以是以下之一:

🌐 The :outdated pseudo selector retrieves data from the registry and returns information about which of your dependencies are outdated. The type parameter may be one of the following:

  • any(默认)存在一个比当前版本更高的版本
  • in-range 存在一个版本,它比当前版本更新,并且满足其至少一个依赖的需求
  • out-of-range 存在一个比当前版本更高的版本,但至少有一个依赖不满足
  • major 存在一个比当前版本大的主版本
  • minor 存在一个比当前版本大的 semver 次要版本
  • patch 存在一个比当前版本更高的 semver 补丁版本

除了伪选择器执行的过滤之外,还会向生成的对象添加一些额外的数据。每个节点的 queryContext 属性下可以找到以下数据。

🌐 In addition to the filtering performed by the pseudo selector, some extra data is added to the resulting objects. The following data can be found under the queryContext property of each node.

  • versions 是给定节点的所有可用版本的数组
  • outdated.inRange 是一个对象数组,每个对象都有 fromversions,其中 from 是依赖于当前节点的节点的磁盘位置,versions 是满足该依赖的所有可用版本的数组。只有在使用 :outdated(in-range) 时才会填充此字段。
  • outdated.outOfRange 是一个对象数组,与 inRange 的结构相同,但其中的 versions 数组包含所有不满足依赖的可用版本。只有在使用 :outdated(out-of-range) 时才会填充此数组。

一些例子:

🌐 Some examples:

  • :root > :outdated(major) 返回每个有新的 semver 主版本发布的直接依赖
  • .prod:outdated(in-range) 返回具有新版本的生产依赖,该新版本至少满足其某个边的要求

属性选择器

🌐 Attribute Selectors

属性选择器会在 package.json 中评估键/值对,如果它们是 String

🌐 The attribute selector evaluates the key/value pairs in package.json if they are Strings.

  • [] 属性选择器(即属性是否存在)
  • [attribute=value] 属性值等同于...
  • [attribute~=value] 属性值包含单词...
  • [attribute*=value] 属性值包含字符串...
  • [attribute|=value] 属性值等于或以...开头
  • [attribute^=value] 属性值以...开头
  • [attribute$=value] 属性值以...结尾

ArrayObject 属性选择器

🌐 Array & Object Attribute Selectors

通用的 :attr() 伪选择器标准化了一种模式,可用于选择通过 ArboristNode.package 元数据可访问的 ObjectObjectArrayArrays 属性。这允许超出顶层 String 评估的迭代属性选择。传递给 :attr() 的最后一个参数必须是 attribute 选择器或嵌套的 :attr()。见下面的示例:

🌐 The generic :attr() pseudo selector standardizes a pattern which can be used for attribute selection of Objects, Arrays or Arrays of Objects accessible via Arborist's Node.package metadata. This allows for iterative attribute selection beyond top-level String evaluation. The last argument passed to :attr() must be an attribute selector or a nested :attr(). See examples below:

Objects

/* return dependencies that have a `scripts.test` containing `"tap"` */
*: attr(scripts, [test~=tap]);

嵌套的 Objects

🌐 Nested Objects

嵌套对象表示为传递给 :attr() 的顺序参数。

🌐 Nested objects are expressed as sequential arguments to :attr().

/* return dependencies that have a testling config for opera browsers */
*: attr(testling, browsers, [~=opera]);

Arrays

Array 特别使用一个特殊/保留的 . 字符来替代典型的属性名称。当将 String 传递给选择器时,Arrays 也支持精确的 value 匹配。

Array 属性选择示例:

🌐 Example of an Array Attribute Selection:

/* removes the distinction between properties & arrays */
/* ie. we'd have to check the property & iterate to match selection */
*:attr([keywords^=react])
*:attr(contributors, :attr([name~=Jordan]))

Array 直接匹配到某个值的示例:

🌐 Example of an Array matching directly to a value:

/* return dependencies that have the exact keyword "react" */
/* this is equivalent to `*:keywords([value="react"])` */
*: attr([keywords=react]);

ObjectArray 示例:

🌐 Example of an Array of Objects:

/* returns */
*: attr(contributors, [email=ruyadorno @github.com]);

🌐 Groups

依赖组是根据包与其上级包的关系来定义的(即在 package.json 中定义的依赖类型)。这种方法以用户为中心,因为生态系统已经被训练首先将依赖按这些组来考虑。依赖可以包含在多个组中(例如,一个 prod 依赖也可能是一个 dev 依赖(因为它也被另一个 dev 依赖所需要)并且也可能是 bundled —— 针对此类依赖的选择器可以如下:*.prod.dev.bundled)。

🌐 Dependency groups are defined by the package relationships to their ancestors (ie. the dependency types that are defined in package.json). This approach is user-centric as the ecosystem has been taught to think about dependencies in these groups first-and-foremost. Dependencies are allowed to be included in multiple groups (ex. a prod dependency may also be a dev dependency (in that it's also required by another dev dependency) & may also be bundled - a selector for that type of dependency would look like: *.prod.dev.bundled).

  • .prod
  • .dev
  • .optional
  • .peer
  • .bundled
  • .workspace

请注意,目前 workspace 依赖始终是 prod 依赖。此外,.root 依赖也被视为 prod 依赖。

🌐 Please note that currently workspace deps are always prod dependencies. Additionally the .root dependency is also considered a prod dependency.

程序化用法

🌐 Programmatic Usage

  • ArboristNode 类有一个 .querySelectorAll() 方法
    • 此方法将根据有效的查询选择器返回经过筛选和平展的依赖树 Arborist Node 列表
const Arborist = require("@npmcli/arborist");
const arb = new Arborist({});
// root-level
arb.loadActual().then(async (tree) => {
// query all production dependencies
const results = await tree.querySelectorAll(".prod");
console.log(results);
});
// iterative
arb.loadActual().then(async (tree) => {
// query for the deduped version of react
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);
});

也可以看看

🌐 See Also