完善 README 文档,添加功能特性、使用说明及开发脚本;在转换逻辑中支持嵌套对象构建

This commit is contained in:
lirui
2026-02-09 20:13:40 +08:00
parent 36f5d247b1
commit c7f97f77c7
3 changed files with 143 additions and 32 deletions

View File

@@ -100,6 +100,27 @@ describe('convertData', () => {
const result = convertData(rows, mappings);
expect(result[0]).toEqual({ full_name: 'Alice' });
});
it('builds nested objects from dot-separated target keys', () => {
const mappings: MappingConfig[] = [
{ source: 'name', target: 'user.name', type: 'string', excludeIfEmpty: false, defaultValue: '', enabled: true },
{ source: 'age', target: 'user.age', type: 'number', excludeIfEmpty: false, defaultValue: '', enabled: true },
{ source: 'active', target: 'meta.active', type: 'boolean', excludeIfEmpty: false, defaultValue: '', enabled: true }
];
const result = convertData(rows, mappings);
expect(result[0]).toEqual({
user: { name: 'Alice', age: 30 },
meta: { active: true }
});
});
it('builds deeply nested objects', () => {
const mappings: MappingConfig[] = [
{ source: 'name', target: 'a.b.c.d', type: 'string', excludeIfEmpty: false, defaultValue: '', enabled: true }
];
const result = convertData(rows, mappings);
expect(result[0]).toEqual({ a: { b: { c: { d: 'Alice' } } } });
});
});
describe('date conversion', () => {

View File

@@ -63,6 +63,31 @@ function formatDate(value: unknown, format?: string): string | number {
return date.format(format || 'YYYY-MM-DD');
}
/**
* Set a value at a dot-separated path, creating nested objects as needed.
* e.g. setNested(obj, "user.address.city", "Beijing")
* => obj = { user: { address: { city: "Beijing" } } }
*/
function setNested(obj: Record<string, unknown>, path: string, value: unknown): void {
if (!path.includes('.')) {
obj[path] = value;
return;
}
const keys = path.split('.');
let current: Record<string, unknown> = obj;
for (let i = 0; i < keys.length - 1; i++) {
const key = keys[i];
if (current[key] === undefined || current[key] === null || typeof current[key] !== 'object') {
current[key] = {};
}
current = current[key] as Record<string, unknown>;
}
current[keys[keys.length - 1]] = value;
}
/**
* Convert raw Excel rows to JSON objects based on mapping configs.
*/
@@ -83,13 +108,13 @@ export function convertData(
continue;
}
if (isEmptyVal) {
obj[mapping.target] = mapping.defaultValue !== undefined && mapping.defaultValue !== ''
const finalValue = isEmptyVal
? (mapping.defaultValue !== undefined && mapping.defaultValue !== ''
? convertValue(mapping.defaultValue, mapping.type, mapping.format)
: null;
} else {
obj[mapping.target] = convertValue(rawValue, mapping.type, mapping.format);
}
: null)
: convertValue(rawValue, mapping.type, mapping.format);
setNested(obj, mapping.target, finalValue);
}
return obj;