json-normalizer

0.3.5 • Public • Published

json-normalizer

Normalize a json object to meets a json-schema using extended schema descriptor.

MIT npm version David Dependency Badge

NPM NPM

Note: Json-normalizer is not a json-schema validator. If you are looking for json-schema validators, please check out here: json-schema validators.

Contents

Overview

The Problems

You want:

  • Alias, e.g., both "entry" and "entries" are valid property name, but you don't want to check both of them,
  • Support either single item or an array of items, but you don't want to handle both of them,
  • Flat data objects, i.e., user don't have to nest properties, and
  • Maximum reuse of schemas, i.e., you want multiple inheritance.

The Solution

The normalizer is based on json-schema with the "normalizable" extension:

  1. Properties can have alias and being normalized, using the "alias" keyword.
  2. For schemas of "object" type, a "primary" property can be specified, that when provided value is not an object (a primitive or an array), can be assigned to.
  3. For schemas of "object" type, a "gathering" property can be specified, that when "additionalProperties" is set to false, all unrecognized additional properties can be gathered to. The "gathering" property name defaults to "others".
  4. For schemas of "array" type, if the provided value is not an array, converts that value to an array automatically.
  5. Allow schema extends other schemas, using the "extends" keyword.

Install

$ npm install json-normalizer

API

normalize(schema, data, [options,] callback)

Normalizes a loose JSON data object to a strict json-schema data object.

Context

Don't care.

Parameters

schema

The schema used to normalize the given JSON data object.

data

The JSON data object.

options
options.loader | options.loaders

Optional. A loader or an array of loaders that help loading remote schemas. Loaders are tested in the order listed.

options.ignoreUnknownProperties

Optional. Allow ignore unknown properties.

options.gatheringProperties

Optional. Change default gathering name. Default was "others".

options.before

Optional. A hook function with signature function (schema, value): function that invoked before processing a value using the given schema. The hook function either returns falsy to instruct the normalizer to continue its job; or returns a function that returns the resolved value to stop further processing.

options.after

Optional. A hook function with signature function (schema, resolved): function that invoked after processing a value using the given schema. The resolved parameter is a function that returns the value resolved by the normalizer; or undefined if nothing resolved by the normalizer. The hook function must either returns a function that returns the value resolved by the hook function; or returns the resolved value passed to it.

callback

The callback function with function(err, result) signature that the normalizer delivers the normalized JSON value object to. Called with null context.

Returns

No return value.

Example

var normalize = require('json-normalizer');
var schema = {
    "properties": {
        "entries": {
            "alias": "entry",
            "type": "array"
        }
    }
};
var data = {
    "entry": "index.js"
};
// optional, only needed if your schema references remote schema.
var mapper = ...; // see example bellow
var options = {
    loaders: [mapper]
};
normalize(schema, data, options, function(err, result) {
    if (!err) {
        // process the normalized JSON data object here.
    }
});

normalize.sync(schema, data [, options])

Same as the async version but returns normalized JSON value object directly. Note that if specified, loaders must also be sync version.

Returns

The normalized JSON value object.

Example

var normalize = require('json-normalizer');
var schema = {
    "properties": {
        "entries": {
            "alias": "entry",
            "type": "array"
        }
    }
};
var data = {
    "entry": "index.js"
};
// optional, only needed if your schema references remote schema.
var mapper = ...; // see example bellow
var options = {
    loaders: [mapper]
};
var result = normalize(schema, data, options);
// process the normalized JSON data object here.

Other functions that may be handy:

deref(schema, [options,] callback)

Dereferences JSON references in a schema. Default implementation supports only local references, i.e. references that starts with "#". Custom loaders can be provided via the options object.

Context

Don't care.

Parameters

schema

The schema that contains JSON references.

options

Optional. Currently only accepts a loader or an array of loaders.

options.loader | options.loaders

A loader or an array of loaders that help loading remote schemas. Loaders are tested in the order listed.

callback

The callback function with function(err, detail) signature that the deref function delivers the deferenced schema to. Called with null context.

Returns

No return value.

deref.sync(schema [, options])

Same as the async version but returns dereferenced schema. Throws when error; Note that loaders must also be sync version.

maperFactory([definitions]): function

Creates a mapper schema loader, i.e. a schema loader that holds schema definitions in memory, initialized with the optional definitions hash object.

Context

Don't care.

Parameters

definitions

Optional. If provided, all definitions in the definitions hash object will be available for mapping. See mapper#map(definitions) for more details.

Returns

The mapper schema loader.

mapper(root, $ref, callback)

The async version of mapper.

mapper#sync(root, $ref)

The sync version of mapper.

mapper#map($ref, schema)

Add a schema with the $ref JSON pointer. Subsequent calls with the same JSON pointer will override definition of preceding calls.

Context

Don't care.

Parameters

$ref

The JSON pointer the schema being published.

schema

The schema.

Returns

No return value.

mapper#map(definitions)

Add all $ref : schema pairs defined in the definitions hash object. Subsequent calls with the same JSON pointer will override definition of preceding calls.

Context

Don't care.

Parameters

definitions

The definitions hash object. Keys in the hash object should be valid JSON pointers; Values in the hash object should be the schema of the corresponding JSON pointer.

Returns

No return value.

Example

