Odoo GraphQL Subscription using Node, Express JS for Sample
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

197 lines
8.1 KiB

const { toString, hasOwnProperty } = Object.prototype;
const fnToStr = Function.prototype.toString;
const previousComparisons = new Map();
/**
* Performs a deep equality check on two JavaScript values, tolerating cycles.
*/
export function equal(a, b) {
try {
return check(a, b);
}
finally {
previousComparisons.clear();
}
}
// Allow default imports as well.
export default equal;
function check(a, b) {
// If the two values are strictly equal, our job is easy.
if (a === b) {
return true;
}
// Object.prototype.toString returns a representation of the runtime type of
// the given value that is considerably more precise than typeof.
const aTag = toString.call(a);
const bTag = toString.call(b);
// If the runtime types of a and b are different, they could maybe be equal
// under some interpretation of equality, but for simplicity and performance
// we just return false instead.
if (aTag !== bTag) {
return false;
}
switch (aTag) {
case '[object Array]':
// Arrays are a lot like other objects, but we can cheaply compare their
// lengths as a short-cut before comparing their elements.
if (a.length !== b.length)
return false;
// Fall through to object case...
case '[object Object]': {
if (previouslyCompared(a, b))
return true;
const aKeys = definedKeys(a);
const bKeys = definedKeys(b);
// If `a` and `b` have a different number of enumerable keys, they
// must be different.
const keyCount = aKeys.length;
if (keyCount !== bKeys.length)
return false;
// Now make sure they have the same keys.
for (let k = 0; k < keyCount; ++k) {
if (!hasOwnProperty.call(b, aKeys[k])) {
return false;
}
}
// Finally, check deep equality of all child properties.
for (let k = 0; k < keyCount; ++k) {
const key = aKeys[k];
if (!check(a[key], b[key])) {
return false;
}
}
return true;
}
case '[object Error]':
return a.name === b.name && a.message === b.message;
case '[object Number]':
// Handle NaN, which is !== itself.
if (a !== a)
return b !== b;
// Fall through to shared +a === +b case...
case '[object Boolean]':
case '[object Date]':
return +a === +b;
case '[object RegExp]':
case '[object String]':
return a == `${b}`;
case '[object Map]':
case '[object Set]': {
if (a.size !== b.size)
return false;
if (previouslyCompared(a, b))
return true;
const aIterator = a.entries();
const isMap = aTag === '[object Map]';
while (true) {
const info = aIterator.next();
if (info.done)
break;
// If a instanceof Set, aValue === aKey.
const [aKey, aValue] = info.value;
// So this works the same way for both Set and Map.
if (!b.has(aKey)) {
return false;
}
// However, we care about deep equality of values only when dealing
// with Map structures.
if (isMap && !check(aValue, b.get(aKey))) {
return false;
}
}
return true;
}
case '[object Uint16Array]':
case '[object Uint8Array]': // Buffer, in Node.js.
case '[object Uint32Array]':
case '[object Int32Array]':
case '[object Int8Array]':
case '[object Int16Array]':
case '[object ArrayBuffer]':
// DataView doesn't need these conversions, but the equality check is
// otherwise the same.
a = new Uint8Array(a);
b = new Uint8Array(b);
// Fall through...
case '[object DataView]': {
let len = a.byteLength;
if (len === b.byteLength) {
while (len-- && a[len] === b[len]) {
// Keep looping as long as the bytes are equal.
}
}
return len === -1;
}
case '[object AsyncFunction]':
case '[object GeneratorFunction]':
case '[object AsyncGeneratorFunction]':
case '[object Function]': {
const aCode = fnToStr.call(a);
if (aCode !== fnToStr.call(b)) {
return false;
}
// We consider non-native functions equal if they have the same code
// (native functions require === because their code is censored).
// Note that this behavior is not entirely sound, since !== function
// objects with the same code can behave differently depending on
// their closure scope. However, any function can behave differently
// depending on the values of its input arguments (including this)
// and its calling context (including its closure scope), even
// though the function object is === to itself; and it is entirely
// possible for functions that are not === to behave exactly the
// same under all conceivable circumstances. Because none of these
// factors are statically decidable in JavaScript, JS function
// equality is not well-defined. This ambiguity allows us to
// consider the best possible heuristic among various imperfect
// options, and equating non-native functions that have the same
// code has enormous practical benefits, such as when comparing
// functions that are repeatedly passed as fresh function
// expressions within objects that are otherwise deeply equal. Since
// any function created from the same syntactic expression (in the
// same code location) will always stringify to the same code
// according to fnToStr.call, we can reasonably expect these
// repeatedly passed function expressions to have the same code, and
// thus behave "the same" (with all the caveats mentioned above),
// even though the runtime function objects are !== to one another.
return !endsWith(aCode, nativeCodeSuffix);
}
}
// Otherwise the values are not equal.
return false;
}
function definedKeys(obj) {
// Remember that the second argument to Array.prototype.filter will be
// used as `this` within the callback function.
return Object.keys(obj).filter(isDefinedKey, obj);
}
function isDefinedKey(key) {
return this[key] !== void 0;
}
const nativeCodeSuffix = "{ [native code] }";
function endsWith(full, suffix) {
const fromIndex = full.length - suffix.length;
return fromIndex >= 0 &&
full.indexOf(suffix, fromIndex) === fromIndex;
}
function previouslyCompared(a, b) {
// Though cyclic references can make an object graph appear infinite from the
// perspective of a depth-first traversal, the graph still contains a finite
// number of distinct object references. We use the previousComparisons cache
// to avoid comparing the same pair of object references more than once, which
// guarantees termination (even if we end up comparing every object in one
// graph to every object in the other graph, which is extremely unlikely),
// while still allowing weird isomorphic structures (like rings with different
// lengths) a chance to pass the equality test.
let bSet = previousComparisons.get(a);
if (bSet) {
// Return true here because we can be sure false will be returned somewhere
// else if the objects are not equivalent.
if (bSet.has(b))
return true;
}
else {
previousComparisons.set(a, bSet = new Set);
}
bSet.add(b);
return false;
}
//# sourceMappingURL=index.js.map