Skip to content

Commit 8fbb33c

Browse files
committed
refactor
1 parent 2b4a0c4 commit 8fbb33c

File tree

4 files changed

+90
-170
lines changed

4 files changed

+90
-170
lines changed

.verb.md

+14-27
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,16 @@
1-
# {%= name %} {%= badge("fury") %} {%= badge("travis") %}
2-
3-
> {%= description %}
4-
5-
{%= include("install-npm", {save: true}) %}
6-
71
## Usage
82

9-
{%= docs('usage') %}
10-
11-
## API
12-
{%= apidocs("index.js") %}
13-
14-
## Running tests
15-
{%= include("tests") %}
16-
17-
## Contributing
18-
{%= include("contributing") %}
19-
20-
## Author
21-
{%= include("author") %}
22-
23-
## License
24-
{%= copyright() %}
25-
{%= license() %}
26-
27-
***
28-
29-
{%= include("footer") %}
3+
```js
4+
const expand = require('expand-hash');
5+
const obj = {
6+
'foo.bar.bar': 'some value',
7+
'foo.qux': 'another value',
8+
fez: true
9+
};
10+
11+
console.log(expand(obj));
12+
// {
13+
// foo: { bar: { bar: 'some value' }, qux: 'another value' },
14+
// fez: true
15+
// }
16+
```

example.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const expand = require('./');
2+
const obj = {
3+
'foo.bar.bar': 'some value',
4+
'foo.qux': 'another value',
5+
fez: true
6+
};
7+
console.log(expand(obj));

index.js

+29-56
Original file line numberDiff line numberDiff line change
@@ -1,64 +1,37 @@
1-
var extend = require('extend-shallow');
2-
var toString = Object.prototype.toString;
1+
'use strict';
32

