0.6.20 • Published 6 months ago

@vues3/flat-json-tree v0.6.20

Weekly downloads
-
License
AGPL-3.0-only
Repository
github
Last release
6 months ago

A dead simple way to manipulate JSON tree objects

The core idea is to transform a JSON tree object into a flat array, allowing standard operations like find, findIndex, filter, map, and others.

A mandatory requirement for the algorithm is that each element in the JSON tree must have a field with a unique identifier.

To preserve the tree structure and enable manipulations, the following computed properties are added to each child object:

{
  // Array of objects representing the path from root to current node
  branch: Record < string, unknown > [];
  // Index of the object in the sibling array
  index: number;
  // Next object in the sibling array
  next: Record<string, unknown> | undefined;
  // Parent object
  parent: Record<string, unknown> | undefined;
  // Previous object in the sibling array
  prev: Record<string, unknown> | undefined;
  // Array of sibling objects
  siblings: Record < string, unknown > [];
}

The transformation is performed using the useFlatJsonTree composable:

function useFlatJsonTree(
  // The JSON tree object
  tree: Record<string, unknown>[],
  //  Optional object to define alternative names for id, children, and computed properties
  {
    branch,
    children,
    id,
    index,
    next,
    parent,
    prev,
    siblings,
  }?: {
    branch?: string | undefined;
    children?: string | undefined;
    id?: string | undefined;
    index?: string | undefined;
    next?: string | undefined;
    parent?: string | undefined;
    prev?: string | undefined;
    siblings?: string | undefined;
  },
);

The composable returns an object with the following properties:

{
  // Computed flat array of objects (access via .value)
  leaves: ComputedRef<Record<string, unknown>[]>;
  // Reactive array of objects
  arrLeaves: Record<string, unknown>[];
  // Reactive object with unique IDs as keys
  objLeaves: {[id: string]: Record<string, unknown>;};
  // Service function to add an empty object to the tree
  add: (pId: string) => string | undefined;
  // Service function to remove an object from the tree
  remove: (pId: string) => string | undefined;
  // Service function to move an object down by one position
  down: (pId: string) => void;
  // Service function to move an object left by one position
  left: (pId: string) => string | undefined;
  // Service function to move an object right by one position
  right: (pId: string) => string | undefined;
  // Service function to move an object up by one position
  up: (pId: string) => void;
}

Installation

npm i @vues3/flat-json-tree

Usage

Assume we have a tree structure with elements like:

{ id: number, name: string, children: [] }

!WARNING

Elements can contain arbitrary fields, but must have a unique identifier

Example using useFlatJsonTree composable

import useFlatJsonTree from "@vues3/flat-json-tree";

const tree = [
  {
    id: 1,
    name: "root",
    children: [
      {
        id: 2,
        name: "1.2",
        children: [
          { id: 5, name: "1.2.5" },
          { id: 6, name: "1.2.6" },
        ],
      },
      { id: 3, name: "1.3" },
      {
        id: 4,
        name: "1.4",
        children: [
          { id: 7, name: "1.4.7" },
          { id: 8, name: "1.4.8" },
          { id: 9, name: "1.4.9" },
        ],
      },
    ],
  },
];

const { leaves, arrLeaves, objLeaves, add, down, left, remove, right, up } =
  useFlatJsonTree(tree);

Check the resulting flat array (using JSON.stringify to omit computed properties):

console.log(JSON.stringify(leaves.value));

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

[
  {
    "id": 1,
    "name": "root",
    "children": [
      {
        "id": 2,
        "name": "1.2",
        "children": [
          { "id": 5, "name": "1.2.5" },
          { "id": 6, "name": "1.2.6" }
        ]
      },
      { "id": 3, "name": "1.3" },
      {
        "id": 4,
        "name": "1.4",
        "children": [
          { "id": 7, "name": "1.4.7" },
          { "id": 8, "name": "1.4.8" },
          { "id": 9, "name": "1.4.9" }
        ]
      }
    ]
  },
  {
    "id": 2,
    "name": "1.2",
    "children": [
      { "id": 5, "name": "1.2.5" },
      { "id": 6, "name": "1.2.6" }
    ]
  },
  { "id": 5, "name": "1.2.5" },
  { "id": 6, "name": "1.2.6" },
  { "id": 3, "name": "1.3" },
  {
    "id": 4,
    "name": "1.4",
    "children": [
      { "id": 7, "name": "1.4.7" },
      { "id": 8, "name": "1.4.8" },
      { "id": 9, "name": "1.4.9" }
    ]
  },
  { "id": 7, "name": "1.4.7" },
  { "id": 8, "name": "1.4.8" },
  { "id": 9, "name": "1.4.9" }
]

Now let's try to find the object named "1.2.6":

