src/object.js
function defineProp(object, name, opts = {}) {
  validateOptions(opts);

  var descriptor = Object.assign({
    name: name,
    get: null,
    set: null,
    default: undefined,
    on: [],
    cache: false,
    pure: !!(opts.get && opts.on && !opts.set),
  }, opts, {readonly: opts.get && !opts.set});

  if (!object.hasOwnProperty('__props__')) {
    object.__props__ = Object.create(object.__props__ || null);
  }

  object.__props__[name] = descriptor;

  if (!object.hasOwnProperty('__deps__')) {
    object.__deps__ = Object.create(object.__deps__ || null);
  }

  descriptor.on.forEach(function(prop) {
    (object.__deps__[prop] = object.__deps__[prop] || []).push(name);

    if (prop.indexOf('.') !== -1) {
      let segments = prop.split('.'), first = segments[0], last = segments[1];
      if (segments.length > 2) {
        throw new Error(`Transis.Object.defineProp: dependent property paths of more than two segments are not allowed: \`${prop}\``);
      }
      (object.__deps__[first] = object.__deps__[first] || []).push(name);
      (object.__deps__[`${first}@`] = object.__deps__[`${first}@`] || []).push(name);
      (object.__deps__[`${first}.${last}@`] = object.__deps__[`${first}.${last}@`] || []).push(name);
    }
    else {
      (object.__deps__[`${prop}@`] = object.__deps__[`${prop}@`] || []).push(name);
    }
  });

  Object.defineProperty(object, name, {
    get: function() { return this._getProp(name); },
    set: descriptor.readonly ? undefined : function(value) { this._setProp(name, value); },
    configurable: false,
    enumerable: true
  });
}
function defineProp(object, name, opts = {}) {
  validateOptions(opts);

  var descriptor = Object.assign({
    name: name,
    get: null,
    set: null,
    default: undefined,
    on: [],
    cache: false,
    pure: !!(opts.get && opts.on && !opts.set),
  }, opts, {readonly: opts.get && !opts.set});

  if (!object.hasOwnProperty('__props__')) {
    object.__props__ = Object.create(object.__props__ || null);
  }

  object.__props__[name] = descriptor;

  if (!object.hasOwnProperty('__deps__')) {
    object.__deps__ = Object.create(object.__deps__ || null);
  }

  descriptor.on.forEach(function(prop) {
    (object.__deps__[prop] = object.__deps__[prop] || []).push(name);

    if (prop.indexOf('.') !== -1) {
      let segments = prop.split('.'), first = segments[0], last = segments[1];
      if (segments.length > 2) {
        throw new Error(`Transis.Object.defineProp: dependent property paths of more than two segments are not allowed: \`${prop}\``);
      }
      (object.__deps__[first] = object.__deps__[first] || []).push(name);
      (object.__deps__[`${first}@`] = object.__deps__[`${first}@`] || []).push(name);
      (object.__deps__[`${first}.${last}@`] = object.__deps__[`${first}.${last}@`] || []).push(name);
    }
    else {
      (object.__deps__[`${prop}@`] = object.__deps__[`${prop}@`] || []).push(name);
    }
  });

  Object.defineProperty(object, name, {
    get: function() { return this._getProp(name); },
    set: descriptor.readonly ? undefined : function(value) { this._setProp(name, value); },
    configurable: false,
    enumerable: true
  });
}
Internal: Defines a property on the given object. See the docs for `Transis.prop`.  Returns nothing.