| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -21,35 +21,44 @@ | |||
| 21 | 21 | 'use strict'; | |
| 22 | 22 | ||
| 23 | 23 | const { | |
| 24 | + ArrayBufferIsView, | ||
| 25 | + ArrayBufferPrototypeGetByteLength, | ||
| 24 | 26 | ArrayFrom, | |
| 25 | 27 | ArrayIsArray, | |
| 26 | 28 | ArrayPrototypeIndexOf, | |
| 27 | 29 | ArrayPrototypeJoin, | |
| 28 | 30 | ArrayPrototypePush, | |
| 29 | 31 | ArrayPrototypeSlice, | |
| 32 | + DataViewPrototypeGetBuffer, | ||
| 33 | + DataViewPrototypeGetByteLength, | ||
| 34 | + DataViewPrototypeGetByteOffset, | ||
| 30 | 35 | Error, | |
| 31 | 36 | FunctionPrototypeCall, | |
| 32 | - MapPrototypeDelete, | ||
| 33 | 37 | MapPrototypeGet, | |
| 38 | + MapPrototypeGetSize, | ||
| 34 | 39 | MapPrototypeHas, | |
| 35 | - MapPrototypeSet, | ||
| 36 | 40 | NumberIsNaN, | |
| 37 | 41 | ObjectAssign, | |
| 38 | 42 | ObjectIs, | |
| 39 | 43 | ObjectKeys, | |
| 40 | 44 | ObjectPrototypeIsPrototypeOf, | |
| 45 | + ObjectPrototypeToString, | ||
| 41 | 46 | ReflectApply, | |
| 42 | 47 | ReflectHas, | |
| 43 | 48 | ReflectOwnKeys, | |
| 44 | 49 | RegExpPrototypeExec, | |
| 50 | + SafeArrayIterator, | ||
| 45 | 51 | SafeMap, | |
| 46 | 52 | SafeSet, | |
| 47 | 53 | SafeWeakSet, | |
| 54 | + SetPrototypeGetSize, | ||
| 48 | 55 | String, | |
| 49 | 56 | StringPrototypeIndexOf, | |
| 50 | 57 | StringPrototypeSlice, | |
| 51 | 58 | StringPrototypeSplit, | |
| 52 | 59 | SymbolIterator, | |
| 60 | + TypedArrayPrototypeGetLength, | ||
| 61 | + Uint8Array, | ||
| 53 | 62 | } = primordials; | |
| 54 | 63 | ||
| 55 | 64 | const { | |
@@ -65,6 +74,8 @@ const AssertionError = require('internal/assert/assertion_error'); | |||
| 65 | 74 | const { inspect } = require('internal/util/inspect'); | |
| 66 | 75 | const { Buffer } = require('buffer'); | |
| 67 | 76 | const { | |
| 77 | + isArrayBuffer, | ||
| 78 | + isDataView, | ||
| 68 | 79 | isKeyObject, | |
| 69 | 80 | isPromise, | |
| 70 | 81 | isRegExp, | |
@@ -73,6 +84,8 @@ const { | |||
| 73 | 84 | isDate, | |
| 74 | 85 | isWeakSet, | |
| 75 | 86 | isWeakMap, | |
| 87 | + isSharedArrayBuffer, | ||
| 88 | + isAnyArrayBuffer, | ||
| 76 | 89 | } = require('internal/util/types'); | |
| 77 | 90 | const { isError, deprecate, emitExperimentalWarning } = require('internal/util'); | |
| 78 | 91 | const { innerOk } = require('internal/assert/utils'); | |
@@ -369,9 +382,161 @@ function isSpecial(obj) { | |||
| 369 | 382 | } | |
| 370 | 383 | ||
| 371 | 384 | const typesToCallDeepStrictEqualWith = [ | |
| 372 | - isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer, | ||
| 385 | + isKeyObject, isWeakSet, isWeakMap, Buffer.isBuffer, isSharedArrayBuffer, | ||
| 373 | 386 | ]; | |
| 374 | 387 | ||
| 388 | + function compareMaps(actual, expected, comparedObjects) { | ||
| 389 | + if (MapPrototypeGetSize(actual) !== MapPrototypeGetSize(expected)) { | ||
| 390 | + return false; | ||
| 391 | + } | ||
| 392 | + const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual); | ||
| 393 | + | ||
| 394 | + comparedObjects ??= new SafeWeakSet(); | ||
| 395 | + | ||
| 396 | + for (const { 0: key, 1: val } of safeIterator) { | ||
| 397 | + if (!MapPrototypeHas(expected, key)) { | ||
| 398 | + return false; | ||
| 399 | + } | ||
| 400 | + if (!compareBranch(val, MapPrototypeGet(expected, key), comparedObjects)) { | ||
| 401 | + return false; | ||
| 402 | + } | ||
| 403 | + } | ||
| 404 | + return true; | ||
| 405 | + } | ||
| 406 | + | ||
| 407 | + function partiallyCompareArrayBuffersOrViews(actual, expected) { | ||
| 408 | + let actualView, expectedView, expectedViewLength; | ||
| 409 | + | ||
| 410 | + if (!ArrayBufferIsView(actual)) { | ||
| 411 | + let actualViewLength; | ||
| 412 | + | ||
| 413 | + if (isArrayBuffer(actual) && isArrayBuffer(expected)) { | ||
| 414 | + actualViewLength = ArrayBufferPrototypeGetByteLength(actual); | ||
| 415 | + expectedViewLength = ArrayBufferPrototypeGetByteLength(expected); | ||
| 416 | + } else if (isSharedArrayBuffer(actual) && isSharedArrayBuffer(expected)) { | ||
| 417 | + actualViewLength = actual.byteLength; | ||
| 418 | + expectedViewLength = expected.byteLength; | ||
| 419 | + } else { | ||
| 420 | + // Cannot compare ArrayBuffers with SharedArrayBuffers | ||
| 421 | + return false; | ||
| 422 | + } | ||
| 423 | + | ||
| 424 | + if (expectedViewLength > actualViewLength) { | ||
| 425 | + return false; | ||
| 426 | + } | ||
| 427 | + actualView = new Uint8Array(actual); | ||
| 428 | + expectedView = new Uint8Array(expected); | ||
| 429 | + | ||
| 430 | + } else if (isDataView(actual)) { | ||
| 431 | + if (!isDataView(expected)) { | ||
| 432 | + return false; | ||
| 433 | + } | ||
| 434 | + const actualByteLength = DataViewPrototypeGetByteLength(actual); | ||
| 435 | + expectedViewLength = DataViewPrototypeGetByteLength(expected); | ||
| 436 | + if (expectedViewLength > actualByteLength) { | ||
| 437 | + return false; | ||
| 438 | + } | ||
| 439 | + | ||
| 440 | + actualView = new Uint8Array( | ||
| 441 | + DataViewPrototypeGetBuffer(actual), | ||
| 442 | + DataViewPrototypeGetByteOffset(actual), | ||
| 443 | + actualByteLength, | ||
| 444 | + ); | ||
| 445 | + expectedView = new Uint8Array( | ||
| 446 | + DataViewPrototypeGetBuffer(expected), | ||
| 447 | + DataViewPrototypeGetByteOffset(expected), | ||
| 448 | + expectedViewLength, | ||
| 449 | + ); | ||
| 450 | + } else { | ||
| 451 | + if (ObjectPrototypeToString(actual) !== ObjectPrototypeToString(expected)) { | ||
| 452 | + return false; | ||
| 453 | + } | ||
| 454 | + actualView = actual; | ||
| 455 | + expectedView = expected; | ||
| 456 | + expectedViewLength = TypedArrayPrototypeGetLength(expected); | ||
| 457 | + | ||
| 458 | + if (expectedViewLength > TypedArrayPrototypeGetLength(actual)) { | ||
| 459 | + return false; | ||
| 460 | + } | ||
| 461 | + } | ||
| 462 | + | ||
| 463 | + for (let i = 0; i < expectedViewLength; i++) { | ||
| 464 | + if (actualView[i] !== expectedView[i]) { | ||
| 465 | + return false; | ||
| 466 | + } | ||
| 467 | + } | ||
| 468 | + | ||
| 469 | + return true; | ||
| 470 | + } | ||
| 471 | + | ||
| 472 | + function partiallyCompareSets(actual, expected, comparedObjects) { | ||
| 473 | + if (SetPrototypeGetSize(expected) > SetPrototypeGetSize(actual)) { | ||
| 474 | + return false; // `expected` can't be a subset if it has more elements | ||
| 475 | + } | ||
| 476 | + | ||
| 477 | + if (isDeepEqual === undefined) lazyLoadComparison(); | ||
| 478 | + | ||
| 479 | + const actualArray = ArrayFrom(FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], actual)); | ||
| 480 | + const expectedIterator = FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], expected); | ||
| 481 | + const usedIndices = new SafeSet(); | ||
| 482 | + | ||
| 483 | + expectedIteration: for (const expectedItem of expectedIterator) { | ||
| 484 | + for (let actualIdx = 0; actualIdx < actualArray.length; actualIdx++) { | ||
| 485 | + if (!usedIndices.has(actualIdx) && isDeepStrictEqual(actualArray[actualIdx], expectedItem)) { | ||
| 486 | + usedIndices.add(actualIdx); | ||
| 487 | + continue expectedIteration; | ||
| 488 | + } | ||
| 489 | + } | ||
| 490 | + return false; | ||
| 491 | + } | ||
| 492 | + | ||
| 493 | + return true; | ||
| 494 | + } | ||
| 495 | + | ||
| 496 | + function partiallyCompareArrays(actual, expected, comparedObjects) { | ||
| 497 | + if (expected.length > actual.length) { | ||
| 498 | + return false; | ||
| 499 | + } | ||
| 500 | + | ||
| 501 | + if (isDeepEqual === undefined) lazyLoadComparison(); | ||
| 502 | + | ||
| 503 | + // Create a map to count occurrences of each element in the expected array | ||
| 504 | + const expectedCounts = new SafeMap(); | ||
| 505 | + for (const expectedItem of expected) { | ||
| 506 | + let found = false; | ||
| 507 | + for (const { 0: key, 1: count } of expectedCounts) { | ||
| 508 | + if (isDeepStrictEqual(key, expectedItem)) { | ||
| 509 | + expectedCounts.set(key, count + 1); | ||
| 510 | + found = true; | ||
| 511 | + break; | ||
| 512 | + } | ||
| 513 | + } | ||
| 514 | + if (!found) { | ||
| 515 | + expectedCounts.set(expectedItem, 1); | ||
| 516 | + } | ||
| 517 | + } | ||
| 518 | + | ||
| 519 | + const safeActual = new SafeArrayIterator(actual); | ||
| 520 | + | ||
| 521 | + // Create a map to count occurrences of relevant elements in the actual array | ||
| 522 | + for (const actualItem of safeActual) { | ||
| 523 | + for (const { 0: key, 1: count } of expectedCounts) { | ||
| 524 | + if (isDeepStrictEqual(key, actualItem)) { | ||
| 525 | + if (count === 1) { | ||
| 526 | + expectedCounts.delete(key); | ||
| 527 | + } else { | ||
| 528 | + expectedCounts.set(key, count - 1); | ||
| 529 | + } | ||
| 530 | + break; | ||
| 531 | + } | ||
| 532 | + } | ||
| 533 | + } | ||
| 534 | + | ||
| 535 | + const { size } = expectedCounts; | ||
| 536 | + expectedCounts.clear(); | ||
| 537 | + return size === 0; | ||
| 538 | + } | ||
| 539 | + | ||
| 375 | 540 | /** | |
| 376 | 541 | * Compares two objects or values recursively to check if they are equal. | |
| 377 | 542 | * @param {any} actual - The actual value to compare. | |
@@ -388,22 +553,16 @@ function compareBranch( | |||
| 388 | 553 | ) { | |
| 389 | 554 | // Check for Map object equality | |
| 390 | 555 | if (isMap(actual) && isMap(expected)) { | |
| 391 | - if (actual.size !== expected.size) { | ||
| 392 | - return false; | ||
| 393 | - } | ||
| 394 | - const safeIterator = FunctionPrototypeCall(SafeMap.prototype[SymbolIterator], actual); | ||
| 395 | - | ||
| 396 | - comparedObjects ??= new SafeWeakSet(); | ||
| 556 | + return compareMaps(actual, expected, comparedObjects); | ||
| 557 | + } | ||
| 397 | 558 | ||
| 398 | - for (const { 0: key, 1: val } of safeIterator) { | ||
| 399 | - if (!MapPrototypeHas(expected, key)) { | ||
| 400 | - return false; | ||
| 401 | - } | ||
| 402 | - if (!compareBranch(val, MapPrototypeGet(expected, key), comparedObjects)) { | ||
| 403 | - return false; | ||
| 404 | - } | ||
| 405 | - } | ||
| 406 | - return true; | ||
| 559 | + if ( | ||
| 560 | + ArrayBufferIsView(actual) || | ||
| 561 | + isAnyArrayBuffer(actual) || | ||
| 562 | + ArrayBufferIsView(expected) || | ||
| 563 | + isAnyArrayBuffer(expected) | ||
| 564 | + ) { | ||
| 565 | + return partiallyCompareArrayBuffersOrViews(actual, expected); | ||
| 407 | 566 | } | |
| 408 | 567 | ||
| 409 | 568 | for (const type of typesToCallDeepStrictEqualWith) { | |
@@ -415,68 +574,12 @@ function compareBranch( | |||
| 415 | 574 | ||
| 416 | 575 | // Check for Set object equality | |
| 417 | 576 | if (isSet(actual) && isSet(expected)) { | |
| 418 | - if (expected.size > actual.size) { | ||
| 419 | - return false; // `expected` can't be a subset if it has more elements | ||
| 420 | - } | ||
| 421 | - | ||
| 422 | - if (isDeepEqual === undefined) lazyLoadComparison(); | ||
| 423 | - | ||
| 424 | - const actualArray = ArrayFrom(FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], actual)); | ||
| 425 | - const expectedIterator = FunctionPrototypeCall(SafeSet.prototype[SymbolIterator], expected); | ||
| 426 | - const usedIndices = new SafeSet(); | ||
| 427 | - | ||
| 428 | - expectedIteration: for (const expectedItem of expectedIterator) { | ||
| 429 | - for (let actualIdx = 0; actualIdx < actualArray.length; actualIdx++) { | ||
| 430 | - if (!usedIndices.has(actualIdx) && isDeepStrictEqual(actualArray[actualIdx], expectedItem)) { | ||
| 431 | - usedIndices.add(actualIdx); | ||
| 432 | - continue expectedIteration; | ||
| 433 | - } | ||
| 434 | - } | ||
| 435 | - return false; | ||
| 436 | - } | ||
| 437 | - | ||
| 438 | - return true; | ||
| 577 | + return partiallyCompareSets(actual, expected, comparedObjects); | ||
| 439 | 578 | } | |
| 440 | 579 | ||
| 441 | 580 | // Check if expected array is a subset of actual array | |
| 442 | 581 | if (ArrayIsArray(actual) && ArrayIsArray(expected)) { | |
| 443 | - if (expected.length > actual.length) { | ||
| 444 | - return false; | ||
| 445 | - } | ||
| 446 | - | ||
| 447 | - if (isDeepEqual === undefined) lazyLoadComparison(); | ||
| 448 | - | ||
| 449 | - // Create a map to count occurrences of each element in the expected array | ||
| 450 | - const expectedCounts = new SafeMap(); | ||
| 451 | - for (const expectedItem of expected) { | ||
| 452 | - let found = false; | ||
| 453 | - for (const { 0: key, 1: count } of expectedCounts) { | ||
| 454 | - if (isDeepStrictEqual(key, expectedItem)) { | ||
| 455 | - MapPrototypeSet(expectedCounts, key, count + 1); | ||
| 456 | - found = true; | ||
| 457 | - break; | ||
| 458 | - } | ||
| 459 | - } | ||
| 460 | - if (!found) { | ||
| 461 | - MapPrototypeSet(expectedCounts, expectedItem, 1); | ||
| 462 | - } | ||
| 463 | - } | ||
| 464 | - | ||
| 465 | - // Create a map to count occurrences of relevant elements in the actual array | ||
| 466 | - for (const actualItem of actual) { | ||
| 467 | - for (const { 0: key, 1: count } of expectedCounts) { | ||
| 468 | - if (isDeepStrictEqual(key, actualItem)) { | ||
| 469 | - if (count === 1) { | ||
| 470 | - MapPrototypeDelete(expectedCounts, key); | ||
| 471 | - } else { | ||
| 472 | - MapPrototypeSet(expectedCounts, key, count - 1); | ||
| 473 | - } | ||
| 474 | - break; | ||
| 475 | - } | ||
| 476 | - } | ||
| 477 | - } | ||
| 478 | - | ||
| 479 | - return !expectedCounts.size; | ||
| 582 | + return partiallyCompareArrays(actual, expected, comparedObjects); | ||
| 480 | 583 | } | |
| 481 | 584 | ||
| 482 | 585 | // Comparison done when at least one of the values is not an object | |
| Back | FazBrowse Home | New Git URL |
0 commit comments