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

extended-shape-json

v1.2.6

Published

util module for json object transformations

Downloads

6

Readme

Forked from https://github.com/ansteh/shape-json

Extended Shape-JSON

Shape-json package from ansteh, but with adding more fexibility and features :

  • Ignore unknown properties
  • Multiple arguments operations
  • Advanced arguments
  • Small fixes
  • More operations keywords
    • eval Compute value from complex input
    • or Select the first non-null or non-indefinite occurrence
    • foreach Iterations simpler
    • if Conditional value or nested object

Parse input by a scheme defined as json

Consider you want to transform the below json object, into a nested json object we used to from MEAN stack.

var input = [
  {pid: 1, contributor: 'jdalton', projectID: 1, projectName: 'lodash'},
  {pid: 1, contributor: 'jdalton', projectID: 2, projectName: 'docdown'},
  {pid: 1, contributor: 'jdalton', projectID: 3, projectName: 'lodash-cli'},
  {pid: 2, contributor: 'contra',  projectID: 4, projectName: 'gulp'},
  {pid: 3, contributor: 'phated',  projectID: 4, projectName: 'gulp'},
]

Instead of producing a lot of duplicated code to accomplish such transformations. We declare a scheme as a json object:

var scheme = {
  "$group[contributors](pid)": {
    "id": "pid",
    "name": "contributor",
    "$group[projects](projectID)": {
      "id": "projectID",
      "name": "projectName"
    }
  }
};
console.log(shape.parse(input, scheme));

This is what you get:

{
  "contributors": [
    {
      "id": 1,
      "name": "jdalton",
      "projects": [
        {
          "id": 1,
          "name": "lodash"
        },
        {
          "id": 2,
          "name": "docdown"
        },
        {
          "id": 3,
          "name": "lodash-cli"
        }
      ]
    },
    {
      "id": 2,
      "name": "contra",
      "projects": [
        {
          "id": 4,
          "name": "gulp"
        }
      ]
    },
    {
      "id": 3,
      "name": "phated",
      "projects": [
        {
          "id": 4,
          "name": "gulp"
        }
      ]
    }
  ]
}

Flexible syntax

Even if it is less useful, you have the possibility to modify the text of the operations by keeping some important keywords. This allows you to get a clearer model.

let template = {
    "currentTopic": "topic",
    "$foreach item of (data.books) push it on [library] section": {
        "bookIndex": "index",
        "bookAuthor": "author",
        "bookName": "name"
    }
}

Operators

foreach

This operator allows you to parse each element of a given array as input to another array with a new structure (defined in the template).

/* Input */
let input = {
    topic: "sample of books",
    data: {
        books: [
            { index: 1, author: 'bart', name: 'title1' },
            { index: 2, author: 'arya', name: 'title2' },
            { index: 3, author: 'gwen', name: 'title3' },
            { index: 4, author: 'arya', name: 'title4' },
            { index: 5, author: 'lara', name: 'title5' }
        ]
    }
}

/* Template */
let template = {
    "currentTopic": "topic",
    "$foreach[library](data.books)": {
        "bookIndex": "index",
        "bookAuthor": "author",
        "bookName": "name"
    }
}

console.log(shape.parse(input, template));
/*
{ 
    currentTopic: 'sample of books',
    library: [
        { bookIndex: 1, bookAuthor: 'bart', bookName: 'title1' },
        { bookIndex: 2, bookAuthor: 'arya', bookName: 'title2' },
        { bookIndex: 3, bookAuthor: 'gwen', bookName: 'title3' },
        { bookIndex: 4, bookAuthor: 'arya', bookName: 'title4' },
        { bookIndex: 5, bookAuthor: 'lara', bookName: 'title5' } 
    ] 
}
*/

eval

Templates allows "eval" keyword to be used in order to generate complex conditions from piece of code. Currently, you can get values from your input data with the "$value" operator, where a simple example is shown just below.

let input = { 
  name: 'marc',
  age: 25
}

let template = {
  "$eval[isMarc]": "$value(name) === 'marc'",
  "$eval[description]": "let a = $value(age); let n = $value(name); if(a > 18) n + ' is an adult'; else n + ' is a child'"
}

console.log(shape.parse(input, template));
/*
{ 
  "isMarc": true,
  "description": "marc is an adult" 
}
*/

or

The templates allow you to use the keywords "or" to select the first non-null or non-indefinite occurrence. This is useful when you can receive multiple entries whose structures may differ.

let input1 = {
  name: 'marc'
}

let input2 = {
  firstname: 'marc'
}

let input3 = {
  lastname: 'marc'
}

let template = {
  "$or[name]": [ 'name', 'firstname' ] // if "name" property is not defined, then we take "firstname" property
}

console.log(shape.parse(input1, template)); // { name: 'marc' }
console.log(shape.parse(input2, template)); // { name: 'marc' }

// If there is no valid property given, the "or" operator return "undefined", that result in ignoring template current property in the result  
console.log(shape.parse(input3, template)); // { }

if

This operator allows you to make a value or a nested object conditional, according to a custom condition statement.

let input1 = {
  a: true,
  c: { 'property1': 1 }
}

