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 🙏

© 2024 – Pkg Stats / Ryan Hefner

json-transformer-js

v4.0.2

Published

Transform an object with dynamic transforms, enabling controlled code execution of JSON 'rules'

Downloads

28

Readme

json-transformer-js

Transform an object (e.g parsed from JSON) through dynamic transforms, enabling JSON "rules" that allows controlled code execution.

Tip: Check out ploson if you need something more robust, simpler & more competent. This package is a kind of predecessor to ploson.

Intro

Imaging having this object (nonsense rules, but to show some different examples):

{
  values: ['%data%'],
  config: {
    width: ['%offset%', 100],
  },
  timestamp: ['%ts%'],
}

do:

transform(obj);

and get:

{
  values:[4, 7, 8, 10, 3, 1],
  config: {
    width: 116,
  },
  timestamp: 1530812733300,
}

What made that work was this simple setup (for node.js):

import getTransformer from 'json-transformer-js';

const offset = 16;
const transform = getTransformer({
  transforms: {
    '%offset%': (x) => x + offset,
    '%ts%': Date.now,
    '%data%': [4, 7, 8, 10, 3, 1],
  },
});

Lets look at a possibility of handling variables (both preset and dynamic) in an extended example:

import getTransformer from 'json-transformer-js';
import get from 'lodash.get';
import set from 'lodash.set';

const ctx = { offset: 16 };

const transform = getTransformer({
  defaultLevel1Transform: (v, k) => get(set(ctx, k, v), k),
  transforms: {
    '%get%': (k) => get(ctx, k),
    '%+%': (args) => args.reduce((r, v) => r + v, 0),
    '%ts%': () => new Date(),
    '%data%': [4, 7, 8, 10, 3, 1],
    '%sqMap%': (a) => a.map((x) => x * x),
  },
});

const transformed = transform({
  values: ['%data%'],
  config: {
    width: ['%+%', ['%get%', 'offset'], 100],
    squares: ['%sqMap%', ['%get%', 'values']],
  },
  timestamp: ['%ts%'],
}); /* -> {
  values: [ 4, 7, 8, 10, 3, 1 ],
  config: {
    width: 116,
    squares: [ 16, 49, 64, 100, 9, 1 ]
  },
  timestamp: 2018-07-05T18:46:42.703Z,
}
*/

Overview

So, this library is simply a depth-first parser of JS objects, making functions of your choice run when encountering certain key strings.

Options

Most of the features are best described through the different options that can be passed to getTransformer (default value after equals):

  • transforms = {}: The collection of transforms that will be used in the transform.
  • maxDepth = 100: A limit on the depth of the parsed object, basically to prevent that cyclic references hangs the thread.
  • defaultRootTransform = undefined: Set a function as an implicit default for the whole parsed data structure.
  • defaultLevel1Transform = undefined: If transforming an object, each value will be run through this (See example above).
  • leafTransform = undefined: Set this to a function in order to transform all simple/leaf values. Ex: arg => (typeof arg === 'string' ? arg.toLowerCase() : arg) to convert all strings anywhere in the transformed object to lower case.

Applied

Let's make something more interesting. Let's import JsonLogic, make it the "level 1" default, and make use of context. Let's also assume we have some websocket client that invokes our function onMessage when a message arrives, and allows for sending a response.

import getTransformer from 'json-transformer-js';
import jsonLogic from 'json-logic-js';

const rule = {
  threshold: 22,
  isTemperature: { '===': [{ var: 'data.type' }, 'temperature'] },
  warning: {
    and: [{ var: 'isTemperature' }, { '>': [{ var: 'data.payload.0' }, { var: 'threshold' }] }],
  },
  message: {
    if: [{ var: 'warning' }, 'Temperature is high', undefined],
  },
};

function onMessage(data, response) {
  const ctx = { data };
  getTransformer({
    defaultLevel1Transform: (v, k) => {
      const res = jsonLogic.apply(v, ctx);
      set(ctx, k, res);
      return res;
    },
  })(rule);
  if (tr.message) {
    response.send({ type: data.type, message: tr.message });
  }
}

The "rule" above should probably be dynamic and e.g. fetched from a database.

Licence

MIT

Change Log

3

  • All context handling removed (including options).
    • (Manual context handling is easy to add in use.)
  • Removed builtInTransforms (the %exec% transform. You can find it in the test file of the source in github).
  • Removed the built in %get% transform.
  • Much smaller footprint.

2

  • Removed objectSyntax & instead both work always.
  • defaultRootTransform is now actually for the root / the whole data structure, and
  • defaultLevel1Transform is the new name for default transform at level 1.
  • Both parameters above take functions, not transform references as strings, as before.
  • Flat transform arguments possible.

1.2

  • Added second parameter, contextInit, to the returned function, for dynamic context.

1.1

  • Added the leafTransform option/feature.

1.0

First official version.