Purpose of this ECMAScript library is to deeply examine an object through processor (exported function objectBrowse
) which calls a custom generator at each breakdown step of this object. Purpose of this library is also to provide a function which internally uses such a generator to make/build a sub-object from an object (done by exported function makeSubObjectFrom
). This sub-object clones all sub-objects it is directed to copy
Making a sub-object with makeSubObjectFrom
is indeed the main drive for this library. However, objectBrowse
processor is exposed for possible purposes where it could help in deep-examination of an object
As a bonus, another function is provided objectIncludes
which helps deeply compare properties and values of two objects
Prototype: objectBrowse (object, processor, initialValue)
with:
object
: the object (or array) to deeply examine extracting its non-inherited properties and those of sub-objects it contains and feeds a generator function with each step of this processprocessor
: a generator function which receives information at each step through itsyield
result and should itself return a result in theyield
call which will be eventually passed in theobjectBrowse
result. What this generator gets at every stage is an object with the following properties:prop
: the examined property, a string or a number (ornull
at level 0, see details below)value
: value corresponding toprop
in the examined object. This value is a reference to the sub-object is case this sub-object is an array or an objecttype
: an integer, which is 0 if value a terminal value, 1 if it is a sub-object, 2 if it is an arraylevel
: an integer which starts from 0 and increases when process goes deeper into sub-objects and arrays. At level 0, prop is always null andtype
can only be 2 or 1, meaning associatedvalue
is an array or not
initialValue
: an initial parameter which will passed toprocessor
What processor
is supposed to do, is to provide an object literal through yield
with the following properties:
result
: connected to whatobjectBrowse
is supposed to finally returnstopAtThisLevel
: if and only iftr
ue will instructobjectBrowse
to stop nesting any deeper from the currentprop
Returned value by objectBrowse
is a literal with the following properties:
result
: what the processor returned in its lastyield
as propresult
completed
:true
generally orfalse
if the processor generator function called areturn
instead of ayield
what of course aborts the entire examination
When processor function calls a return
, it does not have to provide a literal (as it is for yield
): what is returns will be directly copied in the result
property of the returned value of objectBrowse
As the description above is a little bit terse, a small example could help clarify things. Suppose we have:
const object = {
level1_a: "starting...",
level1_b: { level2_a: 21, level2_b: 22 },
level1_c: [NaN, 1 / 0, 42, { pi: Math.PI, doublePi: Math.PI * 2 }],
level1_d: "...finished",
};
And a plain generator function as processor
:
reflectInArray = function* () {
const result = [];
while (true) {
result.push(yield { result });
}
};
which piles every information passed to it into an array. Then calling:
const r = objectBrowse(object, reflectInArray);
will produce a result equivalent to this:
{ completed: true,
result; [
{ prop: null, value: object, type: 1, level: 0 },
{ prop: "level1_a", value: "starting...", type: 0, level: 1 },
{ prop: "level1_b", value: object.level1_b, type: 1, level: 1 },
{ prop: "level2_a", value: 21, type: 0, level: 2 },
{ prop: "level2_b", value: 22, type: 0, level: 2 },
{ prop: "level1_c", value: object.level1_c, type: 2, level: 1 },
{ prop: 0, value: NaN, type: 0, level: 2 },
{ prop: 1, value: Infinity, type: 0, level: 2 },
{ prop: 2, value: 42, type: 0, level: 2 },
{ prop: 3, value: object.level1_c[3], type: 1, level: 2 },
{ prop: "pi", value: 3.141592653589793, type: 0, level: 3 },
{ prop: "doublePi", value: 6.283185307179586, type: 0, level: 3 },
{ prop: "level1_d", value: "...finished", type: 0, level: 1 },
];
}
Prototype: makeSubObjectFrom(pattern, source)
with:
pattern
: an object literal whose properties, sub arrays, and sub-objects serve as a pattern to define which sub-structure of the object to copy by cloning we are interested in. Values of this pattern are ignoredsource
: the source object from which values will be copied
Values from source cover every JSON type and more. In this it supersedes it with regular expressions, functions, etc. However test better be made for special types as described in the Structured Clone Algorithm
If some property in pattern
is not found in source
, the function with throw a generic error with a message explicating what property was missing
Note: using makeSubObjectFrom
when pattern
and source
are equal (in reference or value), is a way to clone an object
const pattern = {
a: null,
b: { bb: null, bc: null, bd: { bde: null, bdf: null } },
c: [null, { c1d: null, c1e: null }],
d: null,
};
const source = {
a: "a",
b: { bb: "bb", bc: NaN, bd: { bde: "bde", bdf: "bdf", ignore: 0 }, ignore: 0 },
c: [3, { c1d: 31, c1e: 32, ignore1: 33, ignore2: 34 }],
d: "d",
ignore: "e",
};
const result = makeSubObjectFrom(pattern, source);
will produce the following result:
{ completed: true,
result: {
a: "a",
b: { bb: "bb", bc: NaN, bd: { bde: "bde", bdf: "bdf" } },
c: [3, { c1d: 31, c1e: 32 }],
d: "d",
}
}
Prototype: objectIncludes(inclusiveObject, includedObject)
with:
inclusiveObject
: the object which must deeply include properties and values ofincludedObject
includedObject
: the object which properties and values must be contained ininclusiveObject
Return value is true
in case of successful comparison or if not successful, a string like the following ones is returned:
wrong base type: one is an array, the other is not
inclusiveObject has no property "x.y.z"
compared object values at property "x.y.z" differ
Properties x.y.z above are just examples
Note: objectIncludes
is a base function as a means to deeply compare objects with the benefit an explicit error message is returned in case of non success . To do this deep compare objectIncludes
must be called two times swapping objects and expecting a true
outcome in each case