Skip to content

Commit 765802a

Browse files
committed
Fixed #84 Output paths
1 parent 13efbfe commit 765802a

File tree

9 files changed

+1848
-6199
lines changed

9 files changed

+1848
-6199
lines changed

package-lock.json

Lines changed: 1715 additions & 6146 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,11 +21,12 @@
2121
"@radix-ui/react-popover": "^1.1.4",
2222
"@radix-ui/react-select": "^2.1.4",
2323
"@radix-ui/react-slot": "^1.1.1",
24+
"@radix-ui/react-switch": "^1.1.3",
2425
"class-variance-authority": "^0.7.1",
2526
"clsx": "^2.1.1",
2627
"cmdk": "^1.0.0",
2728
"jotai": "^2.11.0",
28-
"jsonpath-js": "^0.1.0",
29+
"jsonpath-js": "^0.2.0",
2930
"jsonpath-plus": "^10.3.0",
3031
"lucide-react": "^0.469.0",
3132
"react": "^18.3.1",

src/components/editor/result.tsx

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,15 @@
11
import { useJSONPath } from "@/hooks/use-jsonpath";
22
import Editor from "@monaco-editor/react";
33

4-
export const Result = () => {
4+
interface ResultProps {
5+
outputPathMode: boolean;
6+
}
7+
8+
export const Result = ({ outputPathMode }: ResultProps) => {
59
const { result } = useJSONPath();
6-
const text = result.isValid ? JSON.stringify(result.result, null, 2) : "[]";
10+
const text = result.isValid
11+
? JSON.stringify(outputPathMode ? result.paths : result.values, null, 2)
12+
: "[]";
713

814
return (
915
<Editor

src/components/online-evaluator.tsx

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,12 @@
11
import { Query } from "./query";
22
import { JSONEditor } from "./editor/json-editor";
33
import { Result } from "./editor/result";
4+
import { OutputPathSwitch } from "./output-path-switch";
5+
import { useState } from "react";
46

57
export const JSONPathOnlineEvaluator = () => {
8+
const [outputPathMode, setOutputPathMode] = useState(false);
9+
610
return (
711
<div className="w-full flex flex-col gap-4">
812
<Query />
@@ -13,10 +17,13 @@ export const JSONPathOnlineEvaluator = () => {
1317
<JSONEditor />
1418
</div>
1519
<div>
16-
<h2 className="py-1 text-xl text-joe-green-950">
17-
Evaluation Results
18-
</h2>
19-
<Result />
20+
<div className="flex justify-between">
21+
<h2 className="py-1 text-xl text-joe-green-950">
22+
Evaluation Results
23+
</h2>
24+
<OutputPathSwitch onChange={setOutputPathMode} />
25+
</div>
26+
<Result outputPathMode={outputPathMode} />
2027
</div>
2128
</div>
2229
</div>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { Switch } from "@/components/ui/switch";
2+
import { Label } from "@/components/ui/label";
3+
4+
interface Props {
5+
onChange?: (pathOutput: boolean) => void;
6+
}
7+
8+
export const OutputPathSwitch = ({ onChange }: Props) => {
9+
return (
10+
<div className="flex items-center space-x-2">
11+
<Switch
12+
id="output-paths"
13+
onCheckedChange={(checked) => onChange?.(checked)}
14+
/>
15+
<Label htmlFor="output-paths">Output Paths</Label>
16+
</div>
17+
);
18+
};

src/components/ui/switch.tsx

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import * as React from "react"
2+
import * as SwitchPrimitives from "@radix-ui/react-switch"
3+
4+
import { cn } from "@/lib/utils"
5+
6+
const Switch = React.forwardRef<
7+
React.ElementRef<typeof SwitchPrimitives.Root>,
8+
React.ComponentPropsWithoutRef<typeof SwitchPrimitives.Root>
9+
>(({ className, ...props }, ref) => (
10+
<SwitchPrimitives.Root
11+
className={cn(
12+
"peer inline-flex h-5 w-9 shrink-0 cursor-pointer items-center rounded-full border-2 border-transparent shadow-sm transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 focus-visible:ring-offset-background disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=unchecked]:bg-input",
13+
className
14+
)}
15+
{...props}
16+
ref={ref}
17+
>
18+
<SwitchPrimitives.Thumb
19+
className={cn(
20+
"pointer-events-none block h-4 w-4 rounded-full bg-background shadow-lg ring-0 transition-transform data-[state=checked]:translate-x-4 data-[state=unchecked]:translate-x-0"
21+
)}
22+
/>
23+
</SwitchPrimitives.Root>
24+
))
25+
Switch.displayName = SwitchPrimitives.Root.displayName
26+
27+
export { Switch }

src/hooks/use-jsonpath.ts

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,21 @@
11
import { useAtom, useAtomValue } from "jotai";
22
import { atom } from "jotai";
33
import SampleJsonFile from "../assets/sample.json?raw";
4-
import { JSONValue } from "@/types/json";
5-
import { Engine } from "@/types/engine";
4+
import type { JSONValue } from "@/types/json";
5+
import type { Engine } from "@/types/engine";
66
import { evalJsonPath } from "@/lib/jsonpath";
77

88
type JSONPathResult =
99
| {
1010
isValid: true;
11-
result: JSONValue;
11+
values: JSONValue;
12+
paths: string[];
1213
error: undefined;
1314
}
1415
| {
1516
isValid: false;
16-
result: undefined;
17+
values: undefined;
18+
paths: undefined;
1719
error: string;
1820
};
1921

@@ -51,21 +53,23 @@ const resultAtom = atom<JSONPathResult>((get) => {
5153
const query = get(queryAtom).trim();
5254

5355
try {
54-
const result = evalJsonPath(
56+
const { values, paths } = evalJsonPath(
5557
get(engineAtom),
5658
jsonDocument.error === undefined ? jsonDocument.json : {},
5759
query
5860
);
5961

6062
return {
6163
isValid: true,
62-
result,
64+
values: values,
65+
paths: paths,
6366
error: undefined,
6467
};
6568
} catch (error) {
6669
return {
6770
isValid: false,
68-
result: undefined,
71+
values: undefined,
72+
paths: undefined,
6973
error: String(error),
7074
};
7175
}

src/index.css

Lines changed: 32 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -29,51 +29,52 @@ h3 {
2929
@layer base {
3030
:root {
3131
--background: 0 0% 100%;
32-
--foreground: 0 0% 3.9%;
32+
--foreground: 161 0% 0%;
3333
--card: 0 0% 100%;
34-
--card-foreground: 0 0% 3.9%;
34+
--card-foreground: 240 10% 3.9%;
3535
--popover: 0 0% 100%;
36-
--popover-foreground: 0 0% 3.9%;
37-
--primary: 0 0% 9%;
38-
--primary-foreground: 0 0% 98%;
39-
--secondary: 0 0% 96.1%;
40-
--secondary-foreground: 0 0% 9%;
41-
--muted: 0 0% 96.1%;
42-
--muted-foreground: 0 0% 45.1%;
43-
--accent: 0 0% 96.1%;
44-
--accent-foreground: 0 0% 9%;
36+
--popover-foreground: 240 10% 3.9%;
37+
--primary: 142.1 76.2% 36.3%;
38+
--primary-foreground: 355.7 100% 97.3%;
39+
--secondary: 240 4.8% 95.9%;
40+
--secondary-foreground: 240 5.9% 10%;
41+
--muted: 240 4.8% 95.9%;
42+
--muted-foreground: 240 3.8% 46.1%;
43+
--accent: 240 4.8% 95.9%;
44+
--accent-foreground: 240 5.9% 10%;
4545
--destructive: 0 84.2% 60.2%;
4646
--destructive-foreground: 0 0% 98%;
47-
--border: 0 0% 89.8%;
48-
--input: 0 0% 89.8%;
49-
--ring: 0 0% 3.9%;
47+
--border: 240 5.9% 90%;
48+
--input: 240 5.9% 90%;
49+
--ring: 142.1 76.2% 36.3%;
50+
--radius: 0.75rem;
5051
--chart-1: 12 76% 61%;
5152
--chart-2: 173 58% 39%;
5253
--chart-3: 197 37% 24%;
5354
--chart-4: 43 74% 66%;
5455
--chart-5: 27 87% 67%;
55-
--radius: 0.5rem;
5656
}
57+
5758
.dark {
58-
--background: 0 0% 3.9%;
59-
--foreground: 0 0% 98%;
60-
--card: 0 0% 3.9%;
61-
--card-foreground: 0 0% 98%;
62-
--popover: 0 0% 3.9%;
63-
--popover-foreground: 0 0% 98%;
64-
--primary: 0 0% 98%;
65-
--primary-foreground: 0 0% 9%;
66-
--secondary: 0 0% 14.9%;
59+
--background: 20 14.3% 4.1%;
60+
--foreground: 0 0% 95%;
61+
--card: 24 9.8% 10%;
62+
--card-foreground: 0 0% 95%;
63+
--popover: 0 0% 9%;
64+
--popover-foreground: 0 0% 95%;
65+
--primary: 142.1 70.6% 45.3%;
66+
--primary-foreground: 144.9 80.4% 10%;
67+
--secondary: 240 3.7% 15.9%;
6768
--secondary-foreground: 0 0% 98%;
68-
--muted: 0 0% 14.9%;
69-
--muted-foreground: 0 0% 63.9%;
70-
--accent: 0 0% 14.9%;
69+
--muted: 0 0% 15%;
70+
--muted-foreground: 240 5% 64.9%;
71+
--accent: 12 6.5% 15.1%;
7172
--accent-foreground: 0 0% 98%;
7273
--destructive: 0 62.8% 30.6%;
73-
--destructive-foreground: 0 0% 98%;
74-
--border: 0 0% 14.9%;
75-
--input: 0 0% 14.9%;
76-
--ring: 0 0% 83.1%;
74+
--destructive-foreground: 0 85.7% 97.3%;
75+
--border: 240 3.7% 15.9%;
76+
--input: 240 3.7% 15.9%;
77+
--ring: 142.4 71.8% 29.2%;
7778
--chart-1: 220 70% 50%;
7879
--chart-2: 160 60% 45%;
7980
--chart-3: 30 80% 55%;

src/lib/jsonpath.ts

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,38 @@
1-
import { Engine } from "@/types/engine";
1+
import type { Engine } from "@/types/engine";
22
import { JSONPath } from "jsonpath-plus";
3-
import { JSONValue } from "@/types/json";
3+
import type { JSONValue } from "@/types/json";
44
import { JSONPathJS } from "jsonpath-js";
55

66
export const evalJsonPath = (
77
engine: Engine,
88
document: JSONValue,
99
query: string
10-
) => {
10+
): { values: JSONValue[]; paths: string[] } => {
1111
switch (engine) {
12-
case "rfc9535":
13-
return new JSONPathJS(query).find(document);
14-
case "jsonpath-plus":
15-
return JSONPath({
12+
case "rfc9535": {
13+
const result = new JSONPathJS(query).paths(document);
14+
return {
15+
values: result.map((path) => path.value),
16+
paths: result.map((path) => path.path),
17+
};
18+
}
19+
case "jsonpath-plus": {
20+
const results = JSONPath({
1621
json: document,
1722
path: query,
18-
});
23+
resultType: "all",
24+
}) as {
25+
path: string;
26+
value: JSONValue;
27+
}[];
28+
29+
return {
30+
values: results.map((result) => result.value),
31+
paths: results.map((result) => result.path),
32+
};
33+
}
1934
default:
2035
engine satisfies never;
36+
throw new Error(`Unknown engine: ${engine}`);
2137
}
2238
};

0 commit comments

Comments
 (0)