npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@rubicon2/object-transformer

v1.2.0

Published

Turn one object into a differently formatted object, via user-defined rules

Readme

object-transformer

Turn one object into a differently formatted object, via user-defined rules. Can use nested paths.

Install

npm install @rubicon2/object-transformer

Usage

import transformer, { copy, parseDate } from '@rubicon2/object-transformer';

const rules = {
  'user.age': copy({ key: 'where.age', parser: parseInt }),
  'date.from': copy({ key: 'where.date.gte', parser: parseDate }),
  'date.to': copy({ key: 'where.date.lte', parser: parseDate })
}

const input = {
  user: {
    age: '33'
  },
  date: {
    from: '2020-12-25',
    to: '2021-12-25'
  }
};

const myTransformer = transformer(rules);
const output = myTransformer(input);

// This will create the following output object.
output = {
  where: {
    age: 33,
    date: {
      gte: 2020-12-25T00:00:00.000Z
      lte: 2021-12-25T00:00:00.000Z
    }
  }
}

Transformer Parameters

When a transformer is instantiated, it can be passed a rules object and an options object.

Rules Parameter

This parameter should be of type object, and is used to contain rules for whatever input keys you want to process or manipulate. There are a few built-in special rules:

|Key|Description| |-|-| |_onStart|Runs before the user-defined rules begin running. Use this for any initialisation you might need.| |_onFinish|Runs after the final user-defined rule has finished, but before the built-in _temp object has been deleted. Use this to tie up any input data that depends on each other. As the rules are held in an object, there is no guarantee as to what order the rules will be run in. Therefore, if you are writing a rule that depends on the values produced by another rule, it may be easier to simply store the values on output._temp[key] and then tie them together in whatever way you want within the _onFinish rule, since this is guaranteed to run after all the other rules are finished.|

Options Parameter

This parameter should be of type object, and can utilise the following properties:

|Property|Default|Description| |--------|-------|-----------| |omitRulelessKeys|false|By default, any keys on the input object that don't match a rule will be copied over to the output as is. Set to true to ignore any input keys that do not have a rule explicitly set for them.| |omitEmptyStrings|false|This does nothing internally on the transformer, but is passed along with the other options to each rule function. The rule function can then use it to do whatever. The named export copy function uses this to decide whether to keep empty strings or not.| |pathSeparator|'.'|If nested input or output keys are being used, this will determine how the path segments are delineated. E.g. 'my.nested.path', 'my/nested/path'.| |nestedInputKeys|true|By default, a rule with a key of 'my.nested.key' will look for a value in { my: { nested: { key: 'my nested value' }}} on the input object, but if this is set to false, the rule will look for the value in { 'my.nested.key': 'my nested value' }.| |nestedOutputKeys|true|This does nothing internally on the transformer, but is passed along with the other options to each rule function. The rule function can then use it to do whatever. The named export copy function uses this to decide whether to use nested keys or flat keys, similarly to the transformer with the nestedInputKeys property.|

Rule Functions

Copy

For most purposes, the built-in copy rule can probably cover it. It can create nested output paths and parse the data with whatever parser you give it. It takes an object as its only parameter which can contain the following properties:

|Property|Default|Description| |-|-|-| |parser|(v) => v|This can be used to parse the input value into a different type. For example, you could use parseInt or parseFloat to get a number, String to parse the value into a string, JSON.parse to get boolean, arrays, or objects from strings, or import parseDate to easily parse a date value from a string. This can also be used to customise the result or if the value is of type object, include other properties.| |key|undefined|The key that will be used to store the value. Can be a nested path. If key is undefined, the function will just use the input key.| |destinationKey|undefined|This is a synonym for key, a leftover from version 1 after which I quickly got bored of typing this property name over and over. Way too long. Even 'outputKey' would have been shorter.| |conflictHandler|undefined|If conflictHandler is undefined, the deepMerge function will use its default, which puts non-object values on duplicate keys together into an array - zero data loss.| |options|{}|This can be used to override any properties on the options passed to the rule function by the transformer. Useful for customising the pathSeparator, omitEmptyStrings or nestedOutputKeys properties on a rule-by-rule basis.|

Using The Copy Parser to Create Complex Objects

The parser can be used for more than processing a string into another type. Consider the below:

const rules = {
  name: copy({
    key: 'where.name',
    parser: (value) => ({ contains: value, mode: 'insensitive' }),
  }),
  date: copy({
    key: 'where',
    parser: (value) => ({ date: parseDate(value) }),
  }),
};

const input = {
  name: 'jimmy',
  date: '2020-12-25',
};

const myTransformer = transformer(rules);
const output = myTransformer(input);
// Result:
// where: {
//   name: {
//     contains: 'jimmy',
//     mode: 'insensitive',
//   },
//   date: new Date('2020-12-25'),
// };

Writing a Custom Rule

If copy doesn't cover it, you can write your own rule like the following:

// This just copies the value from the input object onto the output object.
const myCustomRule = ({ output, key, value, options }) => {
  // Do not re-assign output itself like below - this will lose the reference to the original object.
  // output = { ...output, [key]: value }
  // But this is ok!
  output[key] = value;
}

const rules = {
  key1: myCustomRule,
  key2: myCustomRule
}

const input = {
  key1: 'a',
  key2: 'b',
}

const output = transformer(rules)(input);
// Result:
// output = {
//   key1: 'a',
//   key2: 'b',
// }

The parameters are passed to the function by the transformer. The output object is the final object returned by the transformer, the key and value are taken from the input object, and the options include any you provided when instantiating the transformer.

It is useful to curry functions to customise behaviour and do more complicated manipulations:

// This copies the value from the input object and puts it on a different key on the output object.
const copyToDifferentPath = (outputKey) => {
  // Don't need input key or options, so won't bother destructuring them.
  return ({ output, value }) => {
    output[outputKey] = value;
  }
}

const rules = {
  inputA: copyToDifferentPath('outputA'),
  inputB: copyToDifferentPath('outputB')
}

const input = {
  inputA: 'first',
  inputB: 'second',
}

const output = transformer(rules)(input);
// Result:
// output = {
//   outputA: 'first',
//   outputB: 'second'
// }

The _temp Object

When the object transformer starts processing the input, the output will be initialised to the following:

let output = {
  _temp: {}
};

This _temp object can be used to store any values you might need to keep from one rule to another, or to use within the _onFinish function, which runs after all user-defined rules but before the _temp object is removed. If one rule depends on data collected from another rule, instead of writing code that branches depending on whether the data has been collected or not, it would be simpler just to assign the data to a key on the _temp object, and then do whatever needs to be done within the _onFinish function.

The _temp object is prefixed with an underscore (like _onStart and _onFinish) to indicate that it is used internally and cleared at the end of the function, and to reduce the likelihood of naming conflicts with user-defined output object keys.