parent
a4768e0340
commit
5d86f69c79
@ -1,43 +1,75 @@ |
|||||||
interface FlattenOptions { |
interface FlattenOptions { |
||||||
/** Maximum depth to traverse (default: 8). */ |
/** Maximum depth to traverse (default: 8). */ |
||||||
maxDepth?: number; |
maxDepth?: number; |
||||||
/** Skip keys that start with a dollar sign (deepSignal meta). Default: true */ |
/** Skip keys that start with a dollar sign (deepSignal meta). Default: true */ |
||||||
skipDollarKeys?: boolean; |
skipDollarKeys?: boolean; |
||||||
} |
} |
||||||
|
|
||||||
const isPlainObject = (v: any) => |
const isPlainObject = (v: any) => |
||||||
Object.prototype.toString.call(v) === "[object Object]"; |
Object.prototype.toString.call(v) === "[object Object]"; |
||||||
|
|
||||||
const flattenObject = ( |
const flattenObject = ( |
||||||
obj: any, |
obj: any, |
||||||
prefix = "", |
prefix = "", |
||||||
options: FlattenOptions = {}, |
options: FlattenOptions = {}, |
||||||
seen = new Set<any>(), |
seen = new Set<any>(), |
||||||
depth = 0 |
depth = 0 |
||||||
): Array<[string, any, string, any]> => { |
): Array<[string, any, string, any]> => { |
||||||
const { maxDepth = 8, skipDollarKeys = true } = options; |
const { maxDepth = 8, skipDollarKeys = true } = options; |
||||||
const result: Array<[string, any, string, any]> = []; |
const result: Array<[string, any, string, any]> = []; |
||||||
if (!obj || typeof obj !== "object") return result; |
if (!obj || typeof obj !== "object") return result; |
||||||
if (seen.has(obj)) return result; // cycle detected
|
if (seen.has(obj)) return result; // cycle detected
|
||||||
seen.add(obj); |
seen.add(obj); |
||||||
if (depth > maxDepth) return result; |
if (depth > maxDepth) return result; |
||||||
|
|
||||||
for (const [key, value] of Object.entries(obj)) { |
for (const [key, value] of Object.entries(obj)) { |
||||||
if (skipDollarKeys && key.startsWith("$")) continue; |
if (skipDollarKeys && key.startsWith("$")) continue; |
||||||
const fullKey = prefix ? `${prefix}.${key}` : key; |
const fullKey = prefix ? `${prefix}.${key}` : key; |
||||||
if ( |
|
||||||
value && |
// Handle Sets containing objects with @id
|
||||||
typeof value === "object" && |
if (value instanceof Set) { |
||||||
!Array.isArray(value) && |
const setItems = Array.from(value); |
||||||
!(value instanceof Set) && |
// Check if Set contains objects with @id
|
||||||
isPlainObject(value) |
if ( |
||||||
) { |
setItems.length > 0 && |
||||||
result.push(...flattenObject(value, fullKey, options, seen, depth + 1)); |
setItems.some( |
||||||
} else { |
(item) => item && typeof item === "object" && "@id" in item |
||||||
result.push([fullKey, value, key, obj]); |
) |
||||||
|
) { |
||||||
|
// Flatten each object in the Set
|
||||||
|
setItems.forEach((item) => { |
||||||
|
if (item && typeof item === "object" && "@id" in item) { |
||||||
|
const itemId = item["@id"]; |
||||||
|
const itemPrefix = `${fullKey}[@id=${itemId}]`; |
||||||
|
result.push( |
||||||
|
...flattenObject( |
||||||
|
item, |
||||||
|
itemPrefix, |
||||||
|
options, |
||||||
|
seen, |
||||||
|
depth + 1 |
||||||
|
) |
||||||
|
); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
// Set doesn't contain objects with @id, treat as leaf
|
||||||
|
result.push([fullKey, value, key, obj]); |
||||||
|
} |
||||||
|
} else if ( |
||||||
|
value && |
||||||
|
typeof value === "object" && |
||||||
|
!Array.isArray(value) && |
||||||
|
isPlainObject(value) |
||||||
|
) { |
||||||
|
result.push( |
||||||
|
...flattenObject(value, fullKey, options, seen, depth + 1) |
||||||
|
); |
||||||
|
} else { |
||||||
|
result.push([fullKey, value, key, obj]); |
||||||
|
} |
||||||
} |
} |
||||||
} |
return result; |
||||||
return result; |
|
||||||
}; |
}; |
||||||
|
|
||||||
export default flattenObject; |
export default flattenObject; |
||||||
|
|||||||
Loading…
Reference in new issue