⚝
One Hat Cyber Team
⚝
Your IP:
172.22.0.1
Server IP:
151.80.20.34
Server:
Linux 794f04d97d5e 5.15.0-143-generic #153-Ubuntu SMP Fri Jun 13 19:10:45 UTC 2025 x86_64
Server Software:
Apache/2.4.62 (Debian)
PHP Version:
8.2.28
Buat File
|
Buat Folder
Eksekusi
Dir :
~
/
usr
/
share
/
nodejs
/
tcompare
/
dist
/
cjs
/
View File Name :
same.js
"use strict"; // Same is the base class for all comparators // // We walk through both of the expect and actual objects, // creating a Same node for each field in common, based on // their similarity: // - true (they're a match) omit from the result (the child node is discarded) // - false (they're simply nonmatching) format both expect and object // - COMPLEX - walk through child nodes // - if match: child node is discarded // - else, child node is retained (along with its non-matching children) // // We 'discard' by just having the print method return '' // // When walking child nodes, we use the shouldCompare(key) method to determine // whether to check a given field. In this class, this is always true (because // we are testing for full deep sameness), but in Has classes, it's more // complicated (only test nodes that exist in the expect object). Object.defineProperty(exports, "__esModule", { value: true }); exports.Same = void 0; const diff_1 = require("diff"); const format_js_1 = require("./format.js"); const arrayFrom = (obj) => { try { return Array.from(obj); } catch (_) { return null; } }; const { hasOwnProperty } = Object.prototype; const { defineProperty } = Object; class Same extends format_js_1.Format { constructor(obj, options) { if (!options || typeof options !== 'object') { throw new TypeError('must supply options object'); } if (!('expect' in options)) { throw new TypeError('must supply expected value'); } super(obj, options); this.simple = null; this.match = true; this.diffContext = 10; this.memoDiff = null; this.memoExpect = null; this.parent = options.parent || null; this.expect = options.expect; if (!this.style.diffable) { throw new Error(`"${options.style}" style not appropriate for diffs`); } if (options.diffContext) { this.diffContext = options.diffContext; } this.provisional = !!options.provisional; this.simpleMatch(); } simpleMatch() { this.simple = this.test(); if (this.seen() !== this.seenExpect()) { this.simple = false; } if (!this.simple) { this.unmatch(); } } test() { const a = this.object; const b = this.expect; return typeof a === 'function' && typeof b === 'function' ? a === b || (a.name === b.name && a.toString() === b.toString()) : typeof a === 'symbol' || typeof b === 'symbol' ? typeof a === typeof b && a.toString() === b.toString() : typeof a !== 'object' && typeof b !== 'object' && a == b ? true : a === b ? true : a === null || b === null ? a == b : a !== a ? b !== b : typeof a !== 'object' || typeof b !== 'object' ? false : !this.isError() && b instanceof Error ? false : this.isError() && ((b.message && b.message !== a.message) || (b.name && b.name !== a.name)) ? false : this.isSet() && !new format_js_1.Format(b).isSet() ? false : this.isMap() && !new format_js_1.Format(b).isMap() ? false : this.isArray() && !new format_js_1.Format(b).isArray() ? false : Buffer.isBuffer(a) && Buffer.isBuffer(b) ? a.equals(b) : a instanceof Date && b instanceof Date ? a.getTime() === b.getTime() : a instanceof RegExp && b instanceof RegExp ? this.regexpSame(a, b) : 'COMPLEX'; // might still be a deeper mismatch, of course } regexpSame(a, b) { return (a.source === b.source && a.global === b.global && a.multiline === b.multiline && a.lastIndex === b.lastIndex && a.ignoreCase === b.ignoreCase); } unmatch() { if (this.match) { this.match = false; if (!this.provisional) { this.parent && this.parent.unmatch(); } } } // just print the thing as-is simplePrint(obj, options = {}) { return new format_js_1.Format(obj, { ...this.options, ...options, }).print(); } simplePrintExpect() { return new format_js_1.Format(this.expect, { ...this.options, seen: this.seenExpect, }).print(); } seenExpect() { if (!this.expect || typeof this.expect !== 'object') { return false; } for (let p = this.parent; p; p = p.parent) { if (p.expect === this.expect) { p.id = p.id || p.getId(); return p; } } return false; } // if it's the root, then we do the diff // otherwise, we do the dual-walk of both trees, // building up the object and expect memos // this actually returns '' for any non-root node. print() { if (this.memo === null && this.memoExpect === null) { this.memo = ''; this.memoExpect = ''; if (!this.simple) { this.unmatch(); this.memo += this.simplePrint(this.object); this.memoExpect += this.simplePrintExpect(); } else { const seen = this.seen(); const seenExpect = this.seenExpect(); if (this.simple === true && seen === seenExpect) { this.memo = ''; this.memoExpect = ''; } else { if (seen) { this.printCircular(this.object); } else { this.printCollection(); } } } } return this.diff(); } printCircular(seen) { this.memo += this.style.circular(seen); const seenExpect = this.seenExpect(); this.memoExpect = this.memoExpect || ''; if (seenExpect) { this.memoExpect += this.style.circular(seenExpect); } } diff() { // impossible /* c8 ignore start */ if (this.memoExpect === null || this.memo === null) { throw new TypeError('called diff() prior to print()'); } /* c8 ignore stop */ if (this.parent || this.match || this.memoExpect === this.memo) { return (this.memoDiff = ''); } if (this.memoDiff !== null) { return this.memoDiff; } return (this.memoDiff = (0, diff_1.createTwoFilesPatch)('expected', 'actual', this.memoExpect + '\n', this.memo + '\n', undefined, undefined, { context: this.diffContext }).replace(/^\=+\n/, '')); } child(obj, options, cls) { const expectKey = hasOwnProperty.call(options, 'expectKey') ? options.expectKey : options.key; return super.child(obj, { expect: this.childExpect(expectKey), ...options, }, cls); } childExpect(key) { // if we get here, we know that both expect and actual // are collections of the same type. Otherwise they // would have gotten the simple printed diff. return this.isSet() ? key : this.isMap() ? this.expect.get(key) : this.isArray() ? this.expectAsArray[key] : this.expect[key]; } get expectAsArray() { const value = Array.isArray(this.expect) ? this.expect : new format_js_1.Format(this.expect).isArray() ? arrayFrom(this.expect) : /* c8 ignore start */ null; /* c8 ignore stop */ defineProperty(this, 'expectAsArray', { value }); return value; } printStart() { if (!this.parent) { this.memo = this.nodeId() + this.memo; this.memoExpect = this.nodeId() + this.memoExpect; return; } // we always simple print keys /* c8 ignore start */ const indent = this.isKey ? '' : this.indentLevel(); /* c8 ignore stop */ // this will always be keyless, because Array and Set // objects are always simple printed. But if that // chagnes, this will be relevant. /* c8 ignore start */ const key = this.isKeyless() ? '' : this.getKey(); /* c8 ignore stop */ const sep = !key ? '' : this.parent && this.parent.isMap() ? this.style.mapKeyValSep() : this.style.pojoKeyValSep(); const start = this.style.start(indent, key, sep); this.memo = start + this.nodeId() + this.memo; this.memoExpect = start + this.nodeId() + this.memoExpect; } printEnd() { if (!this.parent || this.isKey) { return; } const end = this.parent.isMap() ? this.style.mapEntrySep() : this.parent.isArray() ? this.style.arrayEntrySep() : // these types are always simple printed /* c8 ignore start */ this.parent.isSet() ? this.style.setEntrySep() : this.parent.isBuffer() ? '' : this.parent.isString() ? '' : /* c8 ignore stop */ this.style.pojoEntrySep(); this.memo += end; this.memoExpect += end; } printPojo() { // even though it's not a simple mismatch, it's possible that // a child entry will cause a mismatch, so we have to print // the body *before* doing the head. If we still aren't unmatched // after walking the graph, then nothing to do. if (this.pojoIsEmpty()) { this.memo = this.memo || ''; this.memo += this.printPojoEmpty(); } else { this.printPojoBody(); if (!this.match) { this.printPojoHead(); this.printStart(); this.printPojoTail(); this.printEnd(); } } } pojoIsEmpty() { return super.pojoIsEmpty() && this.pojoExpectIsEmpty(); } pojoExpectIsEmpty() { return super.pojoIsEmpty(this.expect); } printPojoEmpty() { // both are empty and not a simple mismatch, nothing to do } getPojoKeys(obj = this.object) { const fromSuper = super.getPojoKeys(obj); if (obj === this.expect) { return fromSuper; } return fromSuper.concat(this.getPojoKeys(this.expect).filter(k => k in obj)); } printPojoHead() { const h = this.style.pojoHead(this.getClass()); this.memo = h + this.memo; this.memoExpect = h + this.memoExpect; } printPojoTail() { const t = this.style.pojoTail(this.indentLevel()); this.memo += t; this.memoExpect += t; } printPojoBody() { const objEnt = new Map(this.getPojoEntries(this.object)); const expEnt = new Map(this.getPojoEntries(this.expect)); for (const [key, val] of objEnt.entries()) { if (!expEnt.has(key)) { this.unmatch(); } this.printPojoEntry(key, val, false); } for (const key of expEnt.keys()) { if (objEnt.has(key)) { continue; } this.unmatch(); this.printPojoEntry(key, undefined, true); } } printPojoEntry(key, val, notFound) { const child = this.child(val, { key }); child.print(); if (!notFound) { this.memo += child.memo; } if (notFound || hasOwnProperty.call(this.expect, key)) { this.memoExpect += child.memoExpect; } } // error is just a pojo with some fancy styling printError() { if (this.errorIsEmpty()) { return this.printErrorEmpty(); } else { this.printErrorBody(); if (!this.match) { this.printErrorHead(); this.printStart(); this.printErrorTail(); this.printEnd(); } } } errorIsEmpty() { return super.errorIsEmpty() && this.expectErrorIsEmpty(); } expectErrorIsEmpty() { return (this.getPojoEntries(this.expect).filter(([k]) => k !== 'name' && k !== 'message').length === 0); } printErrorEmpty() { // nothing to do } printErrorHead() { const headObj = this.style.errorHead(this.object, this.getClass()); this.memo = headObj + this.memo; const headExp = this.style.errorHead(this.expect, this.getClass()); this.memoExpect = headExp + this.memoExpect; } printErrorTail() { const t = this.style.errorTail(this.indentLevel()); this.memo += t; this.memoExpect += t; } // maps are like pojos with fancier keys printMap() { if (this.mapIsEmpty()) { this.printMapEmpty(); } else { this.printMapBody(); if (!this.match) { this.printMapHead(); this.printStart(); this.printMapTail(); this.printEnd(); } } } mapIsEmpty() { return super.mapIsEmpty() && this.mapExpectIsEmpty(); } mapExpectIsEmpty() { return this.expect.size === 0; } printMapHead() { const h = this.style.mapHead(this.getClass()); this.memo = h + this.memo; this.memoExpect = h + this.memoExpect; } printMapTail() { const t = this.style.mapTail(this.indentLevel()); this.memo += t; this.memoExpect += t; } printMapBody() { // new Map([{}:1]) matches another new Map([{}:1]) // so we can't rely on key identity. const seen = new Set(); // first pass to get any that are key identity matches for (const [key, val] of this.object.entries()) { if (this.expect.has(key)) { seen.add(key); this.printMapEntry(key, val); continue; } } for (const [key, val] of this.object.entries()) { if (seen.has(key)) { continue; } // try to find a matching key not yet seen let sawMatch = false; for (const expectKey of this.expect.keys()) { if (seen.has(expectKey)) { continue; } const s = this.child(key, { expect: expectKey, provisional: true, }); s.print(); if (s.match) { // it's a match! test against this one. sawMatch = true; seen.add(key); seen.add(expectKey); sawMatch = true; this.printMapEntry(key, val, expectKey); break; } } if (!sawMatch) { this.printMapEntryUnexpected(key, val); seen.add(key); } } // now loop over all expected values not found in object for (const [key, val] of this.expect.entries()) { if (seen.has(key)) { continue; } this.printMapEntryNotFound(key, val); } } printMapEntry(key, val, expectKey = key) { const child = this.child(val, { key, expectKey }); child.print(); this.memo += child.memo; this.memoExpect += child.memoExpect; } printMapEntryNotFound(key, val) { this.unmatch(); this.memoExpect += this.simplePrint(val, { parent: this, key, seen: this.seenExpect, }); } printMapEntryUnexpected(key, val) { this.unmatch(); this.memo += this.simplePrint(val, { key, parent: this, }); } // arrays and sets don't have useful keys, so it's really hard to see // where the mismatch occurs with only the path context. For example, // if you have an array of objects with many keys, that mismatches on // only one key in one object, we would get a diff that looks like: // [ // + {key: value}, // - {key: otherValue}, // ] // which isn't super helpful, since you don't know which index it failed // on, or even have the other properties of the object or key path to // use to find it. // So, if it's not a match, we simplePrint both the expected and object, // and let the diff sort it out, since it does a pretty good job of that // anyway. // This can be somewhat noisy, if you have an array with a single large // object, of course. An alternative approach to consider is to do the // full simplePrint for Sets, but include the Array index in the array // print, so it's at least clear where it deviated. printArray() { if (this.arrayIsEmpty()) { this.printArrayEmpty(); } else { this.printArrayBody(); } } arrayIsEmpty() { return super.arrayIsEmpty() && this.arrayExpectIsEmpty(); } arrayExpectIsEmpty() { const a = this.expectAsArray; return !!a && a.length === 0; } printArrayEmpty() { // nothing to do } printArrayBody() { // we know that they're both arrays if we got this far const obj = this.objectAsArray; const exp = this.expectAsArray; // if lengths match, just call printArrayEntry() for each of them if (exp && obj.length === exp.length) { super.printArrayBody(); } else { this.unmatch(); } if (!this.match) { this.memo += this.simplePrint(this.object); this.memoExpect = this.memoExpect || ''; this.memoExpect += this.simplePrintExpect(); } } printArrayEntry(key, val) { const child = this.child(val, { key }); child.print(); } printSet() { if (this.setIsEmpty()) { this.printSetEmpty(); } else { this.printSetBody(); } } setExpectIsEmpty() { return this.expect.size === 0; } setIsEmpty() { return super.setIsEmpty() && this.setExpectIsEmpty(); } printSetBody() { if (this.expect.size !== this.object.size) { this.unmatch(); this.memo += this.simplePrint(this.object); this.memoExpect = this.memoExpect || ''; this.memoExpect += this.simplePrintExpect(); return; } const seen = new Set(); // skip all identity matches, nothing to do for these for (const val of this.object) { if (this.expect.has(val)) { seen.add(val); continue; } } for (const val of this.object) { if (seen.has(val)) { continue; } let sawMatch = false; for (const exp of this.expect) { if (seen.has(exp)) { continue; } const s = this.child(val, { expect: exp, provisional: true, }); s.print(); if (s.match) { sawMatch = true; seen.add(exp); break; } } if (!sawMatch) { this.unmatch(); this.memo += this.simplePrint(this.object); this.memoExpect = this.memoExpect || ''; this.memoExpect += this.simplePrintExpect(); return; } } } } exports.Same = Same; //# sourceMappingURL=same.js.map