cdx- purl (英语)
严格,由定义驱动的软件包-url 解析器/构建器用于节点.js.
- 纯 Java 脚本
- 没有运行时间依赖关系
- ABNF 第一次严格剖析
- 类型规则来自
specification/types/*-definition.json输入generated/type-rules.js - 断断续续的教条化和圆通行为
安装
pnpm add @cdxgen/cdx-purl
npm install @cdxgen/cdx-purl
bun add @cdxgen/cdx-purl
deno add npm:@cdxgen/cdx-purl
快开始
import {
parse,
build,
roundTrip,
Purl,
NpmPurl,
MavenPurl,
TypedPurlBuilders,
TypedPurls,
} from "@cdxgen/cdx-purl";
const parsed = parse("pkg:npm/%40angular/[email protected]");
const built = build(parsed);
const canonical = roundTrip(built);
const npmPurl = NpmPurl.builder()
.setScope("@angular")
.setName("animation")
.setVersion("12.3.1")
.build()
.toString();
const MavenBuilder = TypedPurlBuilders.maven;
const mvn = new MavenBuilder()
.setNamespace("org.apache.commons")
.setName("io")
.buildString();
console.log(parsed, canonical, npmPurl, mvn, !!TypedPurls.swift);
API 密码
parse(input)分析并验证严格的ABNF + 类型规则build(parts)进行严格验证的运河建设roundTrip(input)剖析然后构建条形输出Purl不可移动的严格值对象PurlBuilder流利的通用构建器TypedPurlBuilders生成按类型键的构建者类TypedPurls已生成按类型键的已键分类getTypedPurlBuilder(type)财务报告和审定财务报表getTypedPurlClass(type)寻找助手
运行时注释 : index.js 产生的进口 TYPE_RULES_SOURCE 从 generated/type-rules.js; 不读 specification/types JSON执行时的文件.
所有已命名的打出导出( 例如 ) NpmPurlBuilder, (中文(简体) ), RpmPurl, (中文(简体) ), VscodeExtensionPurlBuilder)是混凝土生成的类,而不是占位符.
验证行为(按设计限制)
保留字符必须是%- 编码
在分离器之外,只有字母,数字, ., (中文(简体) ), -, (中文(简体) ), _, (中文(简体) ), ~ 财务报告和审定财务报表 : 可能
字面上出现在 purl 组件中(specification/purl-proposed-grammar.abnf) (中文(简体) ).
parse 而不是猜测什么,包括
页:1 + 和Debian或Go版本。 传出原始值
改为 build 它能逃避他们; parse 又解码了.
import { build, parse } from "@cdxgen/cdx-purl";
build({ type: "npm", name: "app", version: "1.0.0+build.5" });
// "pkg:npm/[email protected]%2Bbuild.5"
parse("pkg:npm/[email protected]%2Bbuild.5").version; // "1.0.0+build.5"
parse("pkg:npm/[email protected]+build.5");
// throws E_INVALID_CHARACTER:
// Invalid character "+" in version at index 5; percent-encode it as %2B
E_INVALID_CHARACTER 财务报告和审定财务报表 E_DISALLOWED_PERCENT_ENCODING 错误带入
违法 component (单位:千美元)name, (中文(简体) ), version, (中文(简体) ), namespace, (中文(简体) ), subpath 或者说
qualifier <key>页:1 index 在该组件原始文本中
character (或逃跑)在那里发现,和为 E_INVALID_CHARACTER 页:1
encoded 表格来代替。 必须写入的字符逃避
字面上( 简写为%41 页:1 A和一个逃走的分离者%2F 在命名空间中或
(子路径)以 E_DISALLOWED_PERCENT_ENCODING。 。 。 .
上游测试套房有几套解析和圆通箱,其输入离开
(单位:千美元) + 未回避( n)NSData+zlib, (中文(简体) ), Enterprise+Servercdx-purl 拒绝这些
投入;其逃出的形式产生准确的上游期望
(单位:千美元)test/reserved-character-errors.test.js) (中文(简体) ).
未知的修饰键被拒绝
import { build } from "@cdxgen/cdx-purl";
build({
type: "maven",
namespace: "org.apache.commons",
name: "io",
version: "1.3.4",
qualifiers: { mykey: "value" }, // throws E_UNKNOWN_QUALIFIER
subpath: null,
});
只接受明确允许的多值限定符
import { build } from "@cdxgen/cdx-purl";
// throws E_MULTIVALUE_QUALIFIER
build({
type: "maven",
namespace: "org.apache.commons",
name: "io",
version: "1.3.4",
qualifiers: { classifier: "sources,docs" },
subpath: null,
});
// allowed: checksum supports comma-delimited values
build({
type: "generic",
namespace: null,
name: "openssl",
version: "1.1.1w",
qualifiers: {
checksum:
"sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709,sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
},
subpath: null,
});
校验和值通过算法验证
校验和必须使用 algorithm:digest 形式。 库会对照内部算法映射来验证每个条目,并拒绝缺少一个算法,非hex,或选定算法错误长度的文摘.
import { parse } from "@cdxgen/cdx-purl";
// success: valid lengths for each algorithm
parse(
"pkg:generic/[email protected]?checksum=" +
"sha1:da39a3ee5e6b4b0d3255bfef95601890afd80709," +
"sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
);
// throws E_CHECKSUM_MISSING_ALGORITHM
parse(
"pkg:generic/[email protected]?checksum=da39a3ee5e6b4b0d3255bfef95601890afd80709",
);
// throws E_CHECKSUM_INVALID_DIGEST_FOR_ALGORITHM (wrong length)
parse("pkg:generic/[email protected]?checksum=sha256:abc123");
// throws E_CHECKSUM_INVALID_DIGEST_FOR_ALGORITHM (non-hex)
parse(
"pkg:generic/[email protected]?checksum=" +
"sha1:zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz",
);
要求的和被禁的类别字段得到执行
import { build } from "@cdxgen/cdx-purl";
// swift namespace is required and must contain host/owner
build({
type: "swift",
namespace: null, // throws E_REQUIRED_COMPONENT / E_SWIFT_NAMESPACE
name: "alamofire",
version: null,
qualifiers: null,
subpath: null,
});
虚空模块路径没有命名空间被接受
皮尔 golang 定义日期 访问模块并按要求标记命名空间 .
单块虚空模块路径, 如 go.opencensus.io 无效的 Go 模块
namespace,所以当名称类似主机(dot-separated 标签)时它们会被接受.
不类似主机的去名仍需要命名空间 .
import { parse } from "@cdxgen/cdx-purl";
parse("pkg:golang/[email protected]"); // ok, namespace is null
parse("pkg:golang/k8s.io"); // ok
parse("pkg:golang/context"); // throws E_REQUIRED_COMPONENT
构建器和对象流中的子路径验证
当您直接提供 purl 部件时(build, (中文(简体) ), Purl.from,键入的构建者), subpath 必须是相对的.
绝对类型值被拒绝 E_INVALID_SUBPATH 和一个可操作的信息.
这包括领导 / 和 Windows 绝对形式 C:\\docs\\api 或者说 \\\\server\\share\\docs。 。 。 .
import { build, parse } from "@cdxgen/cdx-purl";
// throws E_INVALID_SUBPATH
build({
type: "generic",
namespace: null,
name: "openssl",
version: "1.1.1w",
qualifiers: null,
subpath: "/docs/api",
});
// accepted: relative subpath
build({
type: "generic",
namespace: null,
name: "openssl",
version: "1.1.1w",
qualifiers: null,
subpath: "docs/api",
});
// parser compatibility: raw purl subpaths are canonicalized
// `//docs///api/` -> `docs/api`
parse("pkg:generic/[email protected]#//docs///api/"); // => { type: "generic", namespace: null, name: "openssl", version: "1.1.1w", qualifiers: null, subpath: "docs/api" }
支持的 purl 类型
库在生成时生成每类定义的打入类/构建器 specification/types/*-definition.json数字 :
alpm, (中文(简体) ), apk, (中文(简体) ), bazel, (中文(简体) ), bitbucket, (中文(简体) ), bitnami, (中文(简体) ), cargo, (中文(简体) ), chrome-extension, (中文(简体) ), cocoapods, (中文(简体) ), composer, (中文(简体) ), conan, (中文(简体) ), conda, (中文(简体) ), cpan, (中文(简体) ), cran, (中文(简体) ), deb, (中文(简体) ), docker, (中文(简体) ), gem, (中文(简体) ), generic, (中文(简体) ), github, (中文(简体) ), golang, (中文(简体) ), hackage, (中文(简体) ), hex, (中文(简体) ), huggingface, (中文(简体) ), julia, (中文(简体) ), luarocks, (中文(简体) ), maven, (中文(简体) ), mlflow, (中文(简体) ), npm, (中文(简体) ), nuget, (中文(简体) ), oci, (中文(简体) ), opam, (中文(简体) ), otp, (中文(简体) ), pub, (中文(简体) ), pypi, (中文(简体) ), qpkg, (中文(简体) ), rpm, (中文(简体) ), swid, (中文(简体) ), swift, (中文(简体) ), vscode-extension, (中文(简体) ), yocto。 。 。 .
| 需求领域 | 官方光谱来源 | 这个图书馆执行什么 | 主错误代码 |
|---|---|---|---|
| 标记类型和限定键外壳 | specification/purl-proposed-grammar.abnf + 类型定义 | 键入并修饰到小写; 决定修饰顺序 | E_INVALID_TYPE, (中文(简体) ), E_INVALID_QUALIFIER_KEY, (中文(简体) ), E_DUPLICATE_QUALIFIER |
| ABNF 严格解析规则 | specification/purl-proposed-grammar.abnf | 计划必须是 pkg; 严格的分隔符使用; 严格的%编码接受和解码 | E_INVALID_SCHEME, (中文(简体) ), E_INVALID_QUALIFIERS, (中文(简体) ), E_BAD_PERCENT_ENCODING, (中文(简体) ), E_DISALLOWED_PERCENT_ENCODING, (中文(简体) ), E_INVALID_SUBPATH |
构成部分所需经费namespace, (中文(简体) ), name, (中文(简体) ), version, (中文(简体) ), subpath(中文(简体) ) | specification/types/*-definition.json (单位:千美元)*_definition.requirement(中文(简体) ) | 要求/禁止/可选语义每种类型 | E_REQUIRED_COMPONENT, (中文(简体) ), E_PROHIBITED_COMPONENT, (中文(简体) ), E_MISSING_NAME, (中文(简体) ), E_MISSING_VERSION |
| 特征限制和正常化 | specification/types/*-definition.json (单位:千美元)permitted_characters, (中文(简体) ), normalization_rules, (中文(简体) ), case_sensitive(中文(简体) ) | 在验证和建造运河之前适用案例和正常化规则 | E_PERMITTED_CHARACTERS, (中文(简体) ), E_INVALID_CHARACTER |
| 按类型列出合格名单 | specification/types/*-definition.json (单位:千美元)qualifiers_definition(中文(简体) ) | 拒绝未知的修饰键, 但全局/ spec-compat 策略键除外 | E_UNKNOWN_QUALIFIER |
| 定性值 | 严格政策 | 除非明确允许,否则多值限定语被否决(checksum(中文(简体) ) | E_MULTIVALUE_QUALIFIER, (中文(简体) ), E_INVALID_QUALIFIER_VALUE, (中文(简体) ), E_CHECKSUM_MISSING_ALGORITHM, (中文(简体) ), E_CHECKSUM_INVALID_DIGEST_FOR_ALGORITHM |
| 所需限定词 | specification/types/*-definition.json (单位:千美元)qualifiers_definition.requirement(中文(简体) ) | 缺少必要的修饰符在解析和构建流程中被拒绝 | E_REQUIRED_QUALIFIER |
| 类型特定语义规则 | 类型规格和执行政策 | CPAN 大写作者命名空间和无 :: 分布式名称; Swift 主机/所有者命名空间形状 | E_CPAN_NAMESPACE, (中文(简体) ), E_CPAN_NAME, (中文(简体) ), E_SWIFT_NAMESPACE |
| 类型安全 | 从定义中生成的类型登记册 | 包含不匹配检测的每类类型已锁定的解析 | E_TYPE_MISMATCH |
规范化 opcode 模型
规范化规则 : specification/types/*-definition.json 编译为 opcode 数组 generated/type-rules.js。 。 。 .
index.js 应用这些 opcode 顺序通过 applyNormalizationRules(...) 并拒绝未知的密码 E_UNKNOWN_NORMALIZATION_OP。 。 。 .
当前拼接语义 :
to_lowercase: 小写全部值.apply_kebab_case: 崩溃非全美运行到-和修剪外接线(保留字母大小写).replace_underscore_with_dash: 替换全部_与-。 。 。 .replace_dot_with_underscore: 替换全部.与_。 。 。 .replace_non_alnum_with_underscore: 小写后替换每个非[a-z0-9]字符为_。 。 。 .
Opcode 优先级在生成器中解决(scripts/generate-type-rules.mjs因此,发射的阵列在再生过程中具有决定性.
对于相互冲突的规则,在运行时间之前适用优先。 PyPI 名称示例 :
replace_dot_with_underscorereplace_underscore_with_dash
这保证了对混血儿的宽容 A_B-C.D~x - > (中文) a-b-c-d~x。 。 。 .
已知的正常化限制
alpm.version包括一项正常化规则,即:vercmp(8)语义.- 此库目前保存
alpm支持而不应用版本正常化逻辑. - 解析和验证仍在运行
alpm,但无额外vercmp-基于重写适用于版本值.
测试命令
pnpm test
pnpm test:base
pnpm test:typed
pnpm test:typed:all
pnpm test:mutation
pnpm test:fuzz
决定模糊控制
PURL_FUZZ_SEED=1337
PURL_FUZZ_CASES=300
PURL_FUZZ_HOPS=10
PURL_FUZZ_MUTATION_CASES=200
PURL_TYPED_FUZZ_SEED=4242
PURL_TYPED_FUZZ_CASES=240
PURL_TYPED_FUZZ_HOPS=8
pnpm test:fuzz
覆盖范围包括:
- 基础固定兼容性测试
- 类型和建筑工覆盖所有登记类型
- 对抗性严格政策测试
- 根据类型定义生成的由变异驱动的负面测试
- 具有可再生种子的确定性模糊和突变模糊
支助政策
- 运行时间支持: 节点
>=20组合键>=1.0.0,德诺>=1.40.0 - CI 测试矩阵( 节点) :
20.x, (中文(简体) ),22.x, (中文(简体) ),24.x, (中文(简体) ),25.x - CI 运行时间烟雾覆盖率: Bun和Deno
- 构建和发布路径:节点
24.xnpm 信任的出版 + 来源
许可证
MIT许可证。 见 自由主义 详细情况.