| /* globals suite test */ | |
| var assert = require('assert') | |
| var flat = require('../index') | |
| var flatten = flat.flatten | |
| var unflatten = flat.unflatten | |
| var primitives = { | |
| String: 'good morning', | |
| Number: 1234.99, | |
| Boolean: true, | |
| Date: new Date(), | |
| null: null, | |
| undefined: undefined | |
| } | |
| suite('Flatten Primitives', function () { | |
| Object.keys(primitives).forEach(function (key) { | |
| var value = primitives[key] | |
| test(key, function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| world: value | |
| } | |
| }), { | |
| 'hello.world': value | |
| }) | |
| }) | |
| }) | |
| }) | |
| suite('Unflatten Primitives', function () { | |
| Object.keys(primitives).forEach(function (key) { | |
| var value = primitives[key] | |
| test(key, function () { | |
| assert.deepEqual(unflatten({ | |
| 'hello.world': value | |
| }), { | |
| hello: { | |
| world: value | |
| } | |
| }) | |
| }) | |
| }) | |
| }) | |
| suite('Flatten', function () { | |
| test('Nested once', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| world: 'good morning' | |
| } | |
| }), { | |
| 'hello.world': 'good morning' | |
| }) | |
| }) | |
| test('Nested twice', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| world: { | |
| again: 'good morning' | |
| } | |
| } | |
| }), { | |
| 'hello.world.again': 'good morning' | |
| }) | |
| }) | |
| test('Multiple Keys', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| lorem: { | |
| ipsum: 'again', | |
| dolor: 'sit' | |
| } | |
| }, | |
| world: { | |
| lorem: { | |
| ipsum: 'again', | |
| dolor: 'sit' | |
| } | |
| } | |
| }), { | |
| 'hello.lorem.ipsum': 'again', | |
| 'hello.lorem.dolor': 'sit', | |
| 'world.lorem.ipsum': 'again', | |
| 'world.lorem.dolor': 'sit' | |
| }) | |
| }) | |
| test('Custom Delimiter', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| world: { | |
| again: 'good morning' | |
| } | |
| } | |
| }, { | |
| delimiter: ':' | |
| }), { | |
| 'hello:world:again': 'good morning' | |
| }) | |
| }) | |
| test('Empty Objects', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| empty: { | |
| nested: { } | |
| } | |
| } | |
| }), { | |
| 'hello.empty.nested': { } | |
| }) | |
| }) | |
| if (typeof Buffer !== 'undefined') { | |
| test('Buffer', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| empty: { | |
| nested: Buffer.from('test') | |
| } | |
| } | |
| }), { | |
| 'hello.empty.nested': Buffer.from('test') | |
| }) | |
| }) | |
| } | |
| if (typeof Uint8Array !== 'undefined') { | |
| test('typed arrays', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| empty: { | |
| nested: new Uint8Array([1, 2, 3, 4]) | |
| } | |
| } | |
| }), { | |
| 'hello.empty.nested': new Uint8Array([1, 2, 3, 4]) | |
| }) | |
| }) | |
| } | |
| test('Custom Depth', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| world: { | |
| again: 'good morning' | |
| } | |
| }, | |
| lorem: { | |
| ipsum: { | |
| dolor: 'good evening' | |
| } | |
| } | |
| }, { | |
| maxDepth: 2 | |
| }), { | |
| 'hello.world': { | |
| again: 'good morning' | |
| }, | |
| 'lorem.ipsum': { | |
| dolor: 'good evening' | |
| } | |
| }) | |
| }) | |
| test('Should keep number in the left when object', function () { | |
| assert.deepEqual(flatten({ | |
| hello: { | |
| '0200': 'world', | |
| '0500': 'darkness my old friend' | |
| } | |
| }), { | |
| 'hello.0200': 'world', | |
| 'hello.0500': 'darkness my old friend' | |
| }) | |
| }) | |
| }) | |
| suite('Unflatten', function () { | |
| test('Nested once', function () { | |
| assert.deepEqual({ | |
| hello: { | |
| world: 'good morning' | |
| } | |
| }, unflatten({ | |
| 'hello.world': 'good morning' | |
| })) | |
| }) | |
| test('Nested twice', function () { | |
| assert.deepEqual({ | |
| hello: { | |
| world: { | |
| again: 'good morning' | |
| } | |
| } | |
| }, unflatten({ | |
| 'hello.world.again': 'good morning' | |
| })) | |
| }) | |
| test('Multiple Keys', function () { | |
| assert.deepEqual({ | |
| hello: { | |
| lorem: { | |
| ipsum: 'again', | |
| dolor: 'sit' | |
| } | |
| }, | |
| world: { | |
| greet: 'hello', | |
| lorem: { | |
| ipsum: 'again', | |
| dolor: 'sit' | |
| } | |
| } | |
| }, unflatten({ | |
| 'hello.lorem.ipsum': 'again', | |
| 'hello.lorem.dolor': 'sit', | |
| 'world.lorem.ipsum': 'again', | |
| 'world.lorem.dolor': 'sit', | |
| 'world': {greet: 'hello'} | |
| })) | |
| }) | |
| test('nested objects do not clobber each other when a.b inserted before a', function () { | |
| var x = {} | |
| x['foo.bar'] = {t: 123} | |
| x['foo'] = {p: 333} | |
| assert.deepEqual(unflatten(x), { | |
| foo: { | |
| bar: { | |
| t: 123 | |
| }, | |
| p: 333 | |
| } | |
| }) | |
| }) | |
| test('Custom Delimiter', function () { | |
| assert.deepEqual({ | |
| hello: { | |
| world: { | |
| again: 'good morning' | |
| } | |
| } | |
| }, unflatten({ | |
| 'hello world again': 'good morning' | |
| }, { | |
| delimiter: ' ' | |
| })) | |
| }) | |
| test('Overwrite', function () { | |
| assert.deepEqual({ | |
| travis: { | |
| build: { | |
| dir: '/home/travis/build/kvz/environmental' | |
| } | |
| } | |
| }, unflatten({ | |
| travis: 'true', | |
| travis_build_dir: '/home/travis/build/kvz/environmental' | |
| }, { | |
| delimiter: '_', | |
| overwrite: true | |
| })) | |
| }) | |
| test('Messy', function () { | |
| assert.deepEqual({ | |
| hello: { world: 'again' }, | |
| lorem: { ipsum: 'another' }, | |
| good: { | |
| morning: { | |
| hash: { | |
| key: { nested: { | |
| deep: { and: { even: { | |
| deeper: { still: 'hello' } | |
| } } } | |
| } } | |
| }, | |
| again: { testing: { 'this': 'out' } } | |
| } | |
| } | |
| }, unflatten({ | |
| 'hello.world': 'again', | |
| 'lorem.ipsum': 'another', | |
| 'good.morning': { | |
| 'hash.key': { | |
| 'nested.deep': { | |
| 'and.even.deeper.still': 'hello' | |
| } | |
| } | |
| }, | |
| 'good.morning.again': { | |
| 'testing.this': 'out' | |
| } | |
| })) | |
| }) | |
| suite('Overwrite + non-object values in key positions', function () { | |
| test('non-object keys + overwrite should be overwritten', function () { | |
| assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } }) | |
| assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } }) | |
| assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } }) | |
| assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } }) | |
| }) | |
| test('overwrite value should not affect undefined keys', function () { | |
| assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: true}), { a: { b: 'c' } }) | |
| assert.deepEqual(flat.unflatten({ a: undefined, 'a.b': 'c' }, {overwrite: false}), { a: { b: 'c' } }) | |
| }) | |
| test('if no overwrite, should ignore nested values under non-object key', function () { | |
| assert.deepEqual(flat.unflatten({ a: null, 'a.b': 'c' }), { a: null }) | |
| assert.deepEqual(flat.unflatten({ a: 0, 'a.b': 'c' }), { a: 0 }) | |
| assert.deepEqual(flat.unflatten({ a: 1, 'a.b': 'c' }), { a: 1 }) | |
| assert.deepEqual(flat.unflatten({ a: '', 'a.b': 'c' }), { a: '' }) | |
| }) | |
| }) | |
| suite('.safe', function () { | |
| test('Should protect arrays when true', function () { | |
| assert.deepEqual(flatten({ | |
| hello: [ | |
| { world: { again: 'foo' } }, | |
| { lorem: 'ipsum' } | |
| ], | |
| another: { | |
| nested: [{ array: { too: 'deep' } }] | |
| }, | |
| lorem: { | |
| ipsum: 'whoop' | |
| } | |
| }, { | |
| safe: true | |
| }), { | |
| hello: [ | |
| { world: { again: 'foo' } }, | |
| { lorem: 'ipsum' } | |
| ], | |
| 'lorem.ipsum': 'whoop', | |
| 'another.nested': [{ array: { too: 'deep' } }] | |
| }) | |
| }) | |
| test('Should not protect arrays when false', function () { | |
| assert.deepEqual(flatten({ | |
| hello: [ | |
| { world: { again: 'foo' } }, | |
| { lorem: 'ipsum' } | |
| ] | |
| }, { | |
| safe: false | |
| }), { | |
| 'hello.0.world.again': 'foo', | |
| 'hello.1.lorem': 'ipsum' | |
| }) | |
| }) | |
| }) | |
| suite('.object', function () { | |
| test('Should create object instead of array when true', function () { | |
| var unflattened = unflatten({ | |
| 'hello.you.0': 'ipsum', | |
| 'hello.you.1': 'lorem', | |
| 'hello.other.world': 'foo' | |
| }, { | |
| object: true | |
| }) | |
| assert.deepEqual({ | |
| hello: { | |
| you: { | |
| 0: 'ipsum', | |
| 1: 'lorem' | |
| }, | |
| other: { world: 'foo' } | |
| } | |
| }, unflattened) | |
| assert(!Array.isArray(unflattened.hello.you)) | |
| }) | |
| test('Should create object instead of array when nested', function () { | |
| var unflattened = unflatten({ | |
| 'hello': { | |
| 'you.0': 'ipsum', | |
| 'you.1': 'lorem', | |
| 'other.world': 'foo' | |
| } | |
| }, { | |
| object: true | |
| }) | |
| assert.deepEqual({ | |
| hello: { | |
| you: { | |
| 0: 'ipsum', | |
| 1: 'lorem' | |
| }, | |
| other: { world: 'foo' } | |
| } | |
| }, unflattened) | |
| assert(!Array.isArray(unflattened.hello.you)) | |
| }) | |
| test('Should keep the zero in the left when object is true', function () { | |
| var unflattened = unflatten({ | |
| 'hello.0200': 'world', | |
| 'hello.0500': 'darkness my old friend' | |
| }, { | |
| object: true | |
| }) | |
| assert.deepEqual({ | |
| hello: { | |
| '0200': 'world', | |
| '0500': 'darkness my old friend' | |
| } | |
| }, unflattened) | |
| }) | |
| test('Should not create object when false', function () { | |
| var unflattened = unflatten({ | |
| 'hello.you.0': 'ipsum', | |
| 'hello.you.1': 'lorem', | |
| 'hello.other.world': 'foo' | |
| }, { | |
| object: false | |
| }) | |
| assert.deepEqual({ | |
| hello: { | |
| you: ['ipsum', 'lorem'], | |
| other: { world: 'foo' } | |
| } | |
| }, unflattened) | |
| assert(Array.isArray(unflattened.hello.you)) | |
| }) | |
| }) | |
| if (typeof Buffer !== 'undefined') { | |
| test('Buffer', function () { | |
| assert.deepEqual(unflatten({ | |
| 'hello.empty.nested': Buffer.from('test') | |
| }), { | |
| hello: { | |
| empty: { | |
| nested: Buffer.from('test') | |
| } | |
| } | |
| }) | |
| }) | |
| } | |
| if (typeof Uint8Array !== 'undefined') { | |
| test('typed arrays', function () { | |
| assert.deepEqual(unflatten({ | |
| 'hello.empty.nested': new Uint8Array([1, 2, 3, 4]) | |
| }), { | |
| hello: { | |
| empty: { | |
| nested: new Uint8Array([1, 2, 3, 4]) | |
| } | |
| } | |
| }) | |
| }) | |
| } | |
| }) | |
| suite('Arrays', function () { | |
| test('Should be able to flatten arrays properly', function () { | |
| assert.deepEqual({ | |
| 'a.0': 'foo', | |
| 'a.1': 'bar' | |
| }, flatten({ | |
| a: ['foo', 'bar'] | |
| })) | |
| }) | |
| test('Should be able to revert and reverse array serialization via unflatten', function () { | |
| assert.deepEqual({ | |
| a: ['foo', 'bar'] | |
| }, unflatten({ | |
| 'a.0': 'foo', | |
| 'a.1': 'bar' | |
| })) | |
| }) | |
| test('Array typed objects should be restored by unflatten', function () { | |
| assert.equal( | |
| Object.prototype.toString.call(['foo', 'bar']) | |
| , Object.prototype.toString.call(unflatten({ | |
| 'a.0': 'foo', | |
| 'a.1': 'bar' | |
| }).a) | |
| ) | |
| }) | |
| test('Do not include keys with numbers inside them', function () { | |
| assert.deepEqual(unflatten({ | |
| '1key.2_key': 'ok' | |
| }), { | |
| '1key': { | |
| '2_key': 'ok' | |
| } | |
| }) | |
| }) | |
| }) |