PailUsage GuidesObject Tree Rendering

Object Tree Rendering

Render objects as ASCII tree structures

Last updated:

Object Tree Rendering

The renderObjectTree utility function converts JavaScript objects into visually appealing ASCII tree structures. This is useful for debugging, documentation, or displaying hierarchical data.

Installation

renderObjectTree is exported as a separate module to reduce bundle size:

import { renderObjectTree } from "@visulima/pail/object-tree";

Basic Usage

import { renderObjectTree } from "@visulima/pail/object-tree";

const user = {
    name: "Alice Johnson",
    age: 28,
    email: "alice@example.com",
    active: true,
};

console.log(renderObjectTree(user));

Output:

├─ name: Alice Johnson
├─ age: 28
├─ email: alice@example.com
└─ active: true

Nested Objects

Works seamlessly with nested object structures:

const config = {
    server: {
        host: "localhost",
        port: 3000,
        ssl: {
            enabled: true,
            cert: "/path/to/cert.pem",
        },
    },
    database: {
        type: "postgresql",
        connection: {
            host: "db.example.com",
            port: 5432,
        },
    },
};

console.log(renderObjectTree(config));

Output:

├─ server
│  ├─ host: localhost
│  ├─ port: 3000
│  └─ ssl
│     ├─ enabled: true
│     └─ cert: /path/to/cert.pem
└─ database
   ├─ type: postgresql
   └─ connection
      ├─ host: db.example.com
      └─ port: 5432

Custom Styling

Customize the tree appearance:

const data = {
    project: "MyApp",
    version: "2.1.0",
    contributors: 15,
};

console.log(
    renderObjectTree(data, {
        keyNeighbour: "├── ",
        keyNoNeighbour: "└── ",
        separator: " → ",
        spacerNeighbour: "│  ",
        spacerNoNeighbour: "   ",
    }),
);

Custom Render Function

Format values with a custom render function:

const metrics = {
    responseTime: 145, // milliseconds
    errorRate: 0.02, // percentage
    uptime: 99.9, // percentage
    requestsPerSecond: 1250,
};

console.log(
    renderObjectTree(metrics, {
        renderFn: (node) => {
            if (typeof node === "number") {
                if (node < 1) {
                    return `${(node * 100).toFixed(2)}%`;
                }
                if (node > 1000) {
                    return `${(node / 1000).toFixed(1)}k`;
                }
                return node.toString();
            }
            return ["boolean", "string"].includes(typeof node) ? String(node) : undefined;
        },
    }),
);

Output:

├─ responseTime: 145
├─ errorRate: 2.00%
├─ uptime: 99.90%
└─ requestsPerSecond: 1.3k

Sorting Keys

Sort object keys alphabetically or with a custom function:

const unsorted = {
    zebra: "animal",
    apple: "fruit",
    banana: "fruit",
    car: "vehicle",
};

console.log(
    renderObjectTree(unsorted, {
        sortFn: (a, b) => a.localeCompare(b),
    }),
);

Circular Reference Handling

Detects and handles circular references:

const circularObj = {
    name: "Circular Example",
    data: [1, 2, 3],
};

// Create circular reference
circularObj.self = circularObj;

console.log(
    renderObjectTree(circularObj, {
        breakCircularWith: " [↻ CIRCULAR]",
    }),
);

Output:

├─ name: Circular Example
├─ data: [1,2,3]
└─ self:  [↻ CIRCULAR]

Array Output

Get output as an array of lines instead of a single string:

const obj = {
    method: "GET",
    status: 200,
    cached: false,
};

const lines = renderObjectTree(obj, { joined: false });
lines.forEach((line, index) => {
    console.log(`${index + 1}: ${line}`);
});

Options

ObjectTreeOptions

interface ObjectTreeOptions {
    /** Text to display for circular references (default: " (circular ref.)") */
    breakCircularWith?: string | null;
    /** Whether to return as single string or array of lines (default: true) */
    joined?: boolean;
    /** Connector for neighbor keys (default: "├─ ") */
    keyNeighbour?: string;
    /** Connector for non-neighbor keys (default: "└─ ") */
    keyNoNeighbour?: string;
    /** Function to render node values (default: renders primitives) */
    renderFn?: (node: unknown) => string | undefined;
    /** Separator between key and value (default: ": ") */
    separator?: string;
    /** Function to sort object keys (default: natural order) */
    sortFn?: (a: string, b: string) => number;
    /** Spacer for neighbor branches (default: "│  ") */
    spacerNeighbour?: string;
    /** Spacer for non-neighbor branches (default: "   ") */
    spacerNoNeighbour?: string;
}

Use Cases

  • Debugging: Visualize complex nested objects
  • Documentation: Display configuration structures
  • CLI Tools: Show hierarchical data in terminal
  • Logging: Format object metadata for logs

Browser and Server Support

renderObjectTree works in both Node.js and Browser environments. It's a pure utility function with no platform-specific dependencies.

Support

Contribute to our work and keep us going

Community is the heart of open source. The success of our packages wouldn't be possible without the incredible contributions of users, testers, and developers who collaborate with us every day.Want to get involved? Here are some tips on how you can make a meaningful impact on our open source projects.

Ready to help us out?

Be sure to check out the package's contribution guidelines first. They'll walk you through the process on how to properly submit an issue or pull request to our repositories.

Submit a pull request

Found something to improve? Fork the repo, make your changes, and open a PR. We review every contribution and provide feedback to help you get merged.

Good first issues

Simple issues suited for people new to open source development, and often a good place to start working on a package.
View good first issues