Coder Social home page Coder Social logo

jsonifier's Introduction

jsonifier

Dynamically generates JSON output from templates.

Build Status Coverage Status

Build Status Coverage Status

Installation

npm install --save-dev jsonifier

Usage

const jsonifier = require('jsonifier');

let base = new jsonifier().add('a.b.c', {
       'bob': () => 'woot',
       'countdown': function* count() {
            for(let i=4; i > 0; i--) {
                yield i;
            }
       }
    });

let child = new jsonifier(base, {namespace: 'data'}).add({
        'sample_gen': function* sample() {
            let cycle = ['start', 'middle', 'end'];
            while(true) {
                yield* cycle;
            }
        },
        'normal': {
            1: ['a', 'b'],
            2: 'ok'
        }
    });

Calling jsonifier#build returns a generator

// This creates a generator

> console.log(base.next().value);

    { a: { b: { c: { bob: 'woot', countdown: 4 } } } }

> let max = 4;
> for (let data of child.build()) {
>   console.log(data);
>   if (--max <= 0) break;
> }

    { a: { b: { c: { bob: 'woot', countdown: 4 } } },
      data:
       { sample_gen: 'start',
         normal: { '1': { '0': 'a', '1': 'b' }, '2': 'ok' } } }
    { a: { b: { c: { bob: 'woot', countdown: 3 } } },
      data:
       { sample_gen: 'middle',
         normal: { '1': { '0': 'a', '1': 'b' }, '2': 'ok' } } }
    { a: { b: { c: { bob: 'woot', countdown: 2 } } },
      data:
       { sample_gen: 'end',
         normal: { '1': { '0': 'a', '1': 'b' }, '2': 'ok' } } }
    { a: { b: { c: { bob: 'woot', countdown: 1 } } },
      data:
       { sample_gen: 'start',
         normal: { '1': { '0': 'a', '1': 'b' }, '2': 'ok' } } }

Constructor Options

  • namespace: [optional] decimal separated namespace. All objects JSONifier#add are nested in the namespace. E.g. 'a.b.c' => {'a': {'b': {'c': ... }}}

  • limit: [default: -1] maximum number of times the JSONifier#build generator will produce values

  • compiler: [optional] a function which is called to convert the internal state into a JSON object of static values.

Features

Inheritance

Concisely define data structures (useful for generating test data)

let child = new jsonifier(base)
    .add('a.b', {
        'd': function *() {
            yield* 'What could this possibly do?';
        }
    })
    .add({
        a: {
            f: 'foo'
        }
    });

let gen = child.build();

> console.log(gen.next().value);
> console.log(gen.next().value);
> console.log(gen.next().value);

    { "a": { "b": { "d": "W" } } }
    { "a": { "b": { "d": "h" } } }
    { "a": { "b": { "d": "a" } } }

Respects order of addition

// Using child defined above
let clean = new jsonifier(child)
    .add({
        a: 'wooter',
        f: 'funk town'
    });

> console.log(gen.next().value);

    { "a": { "b": { "d": "a" } } }

> console.log(clean.next().value);

    { "a": "wooter", "b": "funk town" }

Namespaces

let ns = new jsonifier(clean, { namespace: 'woot'})
    .add({
        a: 1,
        b: 2
    });

> console.log(ns.build().next());

    {
        "a": "wooter", "b": "funk town",
        "woot": {
            "a": 1,
            "b": 2
        }
    }

jsonifier's People

Contributors

blakef avatar

Stargazers

 avatar  avatar  avatar

Watchers

 avatar

jsonifier's Issues

Iterator runs infinitely if limit isn't defined

Problem

let test = new jsonifier().add('test', function* test() { yield 1 });
for (let t of test.build()) {
   console.log(t);
}
> { 'test': 1 }
> { 'test': undefined }
> { 'test': undefined }
> { 'test': undefined }
...

The current solution is to use the limit parameter. This isn't very elegant.

Proposal

Limit now represents these 3 options:

  1. Undefined: run until all generators in the jsonifier object have completed
  2. -1: Run indefinitely, returning undefined for generators which have completed
  3. n, n is natural number. Run for n iterations.

Overloading jsonifier getter / setter doesn't work

Fixes for #4, meant I had to pull the tests for this feature. The idea was that you could extend a class with JSONifier and have some control over how it internally stored objects before build.

This hasn't really every worked, and is a feature which would be useful.

Converts arrays to objects

The following doesn't work:

let test = new JSONifier().add({a:[{b: () => 'failure'}])
> test.build().next().value
> { 'a': { '0': 'failure' } }

When we expect:

> {'a': ['failure']}

namespace inheritance broken

When inheriting multiple jsonifier objects with namespaces, you only have the child's states. That is to say all the inherited states are lost.

Nesting tests incorrect

Nesting isn't working, tests don't cover correctly. This is the expected behaviour:

Examples:

let a = new JSONifier({namespace: 'a'}).add({1:2});
> a.build({nest: true}).next().value
{'a': {'1': '2'}}
> a.build({nest: false}).next().value
{'1': '2'}
> a.build('a').next().value
{'1': '2'}
> a.build().next().value
{'a': {'1': '2'}}

Used with namespaces

> a.build({namespace: 'a', nest: true}).next().value
{'1': '2'}
> a.build({namespace: 'a', nest: true}).next().value
{'a': {'1': '2'}}

This is useful because it allows us to use namespaces as a filter (see #4).

TODO:

Add test which represent these use cases.

Build namespaces need more options

Overview

Currently builds allow namespaces to be built by referencing the namespace as a string argument:

new JSONifier({namespace: 'a'}).add({'b': 'c'}).build('a')
> {'b': 'c'}

Limits

We need more options to allow output to be customised. Namespaces should be used for 2 cases:

  • differentiate between various parts of a composite JSON object (I want to use namespaces to include or exclude inherited JSON),
  • represent actual key values (I want the namespaces included in the output)

Future

  1. Allow: string and object arguments to build:
.build('a')
.build({namespace:'a'}) 
  1. Allow multiple namespaces to be build:
.build({namespace:['a', 'b', 'c']}) 
  1. Allow namespaces to be merged
let a = new JSONifier({namespace: 'a'})
   .add({'a': '1'})
   .add({'b': '2'});
let b = new JSONifier({namespace: 'b'})
   .add({'b': 'woot'});

b.build('a').next().value
> {'a': '1', 'b': '2'}
b.build({namespace: 'a'}).next().value
> {'a': '1', 'b': '2'}

b.build('b').next().value
> {'b': 'woot'}

b.build().next().value
> {'a': {'a': '1', 'b': '2'}, 'b': {'b': 'woot'}}

b.build({nest: false}).next().value
> {'a': '1', 'b': 'woot'}

add() creates iterators instead of build()

This means that if we call:

let a = new JSONifier().add('a', function* () { yield* [1,2] });
let b = a.build();
b.next(); b.next();
let c = a.build();
c.next(); // incorrectly is 'undefined'

So it needs to convert generators to iterators in JSONify#build instead of JSONify#add

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.