@marianmeres/topo-merge
v1.1.0
Published
Multiple inheritance for POJOs via topological sort and deep merge.
Readme
@marianmeres/topo-merge
Multiple inheritance for POJOs via topological sort and deep merge.
Installation
deno add jsr:@marianmeres/topo-mergenpm i @marianmeres/topo-mergeQuick Example
import { topoMerge } from "@marianmeres/topo-merge";
const result = topoMerge({
a: { foo: "bar" },
b: { __extends: "a", baz: "bat" },
c: { __extends: "b", hey: "ho" },
d: { __extends: "c", lets: "go", foo: "foo" },
e: { __extends: ["b", "c"] }, // multiple inheritance
});
// Result:
// a: { foo: "bar" }
// b: { foo: "bar", baz: "bat" }
// c: { foo: "bar", baz: "bat", hey: "ho" }
// d: { foo: "foo", baz: "bat", hey: "ho", lets: "go" }
// e: { foo: "bar", baz: "bat", hey: "ho" }API
topoMerge(schema, mergeOptions?, mergeOmitIdProp?)
Main function that resolves inheritance and merges objects.
function topoMerge(
schema: Record<string, WithExtends> | [string, WithExtends][],
mergeOptions?: DeepMergeOptions,
mergeOmitIdProp?: boolean // default: true
): Record<string, Record<string, any>>Parameters:
schema- Object or entries array where keys become node IDs. Each value can have an optional__extendsproperty (string or string array) referencing parent IDs.mergeOptions- Options fordeepMerge. Default:{ arrays: "replace" }.mergeOmitIdProp- Whether to exclude theidproperty from results. Default:true.
Throws:
- Circular dependency detected
- Self-reference (
__extendspointing to itself) - Missing parent reference
topoSort(nodes)
Lower-level utility for topological sorting. Most users should use topoMerge instead.
function topoSort(nodes: InheritedNode[]): InheritedNode[]Merge Behavior
- Child overrides parent - Properties defined on a node override inherited ones
- Arrays are replaced - By default, arrays replace rather than concatenate (configurable via
mergeOptions.arrays) - Deep merge - Nested objects are recursively merged
- Explicit
undefined- Set a property toundefinedto remove an inherited value:
const result = topoMerge({
base: { foo: 1, bar: 2 },
child: { __extends: "base", foo: undefined }
});
// child: { bar: 2 } (foo is removed)Types
interface WithExtends extends Record<string, any> {
__extends?: string | string[];
}
interface InheritedNode extends Record<string, any> {
id: string;
__parents?: InheritedNode[];
}