4-
function type(val) {
5-
return toString.call(val).toLowerCase().replace(/\[object ([\S]+)\]/, '$1');
6-
}
7-
8-
function namespace(obj, str, value) {
9-
var original = str, name;
10-
11-
if (!/\./.test(str)) {
12-
obj[str] = value;
13-
return obj;
3+
module.exports = function expand(value) {
4+
if (!isObject(value)) return value;
5+
const res = Array.isArray(value) ? [] : {};
6+
for (const key of Object.keys(value)) {
7+
set(res, key, expand(value[key]));
148
}
9+
return res;
10+
};
1511

16-
var paths = str.split('.');
17-
while (paths.length > 0) {
18-
var key = paths.shift();
19-
name = namespace((obj[key] = obj[key] || {}), paths.join('.'), value);
20-
if (str === original) { break; }
12+
function set(obj, prop, val) {
13+
const segs = split(prop);
14+
const last = segs.pop();
15+
while (segs.length) {
16+
const key = segs.shift();
17+
obj = obj[key] || (obj[key] = {});
2118
}
22-
return name;
19+
obj[last] = val;
2320
}
2421

25-
var expand = function (obj) {
26-
var result = {};
27-
28-
Object.keys(obj).forEach(function(key) {
29-
if (!/\./.test(key)) {
30-
result[key] = obj[key];
31-
} else {
32-
var paths = key.split('.');
33-
paths = ['__remove__'].concat(paths);
34-
result[paths[0]] = namespace(result, key, obj[key]);
22+
function split(str) {
23+
const segs = str.split('.');
24+
const keys = [];
25+
for (let i = 0; i < segs.length; i++) {
26+
const seg = segs[i];
27+
while (seg.slice(-1) === '\\') {
28+
seg = seg.slice(0, -1) + '.' + (segs[++i] || '');
3529
}
36-
});
37-
38-
delete result.__remove__;
39-
return result;
40-
};
41-
42-
43-
/**
44-
* Recursively expand the keys on each object
45-
*
46-
* @name expand-hash
47-
* @param {Object} `value` Object to expand
48-
* @return {Object} Expanded object
49-
* @api public
50-
*/
51-
52-
var recurse = module.exports = function(value) {
53-
var orig = value, data = {};
30+
keys.push(seg);
31+
}
32+
return keys;
33+
}
5434

55-
Object.keys(value).forEach(function(key) {
56-
extend(data, expand(value));
57-
if (type(value[key]) === 'object') {
58-
value[key] = extend(expand(value[key]), recurse(value[key]));
59-
} else {
60-
return value;
61-
}
62-
});
63-
return data;
64-
};
35+
function isObject(val) {
36+
return val !== null && typeof val === 'object';
37+
}

test/test.js

+40-87
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,55 @@
1-
var expect = require('chai').expect,
2-
expandHash = require('..');
1+
'use strict';
32

4-
describe('expand-hash', function() {
3+
require('mocha');
4+
const assert = require('assert');
5+
const expandHash = require('..');
56

6-
/***
7-
var expandHash = require('expand-hash');
8-
var hash = {
9-
'foo': 'bar',
10-
'baz': 'bang'
11-
};
12-
13-
var expanded = expandHash(hash);
14-
console.log('expanded: ', expanded);
15-
***/
16-
17-
it('expand simple hash', function(done) {
18-
var simple = { 'foo': 'bar', 'baz': 'bang' };
19-
var expected = { foo: 'bar', baz: 'bang' };
20-
var actual = expandHash(simple);
21-
expect(actual).to.eql(expected);
22-
done();
7+
describe('expand-hash', () => {
8+
it('expand simple hash', () => {
9+
assert.deepEqual(expandHash({ foo: 'bar', baz: 'bang' }), { foo: 'bar', baz: 'bang' });
2310
});
2411

25-
/***
26-
var expandHash = require('expand-hash');
27-
var hash = {
28-
'foo.bar': 'bar',
29-
'foo.baz': 'baz',
30-
'something': 'else'
31-
};
32-
var expanded = expandHash(hash);
33-
console.log('expanded: ', expanded);
34-
**/
35-
36-
it('expand complex hash', function (done) {
37-
var complex = { 'foo.bar': 'bar', 'foo.baz': 'baz', 'beep.boop': 'bop', 'something': 'else' };
38-
var expected = { foo: { bar: 'bar', baz: 'baz' }, beep: { boop: 'bop' }, something: 'else' };
39-
var actual = expandHash(complex);
40-
expect(actual).to.eql(expected);
41-
done();
12+
it('expand multiple props with the same keys', () => {
13+
assert.deepEqual(expandHash({ 'foo.bar': 'bar', 'foo.baz': 'baz', 'beep.boop': 'bop', something: 'else' }), {
14+
foo: { bar: 'bar', baz: 'baz' },
15+
beep: { boop: 'bop' },
16+
something: 'else'
17+
});
4218
});
4319

44-
it('expand complex hash', function (done) {
45-
var complex = {'one.two.three.four.five': 'bar', bang: 'fez'};
46-
var expected = {one: {two: {three: {four: {five: 'bar'} } } }, bang: 'fez' };
47-
var actual = expandHash(complex);
48-
expect(actual).to.eql(expected);
49-
done();
20+
it('expand to deeply nested object', () => {
21+
const complex = { 'one.two.three.four.five': 'bar', bang: 'fez' };
22+
const expected = { one: { two: { three: { four: { five: 'bar' } } } }, bang: 'fez' };
23+
const actual = expandHash(complex);
24+
assert.deepEqual(actual, expected);
5025
});
51-
});
5226

53-
describe('when keys are nested', function() {
54-
it('should expand the prop strings into objects', function (done) {
55-
var complex = { one: { 'two.three.four.five': 'bar'}, bang: 'fez'};
56-
var expected = {one: {two: {three: {four: {five: 'bar'} } } }, bang: 'fez' };
57-
var actual = expandHash(complex);
58-
expect(actual).to.eql(expected);
59-
done();
60-
});
61-
});
27+
it('should expand nested keys into objects', () => {
28+
assert.deepEqual(expandHash({ one: { 'two.three.four.five': 'bar' }, bang: 'fez' }), {
29+
one: { two: { three: { four: { five: 'bar' } } } },
30+
bang: 'fez'
31+
});
6232

63-
describe('when keys are nested', function() {
64-
it('should expand the prop strings into objects', function (done) {
65-
var complex = { a: ['b', 'c'], one: { 'two.three.four.five': 'bar'}, bang: 'fez'};
66-
var expected = { a: ['b', 'c'], one: {two: {three: {four: {five: 'bar'} } } }, bang: 'fez' };
67-
var actual = expandHash(complex);
68-
expect(actual).to.eql(expected);
69-
done();
33+
assert.deepEqual(expandHash({ a: ['b', 'c'], one: { 'two.three.four.five': 'bar' }, bang: 'fez' }), {
34+
a: ['b', 'c'],
35+
one: { two: { three: { four: { five: 'bar' } } } },
36+
bang: 'fez'
37+
});
7038
});
71-
});
7239

73-
describe('when keys are nested', function() {
74-
it('should expand the prop strings into objects', function (done) {
75-
var complex = { a: ['b', 'c'], one: {two: {three: { 'four.five': 'bar'} } }, bang: 'fez' };
76-
var expected = { a: ['b', 'c'], one: {two: {three: {four: {five: 'bar'} } } }, bang: 'fez' };
77-
var actual = expandHash(complex);
78-
expect(actual).to.eql(expected);
79-
done();
40+
it('should expand keys on object values into objects', () => {
41+
assert.deepEqual(expandHash({ a: ['b', 'c'], one: { two: { three: { 'four.five': 'bar' } } }, bang: 'fez' }), {
42+
a: ['b', 'c'],
43+
one: { two: { three: { four: { five: 'bar' } } } },
44+
bang: 'fez'
45+
});
8046
});
81-
});
82-
8347

84-
describe('when keys are nested', function () {
85-
it('should expand the prop strings into objects', function (done) {
86-
var complex = {a: ['b', 'c'], one: {two: {three: {four: {five: {six: {seven: {'a.b.c.d.e.f.g': 'Dante\'s ninth circle'} } } } } } }, bang: 'fez'};
87-
var expected = {a: ['b', 'c'], one: {two: {three: {four: {five: {six: {seven: {a: {b: {c: {d: {e: {f: {g: 'Dante\'s ninth circle'} } } } } } } } } } } } }, bang: 'fez'};
88-
var actual = expandHash(complex);
89-
expect(actual).to.eql(expected);
90-
done();
48+
it('should expand keys in arrays into objects', () => {
49+
assert.deepEqual(expandHash({ a: [{'a.b': 'c'}, 'c'], one: { two: { three: { 'four.five': 'bar' } } }, bang: 'fez' }), {
50+
a: [ { a: { b: 'c' } }, 'c' ],
51+
one: { two: { three: { four: { five: 'bar' } } } },
52+
bang: 'fez'
53+
});
9154
});
9255
});
93-
94-
describe('when the value is an object', function() {
95-
it('should expand the prop strings into objects', function (done) {
96-
var complex = {'foo.bar': {'aaa': 'bbbb', 'ccc': 'dddd', 'eee': 'ffff'} };
97-
var expected = {foo: {bar: {'aaa': 'bbbb', 'ccc': 'dddd', 'eee': 'ffff'} } };
98-
var actual = expandHash(complex);
99-
expect(actual).to.eql(expected);
100-
done();
101-
});
102-
});

0 commit comments

Comments
 (0)