ceibo

Ceibo is a JavaScript micro library to model trees that evaluate arbitrary code when accessing its nodes.

Usage no npm install needed!

<script type="module">
  import ceibo from 'https://cdn.skypack.dev/ceibo';
</script>

README

Ceibo

Latest version

JavaScript micro library to model trees that evaluate arbitrary code when accessing its nodes.

The tree is modeled as a plain JavaScript object where each node has an arbitrary getter function. This allows to have a representation of a tree where a subtree is generated on the fly when a node is accessed.

Examples

Let's start by doing the most simple case, the identity case:

var root = Ceibo.create({
  foo: {
    bar: 'baz';
  }
});

console.log(root.foo.bar); // "baz"

You can create special node types called descriptors that allow you to respond to node access:

var root = Ceibo.create({
  foo: {
    isDescriptor: true,

    get() {
      return 'bar';
    }
  }
});

console.log(root.foo); // "bar"

As you can see, a descriptor is a JavaScript object that has a isDescriptor attribute.

You can define a get method or you can declare a value attribute, then the value attribute is going to be used as is:

var root = Ceibo.create({
  foo: {
    isDescriptor: true,

    value(answer) {
      return `The answer to life, the universe and everything is ${answer}`;
    }
  }
});

console.log(root.foo('42')); // "The answer to life, the universe and everything is 42"

descriptors can inspect and mutate the target object by defining a setup method:

var tree = Ceibo.create({
  foo: {
    isDescriptor: true,

    get() {
      return 'bar';
    },

    setup(target, keyName) {
      Ceibo.defineProperty(target, keyName.toUpperCase(), 'generated property');
    }
  }
});

console.log(tree.foo); // "bar"
console.log(tree.FOO); // "generated property"

Note that Ceibo trees are read-only, so you cannot reassign attributes:

var root = Ceibo.create({
  foo: 'bar';
});

root.foo = 'baz'; // => throws an error!

You can redefine how each value type is processed when the Ceibo tree is created:


function buildString(node, blueprintKey, value, defaultBuilder) {
  return defaultBuilder(node, blueprintKey, `Cuack ${value}`);
}

var root = Ceibo.create(
  {
    foo: 'first value'
  },
  {
    builder: {
      string: buildString
    }
  }
);

console.log(root.foo); // "Cuack first value"

Redefine how plain objects are processed to generate custom attributes:


function buildObject(node, blueprintKey, blueprint /*, defaultBuilder */) {
  var value = {
    generatedProperty: 'generated property'
  };

  // define current key and assign the new object
  Ceibo.defineProperty(node, blueprintKey, value);

  // continue to build the tree recursively
  return [value, blueprint];
}

var root = Ceibo.create(
  {
    foo: {
      bar: 'baz'
    }
  },
  {
    builder: {
      object: buildObject
    }
  }
);

console.log(tree.generatedProperty); // "generated property"
console.log(tree.foo.generatedProperty); // "generated property"
console.log(tree.foo.bar); // "baz"

You can navigate to parent nodes

var tree = Ceibo.create({
  foo: {
    bar: {
      baz: 'a value'
    }
  }
});

console.log(Ceibo.parent(tree.foo.bar).bar.baz); // "a value"

You can assign custom parents to trees

var parentTree = Ceibo.create({ foo: 'value' });
var childTree = Ceibo.create({ bar: 'another value' }, { parent: parentTree });

console.log(Ceibo.parent(childTree).foo); // "value"

Descriptor's get function receive the key when evaluated

var descriptor = {
  isDescriptor: true,

  get: function(key) {
    return key;
  }
};

var root = Ceibo.create({
  foo: descriptor,
  bar: descriptor
});

console.log(root.foo); // "foo"
console.log(root.bar); // "bar"

Ceibo's nodes store some meta data, you can access said meta data using Ceibo.meta function.

var descriptor = {
  isDescriptor: true,

  get: function(key) {
    var keys = [key];
    var node = this;
    var meta;

    do {
      meta = Ceibo.meta(node);

      keys.unshift(meta.key);
    } while(node = Ceibo.parent(node));

    return keys;
  }
};

var tree = Ceibo.create({
  foo: {
    bar: {
      baz: {
        qux: descriptor
      }
    }
  }
});

console.log(tree.foo.bar.baz.qux); // ['root', 'foo', 'bar', 'baz', 'qux']

Project's health

Build Status Codacy Badge

License

Ceibo is licensed under the MIT license.

See LICENSE for the full license text.