diff --git a/src/renderer/utils/__tests__/jsonPath.test.tsx b/src/renderer/utils/__tests__/jsonPath.test.ts similarity index 89% rename from src/renderer/utils/__tests__/jsonPath.test.tsx rename to src/renderer/utils/__tests__/jsonPath.test.ts index 49e75585f9..312522a63f 100644 --- a/src/renderer/utils/__tests__/jsonPath.test.tsx +++ b/src/renderer/utils/__tests__/jsonPath.test.ts @@ -5,7 +5,7 @@ import { convertKubectlJsonPathToNodeJsonPath, safeJSONPathValue } from "../jsonPath"; -describe("parseJsonPath", () => { +describe("convertKubectlJsonPathToNodeJsonPath", () => { it("should convert \\. to use indexed notation", () => { const res = convertKubectlJsonPathToNodeJsonPath(".metadata.labels.kubesphere\\.io/alias-name"); @@ -82,13 +82,13 @@ describe("safeJSONPathValue", () => { it("should convert boolean values to strings", () => { const res = safeJSONPathValue({ bar: false }, ".bar"); - expect(res).toBe("false"); + expect(res).toBe(false); }); it("should convert number values to strings", () => { const res = safeJSONPathValue({ bar: 0 }, ".bar"); - expect(res).toBe("0"); + expect(res).toBe(0); }); it("should join sliced entries with commas only", () => { @@ -103,7 +103,7 @@ describe("safeJSONPathValue", () => { ], }, ".bar[].foo"); - expect(res).toBe("1"); + expect(res).toBe(1); }); it("should join an array of values using JSON.stringify", () => { @@ -114,7 +114,7 @@ describe("safeJSONPathValue", () => { ], }, ".bar"); - expect(res).toBe(`["world","hello"]`); + expect(res).toEqual(["world", "hello"]); }); it("should stringify an object value", () => { @@ -122,7 +122,7 @@ describe("safeJSONPathValue", () => { foo: { bar: "bat" }, }, ".foo"); - expect(res).toBe(`{"bar":"bat"}`); + expect(res).toEqual({ "bar":"bat" }); }); it("should use convertKubectlJsonPathToNodeJsonPath", () => { @@ -155,7 +155,7 @@ describe("safeJSONPathValue", () => { const res = safeJSONPathValue(obj, ".spec.metrics[*].external.highWatermark.."); - expect(res).toBe("100, 100"); + expect(res).toEqual(["100", "100"]); }); it("should not throw if path is invalid jsonpath", () => { @@ -163,6 +163,16 @@ describe("safeJSONPathValue", () => { foo: { "hello.world": "bat" }, }, "asd["); - expect(res).toBe(""); + expect(res).toBe(undefined); + }); + + it("should retrive value with '/' in jsonpath", () => { + const res = safeJSONPathValue({ + foo: { + "hello/world": "bat", + }, + }, ".foo.hello/world"); + + expect(res).toBe("bat"); }); }); diff --git a/src/renderer/utils/jsonPath.ts b/src/renderer/utils/jsonPath.ts index 3ba970a044..57fffbaea9 100644 --- a/src/renderer/utils/jsonPath.ts +++ b/src/renderer/utils/jsonPath.ts @@ -6,7 +6,7 @@ import { JSONPath } from "@astronautlabs/jsonpath"; import { TypedRegEx } from "typed-regex"; -const slashDashSearch = /[\\-]/g; +const slashDashSearch = /[/\\-]/g; const pathByBareDots = /(?<=\w)\./; const textBeforeFirstSquare = /^.*(?=\[)/g; const backSlash = /\\/g; @@ -22,6 +22,7 @@ const trailingDotDot = /\.\.$/; * * Known shorthands: * - Leading `$` is optional (but implied) + * - The string `/` can be used without a leading `\` escapement * - The string `\.` is used to denote the "value of '.'" and not "next key" * - The string `-` can be used while not in quotes * - `[]` as shorthand for `[0]` @@ -75,7 +76,15 @@ function convertToIndexNotation(key: string, firstItem = false) { } } -function formatJSONValue(value: unknown) { +export function formatJSONValue(value: unknown): string { + if (value == null) { + return ""; + } + + if (Array.isArray(value)) { + return value.map(formatJSONValue).join(", "); + } + if (typeof value === "object") { return JSON.stringify(value); } @@ -88,21 +97,21 @@ function formatJSONValue(value: unknown) { * * This function will also stringify the value retreived from the object */ -export function safeJSONPathValue(obj: object, path: string): string { +export function safeJSONPathValue(obj: object, path: string): unknown { try { const parsedPath = JSONPath.parse(convertKubectlJsonPathToNodeJsonPath(path)); - const isSlice = parsedPath.some((exp: any) => exp.expression.type === "slice" || "wildcard"); + const isSlice = parsedPath.some((exp: any) => exp.expression.type === "slice" || exp.expression.type === "wildcard"); const value = JSONPath.query(obj, JSONPath.stringify(parsedPath), isSlice ? Infinity : 1); if (isSlice) { - return value.map(formatJSONValue).join(", "); + return value; } - return formatJSONValue(value[0]); + return value[0]; } catch (error) { // something failed console.warn("[JSON-PATH]: failed to parse jsonpath", error); - return ""; + return undefined; } }