Skip to content

Commit 6bd7ef5

Browse files
author
pooya parsa
authored
feat: pass namespace to custom merger (#25)
1 parent 934d736 commit 6bd7ef5

File tree

3 files changed

+31
-14
lines changed

3 files changed

+31
-14
lines changed

src/defu.ts

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ function isObject (val: any) {
55
}
66

77
// Base function to apply defaults
8-
function _defu<T> (baseObj: T, defaults: any, merger?: Merger): T {
8+
function _defu<T> (baseObj: T, defaults: any, namespace: string = '.', merger?: Merger): T {
99
if (!isObject(defaults)) {
10-
return _defu(baseObj, {}, merger)
10+
return _defu(baseObj, {}, namespace, merger)
1111
}
1212

1313
const obj = Object.assign({}, defaults)
@@ -23,14 +23,14 @@ function _defu<T> (baseObj: T, defaults: any, merger?: Merger): T {
2323
continue
2424
}
2525

26-
if (merger && merger(obj, key, val)) {
26+
if (merger && merger(obj, key, val, namespace)) {
2727
continue
2828
}
2929

3030
if (Array.isArray(val) && Array.isArray(obj[key])) {
3131
obj[key] = obj[key].concat(val)
3232
} else if (isObject(val) && isObject(obj[key])) {
33-
obj[key] = _defu(val, obj[key], merger)
33+
obj[key] = _defu(val, obj[key], (namespace ? `${namespace}.` : '') + key.toString(), merger)
3434
} else {
3535
obj[key] = val
3636
}
@@ -41,22 +41,22 @@ function _defu<T> (baseObj: T, defaults: any, merger?: Merger): T {
4141

4242
// Create defu wrapper with optional merger and multi arg support
4343
function extend (merger?: Merger): DefuFn {
44-
return (...args) => args.reduce((p, c) => _defu(p, c, merger), {} as any)
44+
return (...args) => args.reduce((p, c) => _defu(p, c, '', merger), {} as any)
4545
}
4646

4747
// Basic version
4848
const defu = extend() as Defu
4949

5050
// Custom version with function merge support
51-
defu.fn = extend((obj, key, currentValue) => {
51+
defu.fn = extend((obj, key, currentValue, _namespace) => {
5252
if (typeof obj[key] !== 'undefined' && typeof currentValue === 'function') {
5353
obj[key] = currentValue(obj[key])
5454
return true
5555
}
5656
})
5757

5858
// Custom version with function merge support only for defined arrays
59-
defu.arrayFn = extend((obj, key, currentValue) => {
59+
defu.arrayFn = extend((obj, key, currentValue, _namespace) => {
6060
if (Array.isArray(obj[key]) && typeof currentValue === 'function') {
6161
obj[key] = currentValue(obj[key])
6262
return true

src/types.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
export type Merger = <T extends Input, K extends keyof T>(
22
obj: T,
33
key: keyof T,
4-
value: T[K]
4+
value: T[K],
5+
namespace: string
56
) => any;
67

78
export type DefuFn = <Source extends Input, Defaults extends Input>(

test/defu.test.ts

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,15 +25,15 @@ describe('defu', () => {
2525
it('should copy nested values', () => {
2626
const result = defu({ a: { b: 'c' } }, { a: { d: 'e' } })
2727
expect(result).toEqual({
28-
a: { b: 'c', d: 'e' },
28+
a: { b: 'c', d: 'e' }
2929
})
3030
expectTypeOf(result).toEqualTypeOf<{ a: { b: string, d: string } }>()
3131
})
3232

3333
it('should concat array values by default', () => {
3434
const result = defu({ array: ['b', 'c'] }, { array: ['a'] })
3535
expect(result).toEqual({
36-
array: ['a', 'b', 'c'],
36+
array: ['a', 'b', 'c']
3737
})
3838
expectTypeOf(result).toEqualTypeOf<{ array: string[] }>()
3939
})
@@ -52,7 +52,7 @@ describe('defu', () => {
5252

5353
const result = defu({ a: fn }, { a: re })
5454
expect(result).toEqual({ a: fn })
55-
expectTypeOf(result).toEqualTypeOf<{ a: (() => number) | RegExp }>()
55+
expectTypeOf(result).toEqualTypeOf<{ a:(() => number) | RegExp }>()
5656
})
5757

5858
it('should handle non object first param', () => {
@@ -74,7 +74,7 @@ describe('defu', () => {
7474
expect(result).toEqual({
7575
a: 1,
7676
b: 2,
77-
c: 3,
77+
c: 3
7878
})
7979
expectTypeOf(result).toEqualTypeOf<{ a: string | number, b: string | number, c?: number }>()
8080
})
@@ -94,7 +94,7 @@ describe('defu', () => {
9494
// @ts-expect-error
9595
expect(defu(null, { foo: 1 }, false, 123, { bar: 2 })).toEqual({
9696
foo: 1,
97-
bar: 2,
97+
bar: 2
9898
})
9999
})
100100

@@ -113,7 +113,7 @@ describe('defu', () => {
113113
expect(
114114
defu.fn(
115115
{
116-
ignore: (val) => val.filter((i) => i !== 'dist'),
116+
ignore: val => val.filter(i => i !== 'dist'),
117117
num,
118118
ignored: num
119119
},
@@ -142,4 +142,20 @@ describe('defu', () => {
142142
num
143143
})
144144
})
145+
146+
it('custom merger with namespace', () => {
147+
const ext = defu.extend((obj, key, val, namespace) => {
148+
// console.log({ obj, key, val, namespace })
149+
if (key === 'modules') {
150+
// TODO: It is not possible to override types with extend()
151+
// @ts-ignore
152+
obj[key] = namespace + ':' + [...val, ...obj[key]].sort().join(',')
153+
return true
154+
}
155+
})
156+
157+
const obj1 = { modules: ['A'], foo: { bar: { modules: ['X'] } } }
158+
const obj2 = { modules: ['B'], foo: { bar: { modules: ['Y'] } } }
159+
expect(ext(obj1, obj2)).toEqual({ modules: ':A,B', foo: { bar: { modules: 'foo.bar:X,Y' } } })
160+
})
145161
})

0 commit comments

Comments
 (0)