Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/vs/base/common/equals.ts
13405 views
1
//!!! DO NOT modify, this file was COPIED from 'microsoft/vscode'
2
3
/*---------------------------------------------------------------------------------------------
4
* Copyright (c) Microsoft Corporation. All rights reserved.
5
* Licensed under the MIT License. See License.txt in the project root for license information.
6
*--------------------------------------------------------------------------------------------*/
7
8
import * as arrays from './arrays';
9
10
/*
11
* Each function in this file which offers an equality comparison, has an accompanying
12
* `*C` variant which returns an EqualityComparer function.
13
*
14
* The `*C` variant allows for easier composition of equality comparers and improved type-inference.
15
*/
16
17
18
/** Represents a function that decides if two values are equal. */
19
export type EqualityComparer<T> = (a: T, b: T) => boolean;
20
21
export interface IEquatable<T> {
22
equals(other: T): boolean;
23
}
24
25
/**
26
* Compares two items for equality using strict equality.
27
*/
28
export function strictEquals<T>(a: T, b: T): boolean {
29
return a === b;
30
}
31
32
export function strictEqualsC<T>(): EqualityComparer<T> {
33
return (a, b) => a === b;
34
}
35
36
/**
37
* Checks if the items of two arrays are equal.
38
* By default, strict equality is used to compare elements, but a custom equality comparer can be provided.
39
*/
40
export function arrayEquals<T>(a: readonly T[], b: readonly T[], itemEquals?: EqualityComparer<T>): boolean {
41
return arrays.equals(a, b, itemEquals ?? strictEquals);
42
}
43
44
/**
45
* Checks if the items of two arrays are equal.
46
* By default, strict equality is used to compare elements, but a custom equality comparer can be provided.
47
*/
48
export function arrayEqualsC<T>(itemEquals?: EqualityComparer<T>): EqualityComparer<readonly T[]> {
49
return (a, b) => arrays.equals(a, b, itemEquals ?? strictEquals);
50
}
51
52
/**
53
* Drills into arrays (items ordered) and objects (keys unordered) and uses strict equality on everything else.
54
*/
55
export function structuralEquals<T>(a: T, b: T): boolean {
56
if (a === b) {
57
return true;
58
}
59
60
if (Array.isArray(a) && Array.isArray(b)) {
61
if (a.length !== b.length) {
62
return false;
63
}
64
for (let i = 0; i < a.length; i++) {
65
if (!structuralEquals(a[i], b[i])) {
66
return false;
67
}
68
}
69
return true;
70
}
71
72
if (a && typeof a === 'object' && b && typeof b === 'object') {
73
if (Object.getPrototypeOf(a) === Object.prototype && Object.getPrototypeOf(b) === Object.prototype) {
74
const aObj = a as Record<string, unknown>;
75
const bObj = b as Record<string, unknown>;
76
const keysA = Object.keys(aObj);
77
const keysB = Object.keys(bObj);
78
const keysBSet = new Set(keysB);
79
80
if (keysA.length !== keysB.length) {
81
return false;
82
}
83
84
for (const key of keysA) {
85
if (!keysBSet.has(key)) {
86
return false;
87
}
88
if (!structuralEquals(aObj[key], bObj[key])) {
89
return false;
90
}
91
}
92
93
return true;
94
}
95
}
96
97
return false;
98
}
99
100
export function structuralEqualsC<T>(): EqualityComparer<T> {
101
return (a, b) => structuralEquals(a, b);
102
}
103
104
/**
105
* `getStructuralKey(a) === getStructuralKey(b) <=> structuralEquals(a, b)`
106
* (assuming that a and b are not cyclic structures and nothing extends globalThis Array).
107
*/
108
export function getStructuralKey(t: unknown): string {
109
return JSON.stringify(toNormalizedJsonStructure(t));
110
}
111
112
let objectId = 0;
113
const objIds = new WeakMap<object, number>();
114
115
function toNormalizedJsonStructure(t: unknown): unknown {
116
if (Array.isArray(t)) {
117
return t.map(toNormalizedJsonStructure);
118
}
119
120
if (t && typeof t === 'object') {
121
if (Object.getPrototypeOf(t) === Object.prototype) {
122
const tObj = t as Record<string, unknown>;
123
const res: Record<string, unknown> = Object.create(null);
124
for (const key of Object.keys(tObj).sort()) {
125
res[key] = toNormalizedJsonStructure(tObj[key]);
126
}
127
return res;
128
} else {
129
let objId = objIds.get(t);
130
if (objId === undefined) {
131
objId = objectId++;
132
objIds.set(t, objId);
133
}
134
// Random string to prevent collisions
135
return objId + '----2b76a038c20c4bcc';
136
}
137
}
138
return t;
139
}
140
141
142
/**
143
* Two items are considered equal, if their stringified representations are equal.
144
*/
145
export function jsonStringifyEquals<T>(a: T, b: T): boolean {
146
return JSON.stringify(a) === JSON.stringify(b);
147
}
148
149
/**
150
* Two items are considered equal, if their stringified representations are equal.
151
*/
152
export function jsonStringifyEqualsC<T>(): EqualityComparer<T> {
153
return (a, b) => JSON.stringify(a) === JSON.stringify(b);
154
}
155
156
/**
157
* Uses `item.equals(other)` to determine equality.
158
*/
159
export function thisEqualsC<T extends IEquatable<T>>(): EqualityComparer<T> {
160
return (a, b) => a.equals(b);
161
}
162
163
/**
164
* Checks if two items are both null or undefined, or are equal according to the provided equality comparer.
165
*/
166
export function equalsIfDefined<T>(v1: T | undefined | null, v2: T | undefined | null, equals: EqualityComparer<T>): boolean {
167
if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {
168
return v2 === v1;
169
}
170
return equals(v1, v2);
171
}
172
173
/**
174
* Returns an equality comparer that checks if two items are both null or undefined, or are equal according to the provided equality comparer.
175
*/
176
export function equalsIfDefinedC<T>(equals: EqualityComparer<T>): EqualityComparer<T | undefined | null> {
177
return (v1, v2) => {
178
if (v1 === undefined || v1 === null || v2 === undefined || v2 === null) {
179
return v2 === v1;
180
}
181
return equals(v1, v2);
182
};
183
}
184
185
/**
186
* Each function in this file which offers an equality comparison, has an accompanying
187
* `*C` variant which returns an EqualityComparer function.
188
*
189
* The `*C` variant allows for easier composition of equality comparers and improved type-inference.
190
*/
191
export namespace equals {
192
export const strict = strictEquals;
193
export const strictC = strictEqualsC;
194
195
export const array = arrayEquals;
196
export const arrayC = arrayEqualsC;
197
198
export const structural = structuralEquals;
199
export const structuralC = structuralEqualsC;
200
201
export const jsonStringify = jsonStringifyEquals;
202
export const jsonStringifyC = jsonStringifyEqualsC;
203
204
export const thisC = thisEqualsC;
205
206
export const ifDefined = equalsIfDefined;
207
export const ifDefinedC = equalsIfDefinedC;
208
}
209
210