var mapperFactory = require('json-normalizer/src/loader/mapper');
// map json references to local schema files.
var mapper = mapperFactory({
    'http://json-schema.org/draft-04/schema#': require('schema.json'),
    'http://json-schema.org/geo': require('geo.json'),
    'http://json-schema.org/card': require('card.json'),
    'http://json-schema.org/calendar': require('calendar.json'),
    'http://json-schema.org/address': require('address.json')
});
var schema = {
    ...
    "properties": {
        "userId": { "type": "integer" },
        "userProfile": { "$ref": "http://json-schema.org/card" }
    }
};
 
// Async Version
deref(schema, { loader: mapper }, function(err, schema) {
    if (err) {
        // handle error here.
    }
    else {
        // use the dereferenced schema.
    }
});
 
// Sync Version
try {
    var deferenced = deref.sync(schema, { loader: mapper.sync });
    // use the dereferenced schema.
}
catch (err) {
    // handle error here.
}

Write Your Own Loader

  • Async loaders are functions with function(rootSchema, $ref, callback(err, schema)) signature.
  • Async loaders must return truthy if it can handle the given reference $ref, and the callback be called later when the schema is ready. However, if error occurred, e.g., network failure, the callback be called with the err set to the type of error and the second argument provides details of that error.
  • Async loaders must return falsy if it can not handle the given reference $ref, and the callback should not be called at all.
  • Sync loaders are functions with function(rootSchema, $ref) signature.
  • A local loader is always tested first, and other loaders provided in options.loader or options.loaders argument are then tested by the order listed.

Usage Examples

Alias and Array Type

With the schema:

{
    "properties": {
        "entries": {
            "alias": ["entry"],
            "type": "array"
        }
    }
}

will normalize this data object:

{
    "entry": "index.js"
}

to:

{
    "entries": ["index.js"]
}

Primary Property and Gathering Property

With the schema:

{
    "properties": {
        "src": {
            "type": "string | array"
        },
        "options": {
            "properties": {
                "base": {
                    "type": "string"
                },
                "read": {
                    "type": "boolean"
                },
                "buffer": {
                    "type": "boolean"
                }
            }
        },
        "required": ["src"]
    },
    "primary": "src",
    "additionalProperties": false,
    "gathering": "options"
}

will normalize this data object:

"src/index.js"

to:

{
    "src": "src/index.js"
}

and this data object:

{
    "src": "index.js",
    "base": "src",
    "read": false,
    "unknown": "..."
}

to:

{
    "src": "index.js",
    "options": {
        "base": "src",
        "read": false,
        "unknown": "..."
    }
}

Extending Schema

{
    "definitions": {
        "options": {
            "properties": {
                "debug": {
                    "type": "boolean"
                },
                "sourcemap": {
                    "enum": [false, "inline", "external"]
                }
            }
        }
    },
    "extends": [{
        "$ref": "#/definitions/options"
    }],
    "properties": {
        "bundles": {
            "alias": ["bundle"],
            "type": "array",
            "extends": [{
                "$ref": "#/definitions/options"
            }],
            "properties": {
                "entries": {
                    "alias": ["entry"],
                    "type": "array"
                },
                "options": {
                    "$ref": "#/definitions/options"
                }
            }
        },
        "options": {
            "$ref": "#/definitions/options"
        }
    }
}

Please refer to test for more examples.

Build and Contribute

$ git clone https://github.com/amobiz/json-normalizer.git
$ cd json-normalizer
$ npm install

Issues

Iessues

Test

Tests are written in mocha. Run tests in terminal:

$ npm test

Change Logs

  • 2016/01/24 - 0.3.5

    • Feature: add before and after hook.
  • 2016/01/13 - 0.3.4

    • NPM: Upgrade lodash to 4.0.0.
  • 2016/01/01 - 0.3.3

    • Bug Fix: When "additionalProperties" set to false, should ignore all unknown properties.
    • Feature: Add "patternProperties" support.
  • 2015/12/26 - 0.3.2

    • Bug Fix: Respect schema and options settings (e.g. options.ignoreUnknownProperties): returning what ever normalized rather.
  • 2015/12/24 - 0.3.1

    • NPM: Update npm settings.
  • 2015/12/23 - 0.3.0

    • Breaking Change: Sync version now returns normalized JSON value object directly since it never returns error.
    • Feature: Process items property of schema that are array types.
  • 2015/11/24 - 0.2.2

  • 2015/11/20 - 0.2.1

    • Feature: Process only object type at top level [deprecated in 0.3.0].
    • Feature: Always return an object even nothing resolved.
    • Feature: Add default value if required.
  • 2015/11/12 - 0.2.0

    • Breaking Change: stop validate "required" property, since json-normalizer is not a validator.
    • Feature: options.ignoreUnknownProperties allow ignore unknown properties.
    • Feature: options.gatheringProperties allow set default gathering name other then "others".
  • 2015/10/25 - 0.1.2

    • Bug Fix: Convert value to array if primary property's type is array.
  • 2015/09/15 - 0.1.1

    • Feature: Add sync version.
    • Feature: Remove mapper#add() method, use mapper#map() instead.

Related

License

MIT

Author

Amobiz

Package Sidebar

Install

npm i json-normalizer

Weekly Downloads

4

Version

0.3.5

License

MIT

Last publish

Collaborators

  • amobiz