@byc/json-ptr 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +27 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +41 -0
- package/dist/index.mjs.map +1 -0
- package/package.json +21 -0
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
//#region ../shared/src/types.d.ts
|
|
2
|
+
type JsonPrimitive = string | number | boolean | null;
|
|
3
|
+
type JsonValue = JsonPrimitive | {
|
|
4
|
+
[key: string]: JsonValue;
|
|
5
|
+
} | JsonValue[];
|
|
6
|
+
/**
|
|
7
|
+
* 递归还原 JSON Pointer 转义
|
|
8
|
+
*/
|
|
9
|
+
type DecodePointer<S extends string> = S extends `${infer T}~1${infer U}` ? `${T}/${DecodePointer<U>}` : S extends `${infer T}~0${infer U}` ? `${T}~${DecodePointer<U>}` : S;
|
|
10
|
+
/**
|
|
11
|
+
* 严格数字检查 (RE_STRICT_UINT)
|
|
12
|
+
*/
|
|
13
|
+
type IsStrictUint<S extends string> = S extends '0' ? true : S extends `${infer F}${infer R}` ? F extends '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' ? R extends '' ? true : R extends `${number}` ? R extends `${string}.${string}` ? false : true : false : false : false;
|
|
14
|
+
/**
|
|
15
|
+
* 访问处理:对齐运行时逻辑
|
|
16
|
+
*/
|
|
17
|
+
type PathToType<T, K extends string> = T extends any ? DecodePointer<K> extends keyof T ? T[DecodePointer<K>] : K extends `${infer _N extends number}` ? IsStrictUint<K> extends true ? _N extends keyof T ? T[_N] : undefined : undefined : undefined : never;
|
|
18
|
+
/**
|
|
19
|
+
* 递归解析 JSON Pointer
|
|
20
|
+
*/
|
|
21
|
+
type GetByPointer<T, P extends string> = P extends '' | '/' ? T : P extends `/${infer Head}/${infer Tail}` ? Tail extends '' ? PathToType<T, Head> : GetByPointer<PathToType<T, Head>, `/${Tail}`> : P extends `/${infer Last}` ? PathToType<T, Last> : T;
|
|
22
|
+
//#endregion
|
|
23
|
+
//#region src/index.d.ts
|
|
24
|
+
declare function seek<T extends JsonValue, P extends string>(obj: T, path: P): GetByPointer<T, P>;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { type GetByPointer, type JsonValue, seek };
|
|
27
|
+
//# sourceMappingURL=index.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../shared/src/types.ts","../src/index.ts"],"mappings":";KAAK,aAAA;AAAA,KACO,SAAA,GAAY,aAAA;EAAA,CAAmB,GAAA,WAAc,SAAA;AAAA,IAAc,SAAA;;;AAAvE;KAKK,aAAA,qBAAkC,CAAA,uCAChC,CAAA,IAAK,aAAA,CAAc,CAAA,MACtB,CAAA,uCACK,CAAA,IAAK,aAAA,CAAc,CAAA,MACtB,CAAA;;;;KAKD,YAAA,qBAAiC,CAAA,sBAElC,CAAA,kCACE,CAAA,+DACE,CAAA,qBAEE,CAAA,uBACE,CAAA;;;;KAUP,UAAA,wBAAkC,CAAA,eACnC,aAAA,CAAc,CAAA,gBAAiB,CAAA,GAC7B,CAAA,CAAE,aAAA,CAAc,CAAA,KAChB,CAAA,wCACE,YAAA,CAAa,CAAA,iBACX,EAAA,eAAiB,CAAA,GACf,CAAA,CAAE,EAAA;;;;KASF,YAAA,wBAAoC,CAAA,oBAC5C,CAAA,GACA,CAAA,0CACE,IAAA,cACE,UAAA,CAAW,CAAA,EAAG,IAAA,IACd,YAAA,CAAa,UAAA,CAAW,CAAA,EAAG,IAAA,OAAW,IAAA,MACxC,CAAA,4BACE,UAAA,CAAW,CAAA,EAAG,IAAA,IACd,CAAA;;;iBCpDQ,IAAA,WAAe,SAAA,mBAAA,CAA6B,GAAA,EAAK,CAAA,EAAG,IAAA,EAAM,CAAA,GAAI,YAAA,CAAa,CAAA,EAAG,CAAA"}
|
package/dist/index.mjs
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
//#region ../shared/src/constants.ts
|
|
2
|
+
/**
|
|
3
|
+
* 匹配严格的非负整数(不含前导零,除了 0 本身)
|
|
4
|
+
*/
|
|
5
|
+
const RE_STRICT_UINT = /^(?:0|[1-9]\d*)$/;
|
|
6
|
+
/**
|
|
7
|
+
* 危险键名集合,用于防止原型污染攻击
|
|
8
|
+
*/
|
|
9
|
+
const INVALID_KEYS = new Set([
|
|
10
|
+
"__proto__",
|
|
11
|
+
"constructor",
|
|
12
|
+
"prototype"
|
|
13
|
+
]);
|
|
14
|
+
/**
|
|
15
|
+
* JSON Pointer 转义符正则表达式
|
|
16
|
+
*/
|
|
17
|
+
const RE_ESC_1 = /~1/g;
|
|
18
|
+
const RE_ESC_0 = /~0/g;
|
|
19
|
+
//#endregion
|
|
20
|
+
//#region src/index.ts
|
|
21
|
+
function seek(obj, path) {
|
|
22
|
+
if (path === "" || path === "/") return obj;
|
|
23
|
+
if (path[0] !== "/") throw new Error(`Invalid JSON pointer: "${path}". Path must begin with a forward slash.`);
|
|
24
|
+
const segments = path.split("/").slice(1);
|
|
25
|
+
if (segments.length > 1 && segments[segments.length - 1] === "") segments.pop();
|
|
26
|
+
let result = obj;
|
|
27
|
+
for (const rawKey of segments) {
|
|
28
|
+
if (result == null || typeof result !== "object") return;
|
|
29
|
+
const key = rawKey.indexOf("~") !== -1 ? rawKey.replace(RE_ESC_1, "/").replace(RE_ESC_0, "~") : rawKey;
|
|
30
|
+
if (INVALID_KEYS.has(key)) return;
|
|
31
|
+
if (Array.isArray(result)) {
|
|
32
|
+
if (key === "-" || !RE_STRICT_UINT.test(key)) return;
|
|
33
|
+
result = result[key];
|
|
34
|
+
} else result = result[key];
|
|
35
|
+
}
|
|
36
|
+
return result;
|
|
37
|
+
}
|
|
38
|
+
//#endregion
|
|
39
|
+
export { seek };
|
|
40
|
+
|
|
41
|
+
//# sourceMappingURL=index.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../shared/src/constants.ts","../src/index.ts"],"sourcesContent":["/**\r\n * 匹配严格的非负整数(不含前导零,除了 0 本身)\r\n */\r\nexport const RE_STRICT_UINT = /^(?:0|[1-9]\\d*)$/;\r\n\r\n/**\r\n * 危险键名集合,用于防止原型污染攻击\r\n */\r\nexport const INVALID_KEYS = new Set(['__proto__', 'constructor', 'prototype']);\r\n\r\n/**\r\n * JSON Pointer 转义符正则表达式\r\n */\r\nexport const RE_ESC_1 = /~1/g;\r\nexport const RE_ESC_0 = /~0/g;\r\n","import { RE_ESC_1, RE_ESC_0, RE_STRICT_UINT, INVALID_KEYS } from '../../shared';\r\nimport type { GetByPointer, JsonValue } from '../../shared';\r\n\r\nexport function seek<T extends JsonValue, P extends string>(obj: T, path: P): GetByPointer<T, P>;\r\n\r\nexport function seek(obj: any, path: string): JsonValue | undefined {\r\n // 根路径处理:\"\" 或 \"/\" 指向原对象\r\n if (path === '' || path === '/') return obj;\r\n\r\n // 格式校验:非空路径必须以 \"/\" 开头\r\n if (path[0] !== '/') {\r\n throw new Error(`Invalid JSON pointer: \"${path}\". Path must begin with a forward slash.`);\r\n }\r\n\r\n // 路径切分\r\n const segments = path.split('/').slice(1);\r\n\r\n // 兼容性处理:如果以斜杠结尾(如 \"/a/\"), 去掉末尾产生的空片段\r\n if (segments.length > 1 && segments[segments.length - 1] === '') {\r\n segments.pop();\r\n }\r\n\r\n let result: any = obj;\r\n\r\n for (const rawKey of segments) {\r\n // 如果当前层级无法继续深入 (null 或非对象), 直接返回 undefined\r\n if (result == null || typeof result !== 'object') {\r\n return undefined;\r\n }\r\n\r\n // 将 ~1 还原为 /, 将 ~0 还原为 ~\r\n const key =\r\n rawKey.indexOf('~') !== -1 ? rawKey.replace(RE_ESC_1, '/').replace(RE_ESC_0, '~') : rawKey;\r\n\r\n if (INVALID_KEYS.has(key)) {\r\n return undefined;\r\n }\r\n\r\n // 属性访问逻辑\r\n if (Array.isArray(result)) {\r\n // 仅允许合法数字索引. \"-\" 在 get 操作中无意义, 返回 undefined\r\n if (key === '-' || !RE_STRICT_UINT.test(key)) {\r\n return undefined;\r\n }\r\n result = result[key as any];\r\n } else {\r\n // 对象访问, 包含对空字符串键名 \"\" 的支持\r\n result = result[key];\r\n }\r\n }\r\n\r\n return result;\r\n}\r\n\r\nexport type { GetByPointer, JsonValue };\r\n"],"mappings":";;;;AAGA,MAAa,iBAAiB;;;;AAK9B,MAAa,eAAe,IAAI,IAAI;CAAC;CAAa;CAAe;CAAY,CAAC;;;;AAK9E,MAAa,WAAW;AACxB,MAAa,WAAW;;;ACTxB,SAAgB,KAAK,KAAU,MAAqC;AAElE,KAAI,SAAS,MAAM,SAAS,IAAK,QAAO;AAGxC,KAAI,KAAK,OAAO,IACd,OAAM,IAAI,MAAM,0BAA0B,KAAK,0CAA0C;CAI3F,MAAM,WAAW,KAAK,MAAM,IAAI,CAAC,MAAM,EAAE;AAGzC,KAAI,SAAS,SAAS,KAAK,SAAS,SAAS,SAAS,OAAO,GAC3D,UAAS,KAAK;CAGhB,IAAI,SAAc;AAElB,MAAK,MAAM,UAAU,UAAU;AAE7B,MAAI,UAAU,QAAQ,OAAO,WAAW,SACtC;EAIF,MAAM,MACJ,OAAO,QAAQ,IAAI,KAAK,KAAK,OAAO,QAAQ,UAAU,IAAI,CAAC,QAAQ,UAAU,IAAI,GAAG;AAEtF,MAAI,aAAa,IAAI,IAAI,CACvB;AAIF,MAAI,MAAM,QAAQ,OAAO,EAAE;AAEzB,OAAI,QAAQ,OAAO,CAAC,eAAe,KAAK,IAAI,CAC1C;AAEF,YAAS,OAAO;QAGhB,UAAS,OAAO;;AAIpB,QAAO"}
|
package/package.json
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@byc/json-ptr",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"files": [
|
|
5
|
+
"dist",
|
|
6
|
+
"package.json"
|
|
7
|
+
],
|
|
8
|
+
"devDependencies": {
|
|
9
|
+
"tsdown": "^0.21.4",
|
|
10
|
+
"typescript": "^5.9.3",
|
|
11
|
+
"vitest": "^4.1.0"
|
|
12
|
+
},
|
|
13
|
+
"exports": {
|
|
14
|
+
".": "./dist/index.mjs",
|
|
15
|
+
"./package.json": "./package.json"
|
|
16
|
+
},
|
|
17
|
+
"scripts": {
|
|
18
|
+
"test": "vitest",
|
|
19
|
+
"build": "tsdown"
|
|
20
|
+
}
|
|
21
|
+
}
|