console.log(JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6")));

Output:

{ "id": 6, "name": "1.2.6" }

If the ID is known, you can use objLeaves:

console.log(JSON.stringify(objLeaves[6]));

Output:

{ "id": 6, "name": "1.2.6" }

Now let's try using the computed properties. Suppose we need to find the parent element of the object named "1.2.6":

console.log(
  JSON.stringify(arrLeaves.find(({ name }) => name === "1.2.6").parent),
);

The result is the object named "1.2", which is the parent element of the object named "1.2.6":

{
  "id": 2,
  "name": "1.2",
  "children": [
    { "id": 5, "name": "1.2.5" },
    { "id": 6, "name": "1.2.6" }
  ]
}

Now let's add the object { id: 10, name: "1.2.10" } to the tree after the object named "1.2.6":

// Find the object named "1.2.6"
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
// Add the object { id: 10, name: "1.2.10" }
curObject.siblings.splice(curObject.index + 1, 0, { id: 10, name: "1.2.10" });
// Output the tree object passed to the useFlatJsonTree composable
console.log(JSON.stringify(tree));

Output:

[
  {
    "id": 1,
    "name": "root",
    "children": [
      {
        "id": 2,
        "name": "1.2",
        "children": [
          { "id": 5, "name": "1.2.5" },
          { "id": 6, "name": "1.2.6" },
          { "id": 10, "name": "1.2.10" }
        ]
      },
      { "id": 3, "name": "1.3" },
      {
        "id": 4,
        "name": "1.4",
        "children": [
          { "id": 7, "name": "1.4.7" },
          { "id": 8, "name": "1.4.8" },
          { "id": 9, "name": "1.4.9" }
        ]
      }
    ]
  }
]

Finally, let's test the service function. Move the object named "1.2.6" to the position before "1.2.5":

// Find the object named "1.2.6"
const curObject = arrLeaves.find(({ name }) => name === "1.2.6");
// Use the service function up to move it
up(curObject.id);
// Output the tree object passed to the useFlatJsonTree composable
console.log(JSON.stringify(tree));

As a result, the objects named "1.2.5" and "1.2.6" have swapped positions:

[
  {
    "id": 1,
    "name": "root",
    "children": [
      {
        "id": 2,
        "name": "1.2",
        "children": [
          { "id": 6, "name": "1.2.6" },
          { "id": 5, "name": "1.2.5" }
        ]
      },
      { "id": 3, "name": "1.3" },
      {
        "id": 4,
        "name": "1.4",
        "children": [
          { "id": 7, "name": "1.4.7" },
          { "id": 8, "name": "1.4.8" },
          { "id": 9, "name": "1.4.9" }
        ]
      }
    ]
  }
]

!NOTE

Made on the shores of the Baltic Sea

License: AGPL

0.6.20

6 months ago

0.6.12

7 months ago

0.6.18

6 months ago

0.6.17

6 months ago

0.6.19

6 months ago

0.6.14

7 months ago

0.6.13

7 months ago

0.6.16

6 months ago

0.6.15

6 months ago

0.6.9

7 months ago

0.6.8

7 months ago

0.6.10

7 months ago

0.5.6

7 months ago

0.6.3

7 months ago

0.6.2

7 months ago

0.6.4

7 months ago

0.6.1

7 months ago

0.6.0

7 months ago

0.5.4

7 months ago

0.5.5

7 months ago

0.3.31

8 months ago

0.3.30

8 months ago

0.3.39

8 months ago

0.3.38

8 months ago

0.3.37

8 months ago

0.3.36

8 months ago

0.3.35

8 months ago

0.3.34

8 months ago

0.3.33

8 months ago

0.3.32

8 months ago

0.3.29

8 months ago

0.5.3

7 months ago

0.5.0

8 months ago

0.5.2

7 months ago

0.5.1

8 months ago

0.3.40

8 months ago

0.4.1

8 months ago

0.4.0

8 months ago

0.3.28

8 months ago

0.3.27

8 months ago

0.3.26

8 months ago

0.3.25

8 months ago

0.3.24

8 months ago

0.3.23

8 months ago

0.3.15

8 months ago

0.3.20

8 months ago

0.3.22

8 months ago

0.3.21

8 months ago

0.3.19

8 months ago

0.3.12

9 months ago

0.3.11

9 months ago

0.3.9

9 months ago

0.3.10

9 months ago

0.3.8

9 months ago

0.3.7

9 months ago

0.3.6

9 months ago

0.3.5

9 months ago

0.3.4

9 months ago

0.3.3

9 months ago

0.3.0

10 months ago

0.2.0

10 months ago

0.3.2

10 months ago

0.3.1

10 months ago

0.1.2

10 months ago

0.1.1

10 months ago

0.1.3

10 months ago

0.1.0

10 months ago