Comparing version 1.1.0 to 1.2.0
128
index.js
@@ -1,73 +0,87 @@ | ||
var flat = module.exports = {} | ||
var flat = module.exports = { | ||
flatten: flatten | ||
, unflatten: unflatten | ||
} | ||
var flatten = flat.flatten = function (target, opts) { | ||
var output = {} | ||
, opts = opts || {} | ||
, delimiter = opts.delimiter || '.' | ||
function flatten(target, opts) { | ||
opts = opts || {} | ||
function getkey(key, prev) { | ||
return prev ? prev + delimiter + key : key | ||
}; | ||
var delimiter = opts.delimiter || '.' | ||
var output = {} | ||
function step(object, prev) { | ||
Object.keys(object).forEach(function(key) { | ||
var isarray = opts.safe && Array.isArray(object[key]) | ||
, type = Object.prototype.toString.call(object[key]) | ||
, isobject = (type === "[object Object]" || type === "[object Array]") | ||
function step(object, prev) { | ||
Object.keys(object).forEach(function(key) { | ||
var value = object[key] | ||
var isarray = opts.safe && Array.isArray(value) | ||
var type = Object.prototype.toString.call(value) | ||
var isobject = ( | ||
type === "[object Object]" || | ||
type === "[object Array]" | ||
) | ||
if (!isarray && isobject) { | ||
return step(object[key] | ||
, getkey(key, prev) | ||
) | ||
} | ||
var newKey = prev | ||
? prev + delimiter + key | ||
: key | ||
output[getkey(key, prev)] = object[key] | ||
}); | ||
}; | ||
if (!isarray && isobject) { | ||
return step(value, newKey) | ||
} | ||
step(target) | ||
output[newKey] = value | ||
}) | ||
} | ||
return output | ||
}; | ||
step(target) | ||
var unflatten = flat.unflatten = function (target, opts) { | ||
var opts = opts || {} | ||
, delimiter = opts.delimiter || '.' | ||
, result = {} | ||
return output | ||
} | ||
if (Object.prototype.toString.call(target) !== '[object Object]') { | ||
return target | ||
} | ||
function unflatten(target, opts) { | ||
opts = opts || {} | ||
function getkey(key) { | ||
var parsedKey = parseInt(key) | ||
return (isNaN(parsedKey) ? key : parsedKey) | ||
}; | ||
var delimiter = opts.delimiter || '.' | ||
var result = {} | ||
Object.keys(target).forEach(function(key) { | ||
var split = key.split(delimiter) | ||
, firstNibble | ||
, secondNibble | ||
, recipient = result | ||
if (Object.prototype.toString.call(target) !== '[object Object]') { | ||
return target | ||
} | ||
firstNibble = getkey(split.shift()) | ||
secondNibble = getkey(split[0]) | ||
// safely ensure that the key is | ||
// an integer. | ||
function getkey(key) { | ||
var parsedKey = Number(key) | ||
while (secondNibble !== undefined) { | ||
if (recipient[firstNibble] === undefined) { | ||
recipient[firstNibble] = ((typeof secondNibble === 'number') && !opts.object ? [] : {}) | ||
} | ||
return ( | ||
isNaN(parsedKey) || | ||
key.indexOf('.') !== -1 | ||
) ? key | ||
: parsedKey | ||
} | ||
recipient = recipient[firstNibble] | ||
if (split.length > 0) { | ||
firstNibble = getkey(split.shift()) | ||
secondNibble = getkey(split[0]) | ||
} | ||
} | ||
Object.keys(target).forEach(function(key) { | ||
var split = key.split(delimiter) | ||
var key1 = getkey(split.shift()) | ||
var key2 = getkey(split[0]) | ||
var recipient = result | ||
// unflatten again for 'messy objects' | ||
recipient[firstNibble] = unflatten(target[key]) | ||
}); | ||
while (key2 !== undefined) { | ||
if (recipient[key1] === undefined) { | ||
recipient[key1] = ( | ||
typeof key2 === 'number' && | ||
!opts.object ? [] : {} | ||
) | ||
} | ||
return result | ||
}; | ||
recipient = recipient[key1] | ||
if (split.length > 0) { | ||
key1 = getkey(split.shift()) | ||
key2 = getkey(split[0]) | ||
} | ||
} | ||
// unflatten again for 'messy objects' | ||
recipient[key1] = unflatten(target[key]) | ||
}) | ||
return result | ||
} |
{ | ||
"name": "flat", | ||
"version": "1.1.0", | ||
"version": "1.2.0", | ||
"main": "index.js", | ||
@@ -5,0 +5,0 @@ "scripts": { |
543
test/test.js
@@ -6,283 +6,310 @@ var assert = require('assert') | ||
suite('Flatten Primitives', function(){ | ||
test('String', function(){ | ||
assert.deepEqual(flatten({hello:{world: "good morning"}}),{'hello.world':'good morning'}) | ||
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 | ||
}) | ||
}) | ||
test('Number', function(){ | ||
assert.deepEqual(flatten({hello:{world: 1234.99}}),{'hello.world': 1234.99}) | ||
}) | ||
test('Boolean', function(){ | ||
assert.deepEqual(flatten({hello:{world: true}}),{'hello.world': true}) | ||
assert.deepEqual(flatten({hello:{world: false}}),{'hello.world': false}) | ||
}) | ||
test('Date', function(){ | ||
var d = new Date() | ||
assert.deepEqual(flatten({hello:{world: d}}),{'hello.world': d}) | ||
}) | ||
test('Null', function(){ | ||
assert.deepEqual(flatten({hello:{world: null}}),{'hello.world': null}) | ||
}) | ||
test('Undefined', function(){ | ||
assert.deepEqual(flatten({hello:{world: undefined}}),{'hello.world': undefined}) | ||
}) | ||
}) | ||
}) | ||
suite('Unflatten Primitives', function(){ | ||
test('String', function(){ | ||
assert.deepEqual(unflatten({'hello.world':'good morning'}),{hello:{world: "good morning"}}) | ||
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 | ||
} | ||
}) | ||
}) | ||
test('Number', function(){ | ||
assert.deepEqual(unflatten({'hello.world': 1234.99}),{hello:{world: 1234.99}}) | ||
}) | ||
test('Boolean', function(){ | ||
assert.deepEqual(unflatten({'hello.world': true}),{hello:{world: true}}) | ||
assert.deepEqual(unflatten({'hello.world': false}),{hello:{world: false}}) | ||
}) | ||
test('Date', function(){ | ||
var d = new Date() | ||
assert.deepEqual(unflatten({'hello.world': d}),{hello:{world: d}}) | ||
}) | ||
test('Null', function(){ | ||
assert.deepEqual(unflatten({'hello.world': null}),{hello:{world: null}}) | ||
}) | ||
test('Undefined', function(){ | ||
assert.deepEqual(unflatten({'hello.world': undefined}),{hello:{world: undefined}}) | ||
}) | ||
}) | ||
}) | ||
suite('Flatten', function() { | ||
test('Nested once', function() { | ||
assert.deepEqual(flatten({ | ||
hello: { | ||
world: 'good morning' | ||
} | ||
}), { | ||
'hello.world': 'good morning' | ||
}) | ||
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('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('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('Custom Delimiter', function() { | ||
assert.deepEqual(flatten({ | ||
hello: { | ||
world: { | ||
again: 'good morning' | ||
} | ||
} | ||
}, { | ||
delimiter: ':' | ||
}), { | ||
'hello:world:again': 'good morning' | ||
}) | ||
}) | ||
}) | ||
suite('Unflatten', function() { | ||
test('Nested once', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
world: 'good morning' | ||
} | ||
}, unflatten({ | ||
'hello.world': 'good morning' | ||
})) | ||
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: { | ||
lorem: { | ||
ipsum: 'again', | ||
dolor: 'sit' | ||
} | ||
} | ||
}, unflatten({ | ||
'hello.lorem.ipsum': 'again', | ||
'hello.lorem.dolor': 'sit', | ||
'world.lorem.ipsum': 'again', | ||
'world.lorem.dolor': 'sit' | ||
})) | ||
}) | ||
test('Custom Delimiter', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
world: { | ||
again: 'good morning' | ||
} | ||
} | ||
}, unflatten({ | ||
'hello world again': 'good morning' | ||
}, { | ||
delimiter: ' ' | ||
})) | ||
}) | ||
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('.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('Nested twice', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
world: { | ||
again: 'good morning' | ||
} | ||
} | ||
}, unflatten({ | ||
'hello.world.again': 'good morning' | ||
})) | ||
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' | ||
}) | ||
}) | ||
test('Multiple Keys', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
lorem: { | ||
ipsum: 'again', | ||
dolor: 'sit' | ||
} | ||
}, | ||
world: { | ||
lorem: { | ||
ipsum: 'again', | ||
dolor: 'sit' | ||
} | ||
} | ||
}, unflatten({ | ||
'hello.lorem.ipsum': 'again', | ||
'hello.lorem.dolor': 'sit', | ||
'world.lorem.ipsum': 'again', | ||
'world.lorem.dolor': 'sit' | ||
})) | ||
}) | ||
test('Custom Delimiter', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
world: { | ||
again: 'good morning' | ||
} | ||
} | ||
}, unflatten({ | ||
'hello world again': 'good morning' | ||
}, { | ||
delimiter: ' ' | ||
})) | ||
}) | ||
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('.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() { | ||
assert.deepEqual({ | ||
hello: { | ||
you: { | ||
0: 'ipsum', | ||
1: 'lorem', | ||
}, | ||
other: { world: 'foo' } | ||
} | ||
}, unflatten( | ||
{ | ||
'hello.you.0': 'ipsum', | ||
'hello.you.1': 'lorem', | ||
'hello.other.world': 'foo' | ||
}, { | ||
object: true | ||
})) | ||
}) | ||
suite('.object', function() { | ||
test('Should create object instead of array when true', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
you: { | ||
0: 'ipsum', | ||
1: 'lorem', | ||
}, | ||
other: { world: 'foo' } | ||
} | ||
}, unflatten( | ||
{ | ||
'hello.you.0': 'ipsum', | ||
'hello.you.1': 'lorem', | ||
'hello.other.world': 'foo' | ||
}, { | ||
object: true | ||
})); | ||
}) | ||
test('Should not create object when false', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
you: ['ipsum', 'lorem'], | ||
other: { world: 'foo' } | ||
} | ||
}, unflatten( | ||
{ | ||
'hello.you.0': 'ipsum', | ||
'hello.you.1': 'lorem', | ||
'hello.other.world': 'foo' | ||
}, { | ||
object: false | ||
})); | ||
}) | ||
test('Should not create object when false', function() { | ||
assert.deepEqual({ | ||
hello: { | ||
you: ['ipsum', 'lorem'], | ||
other: { world: 'foo' } | ||
} | ||
}, unflatten( | ||
{ | ||
'hello.you.0': 'ipsum', | ||
'hello.you.1': 'lorem', | ||
'hello.other.world': 'foo' | ||
}, { | ||
object: false | ||
})) | ||
}) | ||
}); | ||
}) | ||
}) | ||
suite('Arrays', function() { | ||
var object, flatObject; | ||
object = { "a": ["foo", "bar"] }; | ||
flatObject = { "a.0": "foo", "a.1": "bar"}; | ||
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 flatten arrays properly', function() { | ||
assert.deepEqual(flatObject, flatten(object)); | ||
}); | ||
test('Should be able to revert and reverse array serialization via unflatten', function() { | ||
assert.deepEqual(object, unflatten(flatObject)); | ||
}); | ||
test('Array typed objects should be restored by unflatten', function () { | ||
assert.equal(Object.prototype.toString.call(object.a), Object.prototype.toString.call(unflatten(flatObject).a)); | ||
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' | ||
} | ||
}) | ||
}); | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
361
10996