let input2 = {
  a: true,
  b: 1,
  c: { }
}

let template = {
  "$if(this.a == true && this.b == 1 && this.c !== null)[abcExists]": true
}

console.log(shape.parse(input1, template)); // {}

console.log(shape.parse(input2, template)); // { "abcExists": true }

Parsing nested json objects as input

let scheme = {
  "$mirror(id)": {
    "name": "event.name"
  }
};

let nestedInput = [{
  id: 1,
  event: {
    name: 'lookup',
  }
},{
  id: 2,
  event: {
    name: 'add',
  }
}];
console.log(shape.parse(nestedInput, scheme));
[ { "name": "lookup" }, { "name": "add" } ]

Another example:

var scheme = {
  "$mirror[projects](projectID)": {
    "project": {
      "id": "projectID",
      "name": "projectName"
    }
  }
};
console.log(shape.parse(input, scheme));
{
  "projects": [
    {
      "project": {
        "id": 1,
        "name": "lodash"
      }
    },
    {
      "project": {
        "id": 2,
        "name": "docdown"
      }
    },
    {
      "project": {
        "id": 3,
        "name": "lodash-cli"
      }
    },
    {
      "project": {
        "id": 4,
        "name": "gulp"
      }
    }
  ]
}

The same example as above as Array:

var scheme = {
  "$mirror(projectID)": {
    "project": {
      "id": "projectID",
      "name": "projectName"
    }
  }
};
console.log(shape.parse(input, scheme));
[
  {
    "project": {
      "id": 1,
      "name": "lodash"
    }
  },
  {
    "project": {
      "id": 2,
      "name": "docdown"
    }
  },
  {
    "project": {
      "id": 3,
      "name": "lodash-cli"
    }
  },
  {
    "project": {
      "id": 4,
      "name": "gulp"
    }
  }
]

Assign default values by scheme

var simpleAssignScheme = {
  "id": "pid",
  "$set[active]": true // true in all objects
};
console.log(shape.parse(input, simpleAssignScheme));
{ "id": 1, "active": true }

Extend parse method with own operation

shape.define('growth', function(operation, provider, scheme, helpers){
  var parse = helpers.parse;

  var modifiedProvider = provider.map(function(point){
    point.rate *= 100;
    return point;
  });

  return parse(modifiedProvider, scheme);
});

var scheme = {
  "$growth[growth]": {
    "$mirror[rates]": {
      "name": "name",
      "percent": "rate"
    }
  }
};

var input = [
  {
    "name": "test1",
    "rate": 0.1
  },{
    "name": "test2",
    "rate": 0.2
  }
];

var result = shape.parse(input, scheme);
//result equals:
{
  growth: {
    rates: [
      {
        "name": "test1",
        "percent": 10
      },{
        "name": "test2",
        "percent": 20
      }
    ]
  }
}

Create a scheme as object.

var scheme = shape.scheme()
  .mirror({ id: 'pid', last_name: 'lastName' })
  .indexBy('id');

Apply a scheme.

var inputs = [{
  pid: 1,
  lastName: 'Stehle',
  firstName: 'Andre'
},{
  pid: 2,
  lastName: 'lastname',
  firstName: 'firstname'
}];

console.log(scheme.form(inputs));
/*
  {
    1:{
      id: 1,
      last_name: 'Stehle'
    },
    2:{
      id: 2,
      last_name: 'lastname'
    }
  }
*/

API Documentation

mirror a collection

Mirror a json by a scheme.

var input = {
  pid: 1,
  lastName: 'Stehle',
  firstName: 'Andre'
};
var scheme = {
  id: 'pid',
  last_name: 'lastName',
};

console.log(shape.mirror(input, scheme));
/*
  {
    id: 1,
    last_name: 'Stehle'
  }
*/


var inputs = [{
  pid: 1,
  lastName: 'Stehle',
  firstName: 'Andre'
},{
  pid: 2,
  lastName: 'lastname',
  firstName: 'firstname'
}];

console.log(shape.mirror(inputs, scheme));
/*
  [{
    id: 1,
    last_name: 'Stehle'
  },{
    id: 2,
    last_name: 'lastname'
  }]
*/

indexing

Index an Array by a key.

var inputs = [{
  id: 1,
  last_name: 'Stehle'
},{
  id: 2,
  last_name: 'lastname'
}];

console.log(shape.indexBy(inputs, 'id'));
/*
  {
    1:{
      id: 1,
      last_name: 'Stehle'
    },
    2:{
      id: 2,
      last_name: 'lastname'
    }
  }
*/

chaining

Chaining previous examples.

var inputs = [{
  pid: 1,
  lastName: 'Stehle',
  firstName: 'Andre'
},{
  pid: 2,
  lastName: 'lastname',
  firstName: 'firstname'
}];

var result = shape.chain(inputs)
  .mirror(scheme)
  .indexBy('id')
  .collection;
console.log(result);
/*
  {
    1:{
      id: 1,
      last_name: 'Stehle'
    },
    2:{
      id: 2,
      last_name: 'lastname'
    }
  }
*/

Related

License

MIT © Andre Stehle