目录
依赖项选择器语法和查询
选择 CLI 版本
目录
描述
The npm query command exposes a new dependency selector syntax (informed by & respecting many aspects of the CSS Selectors 4 Spec) which
- Standardizes the shape of, & querying of, dependency graphs with a robust object model, metadata & selector syntax
- Leverages existing, known language syntax & operators from CSS to make disparate package information broadly accessible
- Unlocks the ability to answer complex, multi-faceted questions about dependencies, their relationships & associative metadata
- Consolidates redundant logic of similar query commands in
npm(ex.npm fund,npm ls,npm outdated,npm audit...)
依赖项选择器语法
概述
- there is no "type" or "tag" selectors (ex.
div, h1, a) as a dependency/target is the only type ofNodethat can be queried - the term "dependencies" is in reference to any
Nodefound in atreereturned byArborist
组合器
>direct descendant/childany descendant/child~sibling
选择器
*universal selector#<name>dependency selector (equivalent to[name="..."])#<name>@<version>(equivalent to[name=<name>]:semver(<version>)),selector list delimiter.dependency type selector:pseudo selector
依赖项类型选择器
.proddependency found in thedependenciessection ofpackage.json, or is a child of said dependency.devdependency found in thedevDependenciessection ofpackage.json, or is a child of said dependency.optionaldependency found in theoptionalDependenciessection ofpackage.json, or has"optional": trueset in its entry in thepeerDependenciesMetasection ofpackage.json, or a child of said dependency.peerdependency found in thepeerDependenciessection ofpackage.json.workspacedependency found in theworkspacessection ofpackage.json.bundleddependency found in thebundleDependenciessection ofpackage.json, or is a child of said dependency
伪选择器
:not(<selector>):has(<selector>):is(<selector list>):rootmatches the root node/dependency:scopematches node/dependency it was queried against:emptywhen a dependency has no dependencies:privatewhen a dependency is private:linkwhen a dependency is linked (for instance, workspaces or packages manuallylinked:dedupedwhen a dependency has been deduped (note that this does not always mean the dependency has been hoisted to the root of node_modules):overriddenwhen a dependency has been overridden:extraneouswhen a dependency exists but is not defined as a dependency of any node:invalidwhen a dependency version is out of its ancestors specified range:missingwhen a dependency is not found on disk:semver(<spec>, [selector], [function])匹配有效node-semver版本或范围到选择器:path(<path>)glob 匹配基于相对于项目的依赖路径:type(<type>)基于当前识别的类型:outdated(<type>)当依赖项过时时:vuln(<selector>)当依赖项存在已知漏洞时
:semver(<spec>, [selector], [function])
The :semver() 伪选择器允许使用 semver 方法比较每个节点的 package.json 中的字段。它最多接受 3 个参数,除了第一个参数之外都是可选的。
spec一个 semver 版本或范围selector每个节点的属性选择器(默认[version])function要应用的 semver 方法,以下之一:satisfies,intersects,subset,gt,gte,gtr,lt,lte,ltr,eq,neq或特殊函数infer(默认infer)
当使用特殊函数 infer 时,会比较 spec 和来自节点的实际值。如果两者都是版本,根据 semver.valid(),将使用 eq。如果两个值都是范围,根据 !semver.valid(),将使用 intersects。如果值是混合类型,将使用 satisfies。
一些示例
:semver(^1.0.0)返回每个version满足提供的范围^1.0.0的节点:semver(16.0.0, :attr(engines, [node]))返回每个engines.node属性满足版本16.0.0的节点:semver(1.0.0, [version], lt)每个version小于1.0.0的节点
:outdated(<type>)
The :outdated 伪选择器从注册表检索数据,并返回有关哪些依赖项过时的信息。类型参数可以是以下之一
any(默认)存在一个版本大于当前版本in-range存在一个版本大于当前版本,并且至少满足其父级的依赖项之一out-of-range存在一个版本大于当前版本,不满足其父级的依赖项之一major存在一个版本是 semver 主版本大于当前版本minor存在一个版本是 semver 次版本大于当前版本patch存在一个版本是 semver 修补程序版本大于当前版本
除了伪选择器执行的过滤之外,还会向结果对象添加一些额外的信息。以下数据可以在每个节点的 queryContext 属性下找到。
versions给定节点的所有可用版本的数组outdated.inRange对象数组,每个对象都有一个from和versions,其中from是依赖于当前节点的节点的磁盘位置,而versions是满足该依赖项的所有可用版本的数组。仅当使用:outdated(in-range)时才会填充此信息。outdated.outOfRange对象数组,形状与inRange相同,但versions数组是所有不满足依赖项的可用版本。仅当使用:outdated(out-of-range)时才会填充此信息。
一些示例
:root > :outdated(major)返回每个具有新 semver 主版本的直接依赖项.prod:outdated(in-range)返回具有满足其父级依赖项之一的新版本的生产依赖项
:vuln
The :vuln 伪选择器从注册表检索数据,并返回有关您的依赖项中是否存在已知漏洞的信息。仅当依赖项的当前版本与漏洞匹配时,才会返回依赖项。例如,如果您在树中具有 semver@7.6.0,则针对 semver 影响版本 <=6.3.1 的漏洞将不会匹配。
您还可以按咨询中的某些属性过滤结果。目前这包括 severity 和 cwe。请注意,严重性过滤是按严重性执行的,不包括指定严重性“更高”或“更低”的严重性。
除了伪选择器执行的过滤之外,有关每个相关咨询的信息将添加到每个节点的 queryContext 属性下的 advisories 属性中。
一些示例
:root > .prod:vuln返回具有任何已知漏洞的直接生产依赖项:vuln([severity=high])仅返回具有high严重性的漏洞的依赖项。:vuln([severity=high],[severity=moderate])仅返回具有high或moderate严重性的漏洞的依赖项。:vuln([cwe=1333])仅返回包含 CWE-1333(ReDoS)的漏洞的依赖项
属性选择器
属性选择器评估 package.json 中的键值对,如果它们是 String。
[]属性选择器(即属性的存在)[attribute=value]属性值等效于...[attribute~=value]属性值包含单词...[attribute*=value]属性值包含字符串...[attribute|=value]属性值等于或以...开头[attribute^=value]属性值以...开头[attribute$=value]属性值以...结尾
Array & Object 属性选择器
通用 :attr() 伪选择器标准化了一种模式,该模式可用于 Object、Array 或 Array 的 Object 属性选择,这些属性可以通过 Arborist 的 Node.package 元数据访问。这允许进行迭代属性选择,超出顶层 String 评估。传递给 :attr() 的最后一个参数必须是 attribute 选择器或嵌套的 :attr()。请参阅下面的示例
对象
/* return dependencies that have a `scripts.test` containing `"tap"` */*: attr(scripts, [test~=tap]);
嵌套的 Objects
嵌套对象表示为 :attr() 的顺序参数。
/* return dependencies that have a testling config for opera browsers */*: attr(testling, browsers, [~=opera]);
数组
Array 特别是在典型属性名称的位置使用特殊的/保留的 . 字符。 Array 还支持当将 String 传递给选择器时,进行精确的 value 匹配。
Array 属性选择示例
/* 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 直接匹配值的示例
/* return dependencies that have the exact keyword "react" *//* this is equivalent to `*:keywords([value="react"])` */*: attr([keywords=react]);
Array 的 Object 示例
/* returns */*: attr(contributors, [email=ruyadorno @github.com]);
组
依赖项组由包与其祖先的关系定义(即在 package.json 中定义的依赖项类型)。这种方法以用户为中心,因为生态系统已经被教导首先从这些组中思考依赖项。依赖项被允许包含在多个组中(例如,prod 依赖项也可能是 dev 依赖项(因为它也被另一个 dev 依赖项需要)并且也可能是 bundled - 针对这种类型依赖项的选择器将如下所示:*.prod.dev.bundled)。
.prod.dev.optional.peer.bundled.workspace
请注意,目前 workspace 依赖项始终是 prod 依赖项。此外,.root 依赖项也被视为 prod 依赖项。
编程方式使用
Arborist的Node类具有.querySelectorAll()方法- 该方法将根据有效的查询选择器返回过滤后的扁平化依赖项 Arborist
Node列表
- 该方法将根据有效的查询选择器返回过滤后的扁平化依赖项 Arborist
const Arborist = require("@npmcli/arborist");const arb = new Arborist({});
// root-levelarb.loadActual().then(async (tree) => {// query all production dependenciesconst results = await tree.querySelectorAll(".prod");console.log(results);});
// iterativearb.loadActual().then(async (tree) => {// query for the deduped version of reactconst results = await tree.querySelectorAll("#react:not(:deduped)");// query the deduped react for git depsconst deps = await results[0].querySelectorAll(":type(git)");console.log(deps);});