Path: blob/main/extensions/copilot/src/util/vs/base/common/equals.ts
13405 views
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'12/*---------------------------------------------------------------------------------------------3* Copyright (c) Microsoft Corporation. All rights reserved.4* Licensed under the MIT License. See License.txt in the project root for license information.5*--------------------------------------------------------------------------------------------*/67import * as arrays from './arrays';89/*10* Each function in this file which offers an equality comparison, has an accompanying11* `*C` variant which returns an EqualityComparer function.12*13* The `*C` variant allows for easier composition of equality comparers and improved type-inference.14*/151617/** Represents a function that decides if two values are equal. */18export type EqualityComparer<T> = (a: T, b: T) => boolean;1920export interface IEquatable<T> {21equals(other: T): boolean;22}2324/**25* Compares two items for equality using strict equality.26*/27export function strictEquals<T>(a: T, b: T): boolean {28return a === b;29}3031export function strictEqualsC<T>(): EqualityComparer<T> {32return (a, b) => a === b;33}3435/**36* Checks if the items of two arrays are equal.37* By default, strict equality is used to compare elements, but a custom equality comparer can be provided.38*/39export function arrayEquals<T>(a: readonly T[], b: readonly T[], itemEquals?: EqualityComparer<T>): boolean {40return arrays.equals(a, b, itemEquals ?? strictEquals);41}4243/**44* Checks if the items of two arrays are equal.45* By default, strict equality is used to compare elements, but a custom equality comparer can be provided.46*/47export function arrayEqualsC<T>(itemEquals?: EqualityComparer<T>): EqualityComparer<readonly T[]> {48return (a, b) => arrays.equals(a, b, itemEquals ?? strictEquals);49}5051/**52* Drills into arrays (items ordered) and objects (keys unordered) and uses strict equality on everything else.53*/54export function structuralEquals<T>(a: T, b: T): boolean {55if (a === b) {56return true;57}5859if (Array.isArray(a) && Array.isArray(b)) {60if (a.length !== b.length) {61return false;62}63for (let i = 0; i < a.length; i++) {64if (!structuralEquals(a[i], b[i])) {65return false;66}67}68return true;69}7071if (a && typeof a === 'object' && b && typeof b === 'object') {72if (Object.getPrototypeOf(a) === Object.prototype && Object.getPrototypeOf(b) === Object.prototype) {73const aObj = a as Record<string, unknown>;74const bObj = b as Record<string, unknown>;75const keysA = Object.keys(aObj);76const keysB = Object.keys(bObj);77const keysBSet = new Set(keysB);7879if (keysA.length !== keysB.length) {80return false;81}8283for (const key of keysA) {84if (!keysBSet.has(key)) {85return false;86}87if (!structuralEquals(aObj[key], bObj[key])) {88return false;89}90}9192return true;93}94}9596return false;97}9899export function structuralEqualsC<T>(): EqualityComparer<T> {100return (a, b) => structuralEquals(a, b);101}102103/**104* `getStructuralKey(a) === getStructuralKey(b) <=> structuralEquals(a, b)`105* (assuming that a and b are not cyclic structures and nothing extends globalThis Array).106*/107export function getStructuralKey(t: unknown): string {108return JSON.stringify(toNormalizedJsonStructure(t));109}110111let objectId = 0;112const objIds = new WeakMap<object, number>();113114function toNormalizedJsonStructure(t: unknown): unknown {115if (Array.isArray(t)) {116return t.map(toNormalizedJsonStructure);117}118119if (t && typeof t === 'object') {120if (Object.getPrototypeOf(t) === Object.prototype) {121const tObj = t as Record<string, unknown>;122const res: Record<string, unknown> = Object.create(null);123for (const key of Object.keys(tObj).sort()) {124res[key] = toNormalizedJsonStructure(tObj[key]);125}126return res;127} else {128let objId = objIds.get(t);129if (objId === undefined) {130objId = objectId++;131objIds.set(t, objId);132}133// Random string to prevent collisions134return objId + '----2b76a038c20c4bcc';135}136}137return t;138}139140141/**142* Two items are considered equal, if their stringified representations are equal.143*/144export function jsonStringifyEquals<T>(a: T, b: T): boolean {145return JSON.stringify(a) === JSON.stringify(b);146}147148/**149* Two items are considered equal, if their stringified representations are equal.150*/151export function jsonStringifyEqualsC<T>(): EqualityComparer<T> {152return (a, b) => JSON.stringify(a) === JSON.stringify(b);153}154155/**156* Uses `item.equals(other)` to determine equality.157*/158export function thisEqualsC<T extends IEquatable<T>>(): EqualityComparer<T> {159return (a, b) => a.equals(b);160}161162/**163* Checks if two items are both null or undefined, or are equal according to the provided equality comparer.164*/165export function equalsIfDefined<T>(v1: T | undefined | null, v2: T | undefined | null, equals: EqualityComparer<T>): boolean {166if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {167return v2 === v1;168}169return equals(v1, v2);170}171172/**173* Returns an equality comparer that checks if two items are both null or undefined, or are equal according to the provided equality comparer.174*/175export function equalsIfDefinedC<T>(equals: EqualityComparer<T>): EqualityComparer<T | undefined | null> {176return (v1, v2) => {177if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {178return v2 === v1;179}180return equals(v1, v2);181};182}183184/**185* Each function in this file which offers an equality comparison, has an accompanying186* `*C` variant which returns an EqualityComparer function.187*188* The `*C` variant allows for easier composition of equality comparers and improved type-inference.189*/190export namespace equals {191export const strict = strictEquals;192export const strictC = strictEqualsC;193194export const array = arrayEquals;195export const arrayC = arrayEqualsC;196197export const structural = structuralEquals;198export const structuralC = structuralEqualsC;199200export const jsonStringify = jsonStringifyEquals;201export const jsonStringifyC = jsonStringifyEqualsC;202203export const thisC = thisEqualsC;204205export const ifDefined = equalsIfDefined;206export const ifDefinedC = equalsIfDefinedC;207}208209210