19 changed files with 361 additions and 353 deletions
@ -0,0 +1,132 @@ |
|||||
|
import { describe, expect, it } from 'vitest'; |
||||
|
|
||||
|
import { flattenObject } from './flatten-object'; |
||||
|
|
||||
|
describe('flattenObject', () => { |
||||
|
it('should flatten a nested object correctly', () => { |
||||
|
const nestedObject = { |
||||
|
language: 'en', |
||||
|
notifications: { |
||||
|
email: true, |
||||
|
push: { |
||||
|
sound: true, |
||||
|
vibration: false, |
||||
|
}, |
||||
|
}, |
||||
|
theme: 'light', |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
language: 'en', |
||||
|
notificationsEmail: true, |
||||
|
notificationsPushSound: true, |
||||
|
notificationsPushVibration: false, |
||||
|
theme: 'light', |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle empty objects', () => { |
||||
|
const nestedObject = {}; |
||||
|
const expected = {}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle objects with primitive values', () => { |
||||
|
const nestedObject = { |
||||
|
active: true, |
||||
|
age: 30, |
||||
|
name: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
active: true, |
||||
|
age: 30, |
||||
|
name: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle objects with null values', () => { |
||||
|
const nestedObject = { |
||||
|
user: { |
||||
|
age: null, |
||||
|
name: null, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
userAge: null, |
||||
|
userName: null, |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle nested empty objects', () => { |
||||
|
const nestedObject = { |
||||
|
a: {}, |
||||
|
b: { c: {} }, |
||||
|
}; |
||||
|
|
||||
|
const expected = {}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle arrays within objects', () => { |
||||
|
const nestedObject = { |
||||
|
hobbies: ['reading', 'gaming'], |
||||
|
name: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
hobbies: ['reading', 'gaming'], |
||||
|
name: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
it('should flatten objects with nested arrays correctly', () => { |
||||
|
const nestedObject = { |
||||
|
person: { |
||||
|
hobbies: ['reading', 'gaming'], |
||||
|
name: 'Alice', |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
personHobbies: ['reading', 'gaming'], |
||||
|
personName: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
|
||||
|
it('should handle objects with undefined values', () => { |
||||
|
const nestedObject = { |
||||
|
user: { |
||||
|
age: undefined, |
||||
|
name: 'Alice', |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
const expected = { |
||||
|
userAge: undefined, |
||||
|
userName: 'Alice', |
||||
|
}; |
||||
|
|
||||
|
const result = flattenObject(nestedObject); |
||||
|
expect(result).toEqual(expected); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,2 @@ |
|||||
|
export * from './flatten-object'; |
||||
|
export * from './nested-object'; |
||||
@ -0,0 +1,97 @@ |
|||||
|
import { describe, expect, it } from 'vitest'; |
||||
|
|
||||
|
import { nestedObject } from './nested-object'; |
||||
|
|
||||
|
describe('nestedObject', () => { |
||||
|
it('should convert flat object to nested object with level 1', () => { |
||||
|
const flatObject = { |
||||
|
anotherKeyExample: 2, |
||||
|
commonAppName: 1, |
||||
|
someOtherKey: 3, |
||||
|
}; |
||||
|
|
||||
|
const expectedNestedObject = { |
||||
|
anotherKeyExample: 2, |
||||
|
commonAppName: 1, |
||||
|
someOtherKey: 3, |
||||
|
}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
|
||||
|
it('should convert flat object to nested object with level 2', () => { |
||||
|
const flatObject = { |
||||
|
appAnotherKeyExample: 2, |
||||
|
appCommonName: 1, |
||||
|
appSomeOtherKey: 3, |
||||
|
}; |
||||
|
|
||||
|
const expectedNestedObject = { |
||||
|
app: { |
||||
|
anotherKeyExample: 2, |
||||
|
commonName: 1, |
||||
|
someOtherKey: 3, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 2)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
|
||||
|
it('should convert flat object to nested object with level 3', () => { |
||||
|
const flatObject = { |
||||
|
appAnotherKeyExampleValue: 2, |
||||
|
appCommonNameKey: 1, |
||||
|
appSomeOtherKeyItem: 3, |
||||
|
}; |
||||
|
|
||||
|
const expectedNestedObject = { |
||||
|
app: { |
||||
|
another: { |
||||
|
keyExampleValue: 2, |
||||
|
}, |
||||
|
common: { |
||||
|
nameKey: 1, |
||||
|
}, |
||||
|
some: { |
||||
|
otherKeyItem: 3, |
||||
|
}, |
||||
|
}, |
||||
|
}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 3)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
|
||||
|
it('should handle empty object', () => { |
||||
|
const flatObject = {}; |
||||
|
|
||||
|
const expectedNestedObject = {}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
|
||||
|
it('should handle single key object', () => { |
||||
|
const flatObject = { |
||||
|
singleKey: 1, |
||||
|
}; |
||||
|
|
||||
|
const expectedNestedObject = { |
||||
|
singleKey: 1, |
||||
|
}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
|
||||
|
it('should handle complex keys', () => { |
||||
|
const flatObject = { |
||||
|
anotherComplexKeyWithParts: 2, |
||||
|
complexKeyWithMultipleParts: 1, |
||||
|
}; |
||||
|
|
||||
|
const expectedNestedObject = { |
||||
|
anotherComplexKeyWithParts: 2, |
||||
|
complexKeyWithMultipleParts: 1, |
||||
|
}; |
||||
|
|
||||
|
expect(nestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
||||
|
}); |
||||
|
}); |
||||
@ -0,0 +1,70 @@ |
|||||
|
import { toLowerCaseFirstLetter } from '@vben-core/toolkit'; |
||||
|
|
||||
|
/** |
||||
|
* 将扁平对象转换为嵌套对象。 |
||||
|
* |
||||
|
* @template T - 输入对象值的类型 |
||||
|
* @param {Record<string, T>} obj - 要转换的扁平对象 |
||||
|
* @param {number} level - 嵌套的层级 |
||||
|
* @returns {T} 嵌套对象 |
||||
|
* |
||||
|
* @example |
||||
|
* 将扁平对象转换为嵌套对象,嵌套层级为 1 |
||||
|
* const flatObject = { |
||||
|
* 'commonAppName': 1, |
||||
|
* 'anotherKeyExample': 2, |
||||
|
* 'someOtherKey': 3 |
||||
|
* }; |
||||
|
* const nestedObject = nestedObject(flatObject, 1); |
||||
|
* console.log(nestedObject); |
||||
|
* 输出: |
||||
|
* { |
||||
|
* commonAppName: 1, |
||||
|
* anotherKeyExample: 2, |
||||
|
* someOtherKey: 3 |
||||
|
* } |
||||
|
* |
||||
|
* @example |
||||
|
* 将扁平对象转换为嵌套对象,嵌套层级为 2 |
||||
|
* const flatObject = { |
||||
|
* 'appCommonName': 1, |
||||
|
* 'appAnotherKeyExample': 2, |
||||
|
* 'appSomeOtherKey': 3 |
||||
|
* }; |
||||
|
* const nestedObject = nestedObject(flatObject, 2); |
||||
|
* console.log(nestedObject); |
||||
|
* 输出: |
||||
|
* { |
||||
|
* app: { |
||||
|
* commonName: 1, |
||||
|
* anotherKeyExample: 2, |
||||
|
* someOtherKey: 3 |
||||
|
* } |
||||
|
* } |
||||
|
*/ |
||||
|
|
||||
|
function nestedObject<T>(obj: Record<string, T>, level: number): T { |
||||
|
const result: any = {}; |
||||
|
|
||||
|
for (const key in obj) { |
||||
|
const keys = key.split(/(?=[A-Z])/); |
||||
|
// 将驼峰式分割为数组;
|
||||
|
let current = result; |
||||
|
|
||||
|
for (let i = 0; i < keys.length; i++) { |
||||
|
const lowerKey = keys[i].toLowerCase(); |
||||
|
if (i === level - 1) { |
||||
|
const remainingKeys = keys.slice(i).join(''); // 保留后续部分作为键的一部分
|
||||
|
current[toLowerCaseFirstLetter(remainingKeys)] = obj[key]; |
||||
|
break; |
||||
|
} else { |
||||
|
current[lowerKey] = current[lowerKey] || {}; |
||||
|
current = current[lowerKey]; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
return result as T; |
||||
|
} |
||||
|
|
||||
|
export { nestedObject }; |
||||
@ -1 +0,0 @@ |
|||||
export * from './object'; |
|
||||
@ -1,245 +0,0 @@ |
|||||
import { describe, expect, it } from 'vitest'; |
|
||||
|
|
||||
import { flattenObject, toCamelCase, toNestedObject } from './object'; |
|
||||
|
|
||||
describe('toCamelCase', () => { |
|
||||
it('should return the key if parentKey is empty', () => { |
|
||||
expect(toCamelCase('child', '')).toBe('child'); |
|
||||
}); |
|
||||
|
|
||||
it('should combine parentKey and key in camel case', () => { |
|
||||
expect(toCamelCase('child', 'parent')).toBe('parentChild'); |
|
||||
}); |
|
||||
|
|
||||
it('should handle empty key and parentKey', () => { |
|
||||
expect(toCamelCase('', '')).toBe(''); |
|
||||
}); |
|
||||
|
|
||||
it('should handle key with capital letters', () => { |
|
||||
expect(toCamelCase('Child', 'parent')).toBe('parentChild'); |
|
||||
expect(toCamelCase('Child', 'Parent')).toBe('ParentChild'); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
describe('flattenObject', () => { |
|
||||
it('should flatten a nested object correctly', () => { |
|
||||
const nestedObject = { |
|
||||
language: 'en', |
|
||||
notifications: { |
|
||||
email: true, |
|
||||
push: { |
|
||||
sound: true, |
|
||||
vibration: false, |
|
||||
}, |
|
||||
}, |
|
||||
theme: 'light', |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
language: 'en', |
|
||||
notificationsEmail: true, |
|
||||
notificationsPushSound: true, |
|
||||
notificationsPushVibration: false, |
|
||||
theme: 'light', |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle empty objects', () => { |
|
||||
const nestedObject = {}; |
|
||||
const expected = {}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle objects with primitive values', () => { |
|
||||
const nestedObject = { |
|
||||
active: true, |
|
||||
age: 30, |
|
||||
name: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
active: true, |
|
||||
age: 30, |
|
||||
name: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle objects with null values', () => { |
|
||||
const nestedObject = { |
|
||||
user: { |
|
||||
age: null, |
|
||||
name: null, |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
userAge: null, |
|
||||
userName: null, |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle nested empty objects', () => { |
|
||||
const nestedObject = { |
|
||||
a: {}, |
|
||||
b: { c: {} }, |
|
||||
}; |
|
||||
|
|
||||
const expected = {}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle arrays within objects', () => { |
|
||||
const nestedObject = { |
|
||||
hobbies: ['reading', 'gaming'], |
|
||||
name: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
hobbies: ['reading', 'gaming'], |
|
||||
name: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
it('should flatten objects with nested arrays correctly', () => { |
|
||||
const nestedObject = { |
|
||||
person: { |
|
||||
hobbies: ['reading', 'gaming'], |
|
||||
name: 'Alice', |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
personHobbies: ['reading', 'gaming'], |
|
||||
personName: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
|
|
||||
it('should handle objects with undefined values', () => { |
|
||||
const nestedObject = { |
|
||||
user: { |
|
||||
age: undefined, |
|
||||
name: 'Alice', |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
const expected = { |
|
||||
userAge: undefined, |
|
||||
userName: 'Alice', |
|
||||
}; |
|
||||
|
|
||||
const result = flattenObject(nestedObject); |
|
||||
expect(result).toEqual(expected); |
|
||||
}); |
|
||||
}); |
|
||||
|
|
||||
describe('toNestedObject', () => { |
|
||||
it('should convert flat object to nested object with level 1', () => { |
|
||||
const flatObject = { |
|
||||
anotherKeyExample: 2, |
|
||||
commonAppName: 1, |
|
||||
someOtherKey: 3, |
|
||||
}; |
|
||||
|
|
||||
const expectedNestedObject = { |
|
||||
anotherKeyExample: 2, |
|
||||
commonAppName: 1, |
|
||||
someOtherKey: 3, |
|
||||
}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
|
|
||||
it('should convert flat object to nested object with level 2', () => { |
|
||||
const flatObject = { |
|
||||
appAnotherKeyExample: 2, |
|
||||
appCommonName: 1, |
|
||||
appSomeOtherKey: 3, |
|
||||
}; |
|
||||
|
|
||||
const expectedNestedObject = { |
|
||||
app: { |
|
||||
anotherKeyExample: 2, |
|
||||
commonName: 1, |
|
||||
someOtherKey: 3, |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 2)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
|
|
||||
it('should convert flat object to nested object with level 3', () => { |
|
||||
const flatObject = { |
|
||||
appAnotherKeyExampleValue: 2, |
|
||||
appCommonNameKey: 1, |
|
||||
appSomeOtherKeyItem: 3, |
|
||||
}; |
|
||||
|
|
||||
const expectedNestedObject = { |
|
||||
app: { |
|
||||
another: { |
|
||||
keyExampleValue: 2, |
|
||||
}, |
|
||||
common: { |
|
||||
nameKey: 1, |
|
||||
}, |
|
||||
some: { |
|
||||
otherKeyItem: 3, |
|
||||
}, |
|
||||
}, |
|
||||
}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 3)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
|
|
||||
it('should handle empty object', () => { |
|
||||
const flatObject = {}; |
|
||||
|
|
||||
const expectedNestedObject = {}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
|
|
||||
it('should handle single key object', () => { |
|
||||
const flatObject = { |
|
||||
singleKey: 1, |
|
||||
}; |
|
||||
|
|
||||
const expectedNestedObject = { |
|
||||
singleKey: 1, |
|
||||
}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
|
|
||||
it('should handle complex keys', () => { |
|
||||
const flatObject = { |
|
||||
anotherComplexKeyWithParts: 2, |
|
||||
complexKeyWithMultipleParts: 1, |
|
||||
}; |
|
||||
|
|
||||
const expectedNestedObject = { |
|
||||
anotherComplexKeyWithParts: 2, |
|
||||
complexKeyWithMultipleParts: 1, |
|
||||
}; |
|
||||
|
|
||||
expect(toNestedObject(flatObject, 1)).toEqual(expectedNestedObject); |
|
||||
}); |
|
||||
}); |
|
||||
Loading…
Reference in new issue