




















@@ -168,12 +168,17 @@ export function parseOcPath(input: string): OcPath {
168168fail(`Empty oc:// path: ${printable(input)}`, input, "OC_PATH_EMPTY");
169169}
170170171-const segments = splitRespectingBrackets(pathPart, "/", input);
172-for (const seg of segments) {
171+const rawSegments = splitRespectingBrackets(pathPart, "/", input);
172+for (const seg of rawSegments) {
173173if (seg.length === 0) {
174174fail(`Empty segment in oc:// path: ${printable(input)}`, input, "OC_PATH_EMPTY_SEGMENT");
175175}
176176}
177+const fileSeg = rawSegments[0];
178+const file = isQuotedSeg(fileSeg) ? unquoteSeg(fileSeg) : fileSeg;
179+validateFileSlot(file, input);
180+181+const segments = normalizeDeepJsonPathSegments(rawSegments, file, input);
177182if (segments.length > 4) {
178183fail(`Too many segments in oc:// path (max 4): ${printable(input)}`, input, "OC_PATH_TOO_DEEP");
179184}
@@ -193,13 +198,6 @@ export function parseOcPath(input: string): OcPath {
193198}
194199}
195200196-// Unquote the file slot — splitRespectingBrackets keeps a quoted file
197-// segment intact so its `/` isn't a slot separator; strip the quotes
198-// so consumers see the literal filename.
199-const fileSeg = segments[0];
200-const file = isQuotedSeg(fileSeg) ? unquoteSeg(fileSeg) : fileSeg;
201-validateFileSlot(file, input);
202-203201const session = extractSession(queryPart, input);
204202return {
205203 file,
@@ -210,6 +208,33 @@ export function parseOcPath(input: string): OcPath {
210208};
211209}
212210211+function isJsonPathFile(file: string): boolean {
212+const lower = file.toLowerCase();
213+return lower.endsWith(".json") || lower.endsWith(".jsonc");
214+}
215+216+function normalizeDeepJsonPathSegments(
217+segments: readonly string[],
218+file: string,
219+input: string,
220+): readonly string[] {
221+if (segments.length <= 4 || !isJsonPathFile(file)) {
222+return segments;
223+}
224+const pathSegments = segments.slice(1);
225+if (pathSegments.length > MAX_TRAVERSAL_DEPTH) {
226+fail(
227+`JSON oc:// path exceeds ${MAX_TRAVERSAL_DEPTH} nested segments: ${printable(input)}`,
228+input,
229+"OC_PATH_TOO_DEEP",
230+);
231+}
232+const section = pathSegments.slice(0, -2).join(".");
233+const item = pathSegments[pathSegments.length - 2];
234+const field = pathSegments[pathSegments.length - 1];
235+return [segments[0], section, item, field];
236+}
237+213238/** Format an `OcPath` struct into its canonical string form. */
214239export function formatOcPath(path: OcPath): string {
215240if (!path.file || path.file.length === 0) {
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。