objectro

API

Get

Retrieve an object’s property value. Could be a shallow property or a nested property.

  objectro.get(
    input: object
      | function
      | (object | function)[],
    prop: string
      | number
      | (string | number)[],
    defaultValue?: any
  )
const objectro = require("objectro").default;

const input = {
  an: {
    example: {
      of: [
        {
          nested: {
            objects: [1, 2, 3]
          }
        }
      ]
    }
  }
};

get(input, "an.example.of[0].nested.objects[2]");
// -> 3

Set

Assign an object’s property value. Could be a shallow property or a nested property.

  objectro.get(
    input: object
      | function
      | any[],
    prop: string
      | number
      | (string | number)[],
    value: any
  )
const objectro = require("objectro").default;

const input = {
  an: {
    example: {
      of: [
        {
          nested: {
            objects: [1, 2, 3]
          }
        }
      ]
    }
  }
};

set(input, "an.example.of[0].nested.objects[2]", "nice!");

get(input, "an.example.of[0].nested.objects[2]");
// -> "nice!"

Transform

Transforming allows you to take an input object and describe how you want its property names and values to be reformatted.

  objectro.transform(
    input: object,
    propertyName: string
      | number
      | string[]
      | number[]
      | TransformMap
    ): object

Transforming will allow you to:

const objectro = require("objectro").default;

let input = {
  test1: 1,
  testB: "2",
  testC: "03,04,05"
};

// This transform map specifies how we want to reformat the input object
let outputMap = {
  // Takes `test1` from input and puts it on the output as `testA`
  test1: "testA",
  // Takes `testB` from input and formats its value on the
  // output as `testB`
  testB: value => parseInt(value, 10),
  // Takes `testC` from input and formats its value on the
  // output as `testC`, `testD` and `testE`
  testC: value => {
    let [testC, testD, testE] = value.split(",").map(val => parseInt(val, 10));
    return {
      testC,
      testD,
      testE
    };
  }
};

objectro.transform(input, outputMap);

// Outputs:
// {
//   testA: 1,
//   testB: 2,
//   testC: 3,
//   testD: 4,
//   testE: 5
// }

It’s worth noting that you don’t need to use a transform map if you only want to pluck certain values from an object. Instead of transform maps, you can use string values (or arrays of strings) to mark the properties you do want to keep:

const objectro = require("objectro").default;

let input = {
  testA: "Hello",
  testB: "This is a simple test",
  testC: "Don't need this property",
  testD: "Rename this property to testC"
};

objectro.transform(input, "testA", "testB");

// Outputs:
// {
//   testA: "Hello",
//   testB: "This is a simple test"
// }

You can combine all accepted argument types and objectro.transform will apply them in sequence:

objectro.transform(input, "testA", ["testB"], { testD: "testC" });

// Outputs:
// {
//   testA: "Hello",
//   testB: "This is a simple test",
//   testC: "Rename this property to testC"
// }

Transform Map

  {
    fromPropertyName: string
      | map: TransformMap
      | formatFn: Function(
        value: any,
        propName: string,
        input: object,
        output: object
      )
  }

A transform map is an object which maps an input object’s structure from one model to another.

The transform map will generally mimic the input object’s structure, however the values of each property can vary:

{
  fromPropertyName: "toPropertyName";
}

The above transforms from one property name on the input object to a different property name on the output object.

{
  fromPropertyName: {
    nestedObjectFromPropertyName: "toPropertyName";
  }
}

If fromPropertyName is a nested object, you can nest transform maps that will be applied to that nested object. Note that the nested objects will be placed under the fromPropertyName – if you need to change the parent property name, you can use a formatFn.

Using the formatFn method also allows more control over formatting the value and where that value will be placed in the output object.

  {
    fromPropertyName:
      (fromPropertyValue, propName, inputObject, outputObject) => {
        // Return either a new non-object value to be the new property
        // value, or return an object to merge into the output object.
        // This method is good for when you need to split one value into
        // multiple values or multiple properties on the output object.
        return {
          toPropertyName: fromPropertyValue
        }
      }
    }
  }

