尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

深入解析 @pnpm/object.property-path:pnpm 内部的对象属性路径解析与读写基础库

发布时间:2026/9/20 15:38:49

资讯中心
01
ARTICLE

深入解析 @pnpm/object.property-path:pnpm 内部的对象属性路径解析与读写基础库

深入解析 @pnpm/object.property-path:pnpm 内部的对象属性路径解析与读写基础库
包管理器开发工具CLI【免费下载链接】pnpmFast, disk space efficient package manager项目地址https://gitcode.com/gh_mirrors/pn/pnpm点击查看免费下载导读本文围绕 pnpm 11 仓库中的pnpm/object.property-path基础库展开系统讲解它如何解析并读写含点号.与下标[...]的对象属性路径覆盖路径语法、解析器实现、get/set/delete 三类读写操作、原型污染防护以及完整错误体系。读完本文你将掌握该库的全部公开 API 与底层实现原理并理解它如何支撑pnpm pkg与pnpm config等真实命令的嵌套字段操作。库的定位用字符串路径操作嵌套对象pnpm/object.property-path是一个Basic library to manipulate object property path which includes dots and subscriptions操作包含点号与下标的对象属性路径的基础库位于仓库的 pnpm11/object/property-path 目录。它解决的是一个非常典型的工程问题pnpm 的配置、package.json 清单、catalog 等都是深层嵌套结构例如scripts.build、packageExtensions[babel/parser].peerDependencies命令行场景下需要一种字符串形式的路径语法来定位任意深度的字段并完成读取、写入与删除。这里的 dots 指foo.bar.baz这样的点号分隔写法subscriptions下标指foo[0]、foo[bar]这样的方括号访问写法。库把字符串路径解析为string | number的段序列再基于该序列完成对象操作。从包元数据package.json可以看到该包当前版本为1100.1.6采用 ESMtype: module要求node 22.13唯一的外部依赖是pnpm/error用于定义标准化的 Pnpm 错误源码入口统一从 src/index.ts 导出。安装与包信息安装方式与 README 一致pnpm add pnpm/object.property-path其他包信息名称pnpm/object.property-path许可证MIT包入口lib/index.js类型声明lib/index.d.ts运行环境Node.js 22.13ESM 模块路径语法从字符串到段序列支持的写法解析核心是parsePropertyPath定义在 src/parse.ts 中。它是一个生成器函数签名如下export function * parsePropertyPath (propertyPath: string): Generatorstring | number, void, void即把字符串路径逐一产出为string标识符/字符串字面量或number数字字面量类型的段。函数文档注释给出了完整语法示例结合 test/parse.test.ts 中的断言可以得到如下等价关系路径字符串解析结果[]空路径foo[foo].foo[foo]允许前导点[foo]/[foo][foo][ foo ][foo]方括号内允许空白foo.bar[0][foo, bar, 0]foo[bar][0][foo, bar, 0]foo.bar[0][foo, bar, 0]引号内是字符串0是数字a .b .c .d[a, b, c, d]点号两侧允许空白注意foo.bar[0]与foo.bar[0]的区别带引号产出字符串段0不带引号产出数字段0。这个区分会直接影响读写语义——数字段会被当作数组下标处理。连字符键名包名、脚本名等经常包含连字符如some-package-name、build-prod因此标识符解析src/token/Identifier.ts在首字符为字母或下划线/[a-z_]/i后允许后续字符为[\w-]即字母、数字、下划线与连字符。于是parsePropertyPath(dependencies.some-package-name) // [dependencies, some-package-name] parsePropertyPath(scripts.build-prod) // [scripts, build-prod]这也呼应了源码注释中的设计意图Hyphens are in because package names are full of themnpm 包名充满连字符。字符串字面量转义方括号内的字符串字面量解析在 src/token/StringLiteral.ts 中支持单引号与双引号两种引用方式转义规则有限且严格仅支持\\、\、\、\b、\n、\r、\t。其他转义序列如\u会抛出UnsupportedEscapeSequenceError字符串未闭合则抛出IncompleteStringLiteralError。数字字面量的限制数字字面量解析在 src/token/NumericLiteral.ts 中。按源码注释出于严格性考虑当前不支持0x1A2E、1e20、123n这类十六进制、科学计数法或 BigInt 后缀写法遇到字母后缀会抛出UnsupportedNumericSuffix。词法分析器与非法路径路径解析分两层先由 src/token/tokenize.ts 把字符串切成 token点号、开闭方括号、标识符、数字字面量、字符串字面量、空白再由 src/parse.ts 依据状态机约束 token 顺序。tokenize对无法识别的字符产出unexpectedtoken最终由解析器抛出错误。测试中明确列出的非法路径包括foo.bar.0 // 点号后跟数字字面量 → UnexpectedLiteralError foo.bar.baz. // 尾部点号 → UnexpectedEndOfInputError foo.bar[0 // 方括号未闭合 → UnexpectedEndOfInputError foo.bar?.baz // 不支持的 ? 字符 → UnexpectedTokenError foo.bar[baz] // 方括号内出现标识符 → UnexpectedIdentifierError foo.bar..baz // 连续点号 → UnexpectedTokenError dependencies.-foo // 点号后跟连字符 → UnexpectedTokenError值得一提的特性是生成器的流式语义解析是惰性的调用方可以逐段消费路径遇到非法 token 时错误在消费到该位置才抛出partial parse测试验证了这一点。核心 API读取、写入、删除库公开的读写函数都提供两种形态接受已解析段序列Iterablestring | number的版本以及直接接受路径字符串的版本内部调用parsePropertyPath。读取getObjectValueByPropertyPath定义在 src/get.tsexport function getObjectValueByPropertyPath (object: unknown, propertyPath: Iterablestring | number): unknown export const getObjectValueByPropertyPathString (object: unknown, propertyPath: string): unknown ...读取规则test/get.test.ts 全部验证遇到非对象、null、自身不存在的键用Object.hasOwn判断、或用非数字访问数组时返回undefined绝不抛异常空路径返回对象本身getObjectValueByPropertyPathString(obj, )等价于obj不泄漏 JavaScript 内建属性由于使用Object.hasOwn而非原型链查找constructor、length、valueOf、prototype等原型属性一律返回undefinedpackages.length也不会意外读到数组长度字符串上无法用下标取字符getObjectValueByPropertyPathString(foo, [0])返回undefined。写入setObjectValueByPropertyPath定义在 src/set.tsexport function setObjectValueByPropertyPath (object: ObjectOrArray, propertyPath: Iterablestring | number, value: unknown): void写入规则test/set.test.ts 全部验证自动创建中间容器setObjectValueByPropertyPathString({}, scripts.build, tsc)会生成{ scripts: { build: tsc } }根据下一段类型决定数组还是对象下一段是数字则建数组是字符串则建对象。例如contributors[0].name生成{ contributors: [{ name: Alice }] }形状不匹配时替换容器如果中间节点已存在但形状不符标量需要变容器、数组需要变对象、对象需要变数组会替换为全新的容器保证写入结果能通过JSON.stringify无损往返。例如{ scripts: echo hi }上写scripts.test会把scripts整体替换为对象空路径抛错EmptyPropertyPathError错误码EMPTY_PROPERTY_PATH写入用Object.defineProperty而非括号赋值确保即使异常键漏过校验也只会创建自有属性不会触发原型 setter——这是防原型污染的最后一道保险详见下文安全机制。删除deleteObjectValueByPropertyPath定义在 src/delete.tsexport function deleteObjectValueByPropertyPath (object: ObjectOrArray, propertyPath: Iterablestring | number): void删除规则路径不存在时静默无操作no-op不抛错中间某段不是对象、为null、没有该自有键或非数字键访问数组时同样直接返回数组元素用splice删除不会留下null空洞isArrayIndex还会严格校验数组下标非负整数且为安全整数字符串形式如0也接受空路径直接返回与 set 的抛错行为不同同样会先做不安全键校验见下文。不安全键防护rejectUnsafeKeys定义在 src/unsafeKeys.tsset与delete在操作前都会调用它。它维护一个黑名单集合const UNSAFE_KEYS new Set([__proto__, constructor, prototype])路径中只要出现上述任意键就抛出UnsafePropertyPathKeyError错误码UNSAFE_PROPERTY_PATH_KEY从源头阻断通过__proto__.polluted这类路径进行的原型污染攻击。测试验证了三个键全部被拒绝且对象上不会出现polluted属性。错误体系一览所有错误均继承自pnpm/error的PnpmError因此会带ERR_PNPM_前缀便于 pnpm 统一的错误报告与排查。汇总如下错误类错误码触发场景UnexpectedTokenErrorUNEXPECTED_TOKEN_IN_PROPERTY_PATH语法错误字符?、-等或非法 token 顺序UnexpectedIdentifierErrorUNEXPECTED_IDENTIFIER_IN_PROPERTY_PATH方括号内出现标识符如foo.bar[baz]UnexpectedLiteralErrorUNEXPECTED_LITERAL_IN_PROPERTY_PATH点号后跟数字/字符串字面量如foo.bar.0UnexpectedEndOfInputErrorUNEXPECTED_END_OF_PROPERTY_PATH尾部点号、未闭合方括号EmptyPropertyPathErrorEMPTY_PROPERTY_PATH用空路径执行 setUnsafePropertyPathKeyErrorUNSAFE_PROPERTY_PATH_KEY路径含__proto__/constructor/prototypeUnsupportedEscapeSequenceErrorUNSUPPORTED_STRING_LITERAL_ESCAPE_SEQUENCE字符串字面量含不支持的转义IncompleteStringLiteralErrorINCOMPLETE_STRING_LITERAL字符串未闭合UnsupportedNumericSuffixUNSUPPORTED_NUMERIC_LITERAL_SUFFIX数字字面量带字母后缀在 pnpm 生态中的真实应用该库不是孤立的工具包而是 pnpm 11 中若干命令的底层依赖pnpm pkg get / set / delete命令实现位于 pkg.ts它对package.json清单直接调用getObjectValueByPropertyPathString、setObjectValueByPropertyPathString与deleteObjectValueByPropertyPathString。因此你可以这样操作嵌套字段pnpm pkg get scripts.build pnpm pkg set scripts.buildtsc pnpm pkg set contributors[0].nameAlice --json pnpm pkg delete scripts.build其中--json模式下值会先经JSON.parse再写入支持数组等结构化值--recursive/-r与--filter可对工作区多个项目批量执行。pnpm config get key实现位于 configGet.ts当键包含.或[或为空串时会被判定为属性路径并走lookupByPropertyPath将配置扁平化configToRecord后交给getObjectValueByPropertyPath读取。例如读取 catalog 或 packageExtensions 等嵌套配置时就能用点号/方括号路径直接定位。pnpm config set的键校验实现位于 configSet.ts它用parsePropertyPath解析用户传入的键空路径抛出CONFIG_SET_EMPTY_KEY深度超过 1 段则抛出CONFIG_SET_DEEP_KEYSetting deep property path is not supported——即config set刻意只允许单层键深层路径目前仅供config get读取。配置路径的 camelCase 适配parseConfigPropertyPath.ts 在parsePropertyPath之上做了包装——把首段统一转换为 camelCase以匹配配置内部configToRecord产出的驼峰键。从这些调用关系可以看出该库承担着 pnpm 命令与用户输入之间的路径语言职责用户写路径字符串库负责解析与安全读写。测试覆盖与质量保障包的测试位于 pnpm11/object/property-path/test 目录与源码一一对应parse.test.ts合法/非法路径、连字符键、流式部分解析get.test.ts路径存在/不存在、原型属性不泄漏、非对象输入、字符串不可按下标访问set.test.ts中间容器创建、形状替换、数组/对象互相转换、覆盖写、不安全键拒绝、空路径抛错另有 delete 测试与 token 级单元测试Identifier、NumericLiteral、StringLiteral、tokenize。这些测试既是对外契约的固化也是理解库行为边界的权威参考。包脚本中test命令为pn compile pn .test使用 Jestpreset 为pnpm/jest-config运行。小结pnpm/object.property-path虽是一个基础库却在 pnpm 11 的命令层扮演关键角色它定义了统一、严格、安全的属性路径语法提供解析、读取、写入、删除四类能力并通过Object.hasOwn自省读取、Object.defineProperty安全写入、__proto__/constructor/prototype黑名单三重机制防范原型污染。理解它也就理解了pnpm pkg、pnpm config get等命令背后用字符串操作嵌套对象的完整链路——无论是希望在自己的工具中复用这类路径语法还是深入 pnpm 源码这个库都是值得研读的范本。LicenseMIT赞分享包管理器开发工具CLI【免费下载链接】pnpmFast, disk space efficient package manager项目地址https://gitcode.com/gh_mirrors/pn/pnpm点击查看免费下载相关推荐es-toolkit 的 get 函数深度解析类型安全地按路径读取对象属性es toolkit 的 get 函数深度解析类型安全地按路径读取对象属性 get 是 es toolkit 兼容层compat中与 Lodash 完全对前端后端TypeScript Workshop项目实战从tsconfig配置到完整项目构建TypeScript Workshop项目实战从tsconfig配置到完整项目构建 TypeScript Workshop是一个全面的TypeScript学习包管理器开发工具CLIMyBatis 反射工具箱核心MetaObject 源码解析——统一属性读写、嵌套路径解析与对象包装器机制MyBatis 反射工具箱核心MetaObject 源码解析——统一属性读写、嵌套路径解析与对象包装器机制 MetaObject 是 MyBatis org.文档教程技术博客知识库创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。