Display a tree

Now that we’ve applied the AsyncTree interface to an object to create an async tree, let’s write a simple tool that will display the contents of that async tree in the console.

To stay as close to the platform as possible, we’ll render the tree in JSON format. JSON isn’t particularly friendly to write or read, but it’s built into the platform and supports hierarchical structures.

Convert an async tree to a plain object

An async tree is asynchronous, so we’ll need to either traverse it asynchronously and display its values as we go, or else resolve the entire tree to a synchronous, in-memory object. We’ll take the latter approach here.

// Resolve an async tree to an object with string keys and string values.
async function plain(tree) {
  const result = {};
  // Get each of the values from the tree.
  for (const key of await tree.keys()) {
    const value = await tree.get(key);
    result[key.toString()] = value.toString();
  }
  return result;
}

It may feel counter-productive to do work to wrap a synchronous in-memory object with the asynchronous AsyncTree interface — and then immediately unwind all those asynchronous promises to get back an in-memory object!

But we’ll soon be working with trees that are inherently asynchronous, so it’s worth tackling the general case now. We’ve still made an important step to separate the underlying representation of some hierarchical data with a tool to display such data.

Note: We could make this function more efficient if we didn’t await the result of each get call serially. Instead, we could kick off all the asynchronous requests, then wait for them all to resolve before continuing. That said, the simple approach here suffices.

Dynamically import a JavaScript module

We could write a tool to statically import a specific tree we want to display, but our goal is a utility that can quickly display any tree. So let’s have the tool parse a command line argument specifying the file name of a JavaScript module that exports a tree.

/* src/flat/json.js */

import path from "node:path";
import process from "node:process";
import { pathToFileURL } from "node:url";

async function plain(tree) { /* See above */ }

// Get a file name from the command line.
const [node, command, moduleName] = process.argv;
const modulePath = path.resolve(process.cwd(), moduleName);

// On Windows, import paths must be valid file:// URLs.
const moduleUrl = pathToFileURL(modulePath);

// Load the module.
const module = await import(moduleUrl);

// Take the module's default export as a tree.
const tree = module.default;

// Resolve the tree to an in-memory object.
const obj = await plain(tree);

// Convert to JSON text and display it.
const json = JSON.stringify(obj, null, 2);
console.log(json);

The tool dynamically imports the indicated JavaScript file and gets its default export, which is expected to be an async tree. We then use the plain function above to resolve the tree to an in-memory object, then render the JSON for that object to the console.

Display the tree in the console

Use this json utility from inside the src/flat directory to display the object.js tree we created in the previous step.

$ node json object.js
{
  "Alice.md": "Hello, **Alice**.",
  "Bob.md": "Hello, **Bob**.",
  "Carol.md": "Hello, **Carol**."
}

 

Next: Transform a tree »