Validate

  objectro.validate(
    input: any,
    rules: ValidationRules,
    options: ValidationOptions
  ): boolean

You can verify an object’s structure and its contents using objectro.validate. You can also combine multiple rules and use rule modifiers to change behaviours of those rules.

Validation allows you to:

The simplest rules to use are:

The following rule modifiers change the behaviour of any nested rules:

const objectro = require("objectro").default;

function isDefined(input) {
  return input !== null && input !== undefined;
}

function validateExample(input) {
  return objectro.validate(input, {
    // All nested rules must positively match to be valid
    all: {
      // Check that the input type is an object
      type: "object",
      // Check if the input object has a "name" property
      // (we don't care if it's not defined)
      has: "name",
      // Run specific rules against multiple properties
      match: {
        // We can specify multiple rules for each named property
        age: {
          // These rules check if the "age" property is a string
          // and greater than or equal to 18
          type: "string",
          gte: 18
        },
        // Here we can enforce that we want the name to be defined
        // by using a custom function to validate the value
        name: isDefined
      }
    }
  });
}

validateExample({}); // false
validateExample({ example: true }); // false
validateExample("{}"); // false
validateExample({ name: "Example" }); // false
validateExample({ age: "55" }); // false
validateExample({ name: "Example", age: 16 }); // false
validateExample({ name: null, age: 35 }); // false
validateExample({ name: "Example", age: 35 }); // true

Using the ValidationOptions.data option, we can supply meta-data that can be validated if the original input object does not contain the referenced property:

const objectro = require("objectro").default;

const input = {
  name: "Matt Scheurich",
  nationality: "nz",
  location: "fr",
  languages: ["en", "fr"]
};

const canUnderstandEachOther = lang => {
  objectro.validate(
    input,
    {
      all: {
        has: {
          // Check if the languages field has the locale value assigned
          languages: lang,
          // This property is not on the original input object
          // however we do feed it via the `ValidationOptions.data` value
          systemLanguages: lang
        }
      }
    },
    {
      data: {
        systemLanguages: ["en", "de"]
      }
    }
  );
};

canUnderstandEachOther("fr");
// false: input.languages has "fr", but data.systemLanguages doesn't

canUnderstandEachOther("de");
// false: data.systemLanguages has "de", but input.languages doesn't

canUnderstandEachOther("en"); // true

Validation Rules

There are three types of rules:

Rule Type Description
any Modifier Return true if any nested rules match
all Modifier Return true only if all nested rules match
not Modifier Negate the return value: truefalse, falsetrue
has Expression, Map Check for existence of properties (using a string or Array<String>), or for possible values (using an object)
match Map Validate properties using nested ValidationRules objects for each property name
type Expression Check if input matches a specific type: string, number, integer, float, boolean, array, arrayLike, set, map, object, objectLike, plainObject, function (more)
eq Expression Equality (==)
eqs Expression Strict equality (===)
gt Expression Greater than
gte Expression Greather than or equals
lt Expression Less than
lte Expression Less than or equals
re Expression RegExp test
startsWith Expression Check if input starts with a value (can be affected by caseSensitive)
endsWith Expression Check if input ends with a value (can be affected by caseSensitive)
contains Expression Check if input (string or array) contains value (can be affected by caseSensitive if input is string)
includesAny Expression Check if input includes any values
includesAll Expression Check if input includes all values

There are more specialised rules available.

Validation Options

Option Type Description
matchAll boolean Return true only if all rules within the ValidationRules object match
negateMatch boolean Return the opposite of the match’s result
skipMissingProps boolean Pass any properties on the input object if they don’t exist or are undefined
caseSensitive boolean Enable or disable case sensitivity mode
data object Supply extra data to validate against. If the input object does not contain the property within the rules, objectro.validate will then check this object.