Skip to content

Commit b61456f

Browse files
committed
modified: README.md
1 parent 914454d commit b61456f

File tree

1 file changed

+324
-1
lines changed

1 file changed

+324
-1
lines changed

README.md

Lines changed: 324 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,327 @@
1-
# A dead simple way to manipulate json tree objects
1+
# A dead simple way to manipulate JSON tree objects
2+
3+
The core idea is to transform a JSON tree object into a flat array, allowing standard operations like find, findIndex, filter, map, and others.
4+
5+
A mandatory requirement for the algorithm is that each element in the JSON tree must have a field with a unique identifier.
6+
7+
To preserve the tree structure and enable manipulations, the following computed properties are added to each child object:
8+
9+
```ts
10+
{
11+
// Array of objects representing the path from root to current node
12+
branch: Record < string, unknown > [];
13+
// Index of the object in the sibling array
14+
index: number;
15+
// Next object in the sibling array
16+
next: Record<string, unknown> | undefined;
17+
// Parent object
18+
parent: Record<string, unknown> | undefined;
19+
// Previous object in the sibling array
20+
prev: Record<string, unknown> | undefined;
21+
// Array of sibling objects
22+
siblings: Record < string, unknown > [];
23+
}
24+
```
25+
26+
The transformation is performed using the `useFlatJsonTree` composable:
27+
28+
```ts
29+
function useFlatJsonTree(
30+
// The JSON tree object
31+
tree: Record<string, unknown>[],
32+
// Optional object to define alternative names for id, children, and computed properties
33+
{
34+
branch,
35+
children,
36+
id,
37+
index,
38+
next,
39+
parent,
40+
prev,
41+
siblings,
42+
}?: {
43+
branch?: string | undefined;
44+
children?: string | undefined;
45+
id?: string | undefined;
46+
index?: string | undefined;
47+
next?: string | undefined;
48+
parent?: string | undefined;
49+
prev?: string | undefined;
50+
siblings?: string | undefined;
51+
},
52+
);
53+
```
54+
55+
The composable returns an object with the following properties:
56+
57+
```ts
58+
{
59+
// Computed flat array of objects (access via .value)
60+
leaves: ComputedRef<Record<string, unknown>[]>;
61+
// Reactive array of objects
62+
arrLeaves: Record<string, unknown>[];
63+
// Reactive object with unique IDs as keys
64+
objLeaves: {[id: string]: Record<string, unknown>;};
65+
// Service function to add an empty object to the tree
66+
add: (pId: string) => string | undefined;
67+
// Service function to remove an object from the tree
68+
remove: (pId: string) => string | undefined;
69+
// Service function to move an object down by one position
70+
down: (pId: string) => void;
71+
// Service function to move an object left by one position
72+
left: (pId: string) => string | undefined;
73+
// Service function to move an object right by one position
74+
right: (pId: string) => string | undefined;
75+
// Service function to move an object up by one position
76+
up: (pId: string) => void;
77+
}
78+
```
79+
80+
## Installation
81+
82+
```bash
83+
84+
npm i @vues3/flat-json-tree
85+
86+
```
87+
88+
## Usage
89+
90+
Assume we have a tree structure with elements like:
91+
92+
```ts
93+
{ id: number, name: string, children: [] }
94+
```
95+
96+
> [!WARNING]
97+
>
98+
> Elements can contain arbitrary fields, but must have a unique identifier
99+
100+
### Example using `useFlatJsonTree` composable
101+
102+
```js
103+
import useFlatJsonTree from "@vues3/flat-json-tree";
104+
105+
const tree = [
106+
{
107+
id: 1,
108+
name: "root",
109+
children: [
110+
{
111+
id: 2,
112+
name: "1.2",
113+
children: [
114+
{ id: 5, name: "1.2.5" },
115+
{ id: 6, name: "1.2.6" },
116+
],
117+
},
118+
{ id: 3, name: "1.3" },
119+
{
120+
id: 4,
121+
name: "1.4",
122+
children: [
123+
{ id: 7, name: "1.4.7" },
124+
{ id: 8, name: "1.4.8" },
125+
{ id: 9, name: "1.4.9" },
126+
],
127+
},
128+
],
129+
},
130+
];
131+
132+
const { leaves, arrLeaves, objLeaves, add, down, left, remove, right, up } =
133+
useFlatJsonTree(tree);
134+
```
135+
136+
Check the resulting flat array (using `JSON.stringify` to omit computed properties):
137+
138+
```js
139+
console.log(JSON.stringify(leaves.value));
140+
```
141+
142+
The result is a flat array containing all objects. Keep in mind that each object has computed properties added: `branch`, `index`, `next`, `parent`, `prev`, and `siblings`
143+
144+
```json
145+
[
146+
{
147+
"id": 1,
148+
"name": "root",
149+
"children": [
150+
{
151+
"id": 2,
152+
"name": "1.2",
153+
"children": [
154+
{ "id": 5, "name": "1.2.5" },
155+
{ "id": 6, "name": "1.2.6" }
156+
]
157+
},
158+
{ "id": 3, "name": "1.3" },
159+
{
160+
"id": 4,
161+
"name": "1.4",
162+
"children": [
163+
{ "id": 7, "name": "1.4.7" },
164+
{ "id": 8, "name": "1.4.8" },
165+
{ "id": 9, "name": "1.4.9" }
166+
]
167+
}
168+
]
169+
},
170+
{
171+
"id": 2,
172+
"name": "1.2",
173+
"children": [
174+
{ "id": 5, "name": "1.2.5" },
175+
{ "id": 6, "name": "1.2.6" }
176+
]
177+
},
178+
{ "id": 5, "name": "1.2.5" },
179+
{ "id": 6, "name": "1.2.6" },
180+
{ "id": 3, "name": "1.3" },
181+
{
182+
"id": 4,
183+
"name": "1.4",
184+
"children": [
185+
{ "id": 7, "name": "1.4.7" },
186+
{ "id": 8, "name": "1.4.8" },
187+
{ "id": 9, "name": "1.4.9" }
188+
]
189+
},
190+
{ "id": 7, "name": "1.4.7" },
191+
{ "id": 8, "name": "1.4.8" },
192+
{ "id": 9, "name": "1.4.9" }
193+
]
194+
```
195+
196+
Now let's try to find the object named "1.2.6":
197+
198+
```js
199+
console.log(JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6")));
200+
```
201+
202+
Output:
203+
204+
```json
205+
{ "id": 6, "name": "1.2.6" }
206+
```
207+
208+
If the ID is known, you can use `objLeaves`:
209+
210+
```js
211+
console.log(JSON.stringify(objLeaves[6]));
212+
```
213+
214+
Output:
215+
216+
```json
217+
{ "id": 6, "name": "1.2.6" }
218+
```
219+
220+
Now let's try using the computed properties. Suppose we need to find the parent element of the object named "1.2.6":
221+
222+
```js
223+
console.log(
224+
JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6").parent),
225+
);
226+
```
227+
228+
The result is the object named "1.2", which is the parent element of the object named "1.2.6":
229+
230+
```json
231+
{
232+
"id": 2,
233+
"name": "1.2",
234+
"children": [
235+
{ "id": 5, "name": "1.2.5" },
236+
{ "id": 6, "name": "1.2.6" }
237+
]
238+
}
239+
```
240+
241+
Now let's add the object `{ id: 10, name: "1.2.10" }` to the tree after the object named "1.2.6":
242+
243+
```js
244+
// Find the object named "1.2.6"
245+
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
246+
// Add the object { id: 10, name: "1.2.10" }
247+
curObject.siblings.splice(curObject.index + 1, 0, { id: 10, name: "1.2.10" });
248+
// Output the tree object passed to the useFlatJsonTree composable
249+
console.log(JSON.stringify(tree));
250+
```
251+
252+
Output:
253+
254+
```json
255+
[
256+
{
257+
"id": 1,
258+
"name": "root",
259+
"children": [
260+
{
261+
"id": 2,
262+
"name": "1.2",
263+
"children": [
264+
{ "id": 5, "name": "1.2.5" },
265+
{ "id": 6, "name": "1.2.6" },
266+
{ "id": 10, "name": "1.2.10" }
267+
]
268+
},
269+
{ "id": 3, "name": "1.3" },
270+
{
271+
"id": 4,
272+
"name": "1.4",
273+
"children": [
274+
{ "id": 7, "name": "1.4.7" },
275+
{ "id": 8, "name": "1.4.8" },
276+
{ "id": 9, "name": "1.4.9" }
277+
]
278+
}
279+
]
280+
}
281+
]
282+
```
283+
284+
Finally, let's test the service function. Move the object named "1.2.6" to the position before "1.2.5":
285+
286+
```js
287+
// Find the object named "1.2.6"
288+
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
289+
// Use the service function up to move it
290+
up(curObject.id);
291+
// Output the tree object passed to the useFlatJsonTree composable
292+
console.log(JSON.stringify(tree));
293+
```
294+
295+
As a result, the objects named "1.2.5" and "1.2.6" have swapped positions:
296+
297+
```json
298+
[
299+
{
300+
"id": 1,
301+
"name": "root",
302+
"children": [
303+
{
304+
"id": 2,
305+
"name": "1.2",
306+
"children": [
307+
{ "id": 6, "name": "1.2.6" },
308+
{ "id": 5, "name": "1.2.5" }
309+
]
310+
},
311+
{ "id": 3, "name": "1.3" },
312+
{
313+
"id": 4,
314+
"name": "1.4",
315+
"children": [
316+
{ "id": 7, "name": "1.4.7" },
317+
{ "id": 8, "name": "1.4.8" },
318+
{ "id": 9, "name": "1.4.9" }
319+
]
320+
}
321+
]
322+
}
323+
]
324+
```
2325

3326
> [!NOTE]
4327
>

0 commit comments

Comments
 (0)