Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/extensions/copilot/src/util/vs/base/common/objects.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 { isTypedArray, isObject, isUndefinedOrNull } from './types';
9
10
export function deepClone<T>(obj: T): T {
11
if (!obj || typeof obj !== 'object') {
12
return obj;
13
}
14
if (obj instanceof RegExp) {
15
return obj;
16
}
17
const result: any = Array.isArray(obj) ? [] : {};
18
Object.entries(obj).forEach(([key, value]) => {
19
result[key] = value && typeof value === 'object' ? deepClone(value) : value;
20
});
21
return result;
22
}
23
24
export function deepFreeze<T>(obj: T): T {
25
if (!obj || typeof obj !== 'object') {
26
return obj;
27
}
28
const stack: any[] = [obj];
29
while (stack.length > 0) {
30
const obj = stack.shift();
31
Object.freeze(obj);
32
for (const key in obj) {
33
if (_hasOwnProperty.call(obj, key)) {
34
const prop = obj[key];
35
if (typeof prop === 'object' && !Object.isFrozen(prop) && !isTypedArray(prop)) {
36
stack.push(prop);
37
}
38
}
39
}
40
}
41
return obj;
42
}
43
44
const _hasOwnProperty = Object.prototype.hasOwnProperty;
45
46
47
export function cloneAndChange(obj: any, changer: (orig: any) => any): any {
48
return _cloneAndChange(obj, changer, new Set());
49
}
50
51
function _cloneAndChange(obj: any, changer: (orig: any) => any, seen: Set<any>): any {
52
if (isUndefinedOrNull(obj)) {
53
return obj;
54
}
55
56
const changed = changer(obj);
57
if (typeof changed !== 'undefined') {
58
return changed;
59
}
60
61
if (Array.isArray(obj)) {
62
const r1: any[] = [];
63
for (const e of obj) {
64
r1.push(_cloneAndChange(e, changer, seen));
65
}
66
return r1;
67
}
68
69
if (isObject(obj)) {
70
if (seen.has(obj)) {
71
throw new Error('Cannot clone recursive data-structure');
72
}
73
seen.add(obj);
74
const r2: Record<string, unknown> = {};
75
for (const i2 in obj) {
76
if (_hasOwnProperty.call(obj, i2)) {
77
r2[i2] = _cloneAndChange(obj[i2], changer, seen);
78
}
79
}
80
seen.delete(obj);
81
return r2;
82
}
83
84
return obj;
85
}
86
87
/**
88
* Copies all properties of source into destination. The optional parameter "overwrite" allows to control
89
* if existing properties on the destination should be overwritten or not. Defaults to true (overwrite).
90
*/
91
export function mixin(destination: any, source: any, overwrite: boolean = true): any {
92
if (!isObject(destination)) {
93
return source;
94
}
95
96
if (isObject(source)) {
97
Object.keys(source).forEach(key => {
98
if (key in destination) {
99
if (overwrite) {
100
if (isObject(destination[key]) && isObject(source[key])) {
101
mixin(destination[key], source[key], overwrite);
102
} else {
103
destination[key] = source[key];
104
}
105
}
106
} else {
107
destination[key] = source[key];
108
}
109
});
110
}
111
return destination;
112
}
113
114
export function equals(one: any, other: any): boolean {
115
if (one === other) {
116
return true;
117
}
118
if (one === null || one === undefined || other === null || other === undefined) {
119
return false;
120
}
121
if (typeof one !== typeof other) {
122
return false;
123
}
124
if (typeof one !== 'object') {
125
return false;
126
}
127
if ((Array.isArray(one)) !== (Array.isArray(other))) {
128
return false;
129
}
130
131
let i: number;
132
let key: string;
133
134
if (Array.isArray(one)) {
135
if (one.length !== other.length) {
136
return false;
137
}
138
for (i = 0; i < one.length; i++) {
139
if (!equals(one[i], other[i])) {
140
return false;
141
}
142
}
143
} else {
144
const oneKeys: string[] = [];
145
146
for (key in one) {
147
oneKeys.push(key);
148
}
149
oneKeys.sort();
150
const otherKeys: string[] = [];
151
for (key in other) {
152
otherKeys.push(key);
153
}
154
otherKeys.sort();
155
if (!equals(oneKeys, otherKeys)) {
156
return false;
157
}
158
for (i = 0; i < oneKeys.length; i++) {
159
if (!equals(one[oneKeys[i]], other[oneKeys[i]])) {
160
return false;
161
}
162
}
163
}
164
return true;
165
}
166
167
/**
168
* Calls `JSON.Stringify` with a replacer to break apart any circular references.
169
* This prevents `JSON`.stringify` from throwing the exception
170
* "Uncaught TypeError: Converting circular structure to JSON"
171
*/
172
export function safeStringify(obj: any): string {
173
const seen = new Set<any>();
174
return JSON.stringify(obj, (key, value) => {
175
if (isObject(value) || Array.isArray(value)) {
176
if (seen.has(value)) {
177
return '[Circular]';
178
} else {
179
seen.add(value);
180
}
181
}
182
if (typeof value === 'bigint') {
183
return `[BigInt ${value.toString()}]`;
184
}
185
return value;
186
});
187
}
188
189
type obj = { [key: string]: any };
190
/**
191
* Returns an object that has keys for each value that is different in the base object. Keys
192
* that do not exist in the target but in the base object are not considered.
193
*
194
* Note: This is not a deep-diffing method, so the values are strictly taken into the resulting
195
* object if they differ.
196
*
197
* @param base the object to diff against
198
* @param obj the object to use for diffing
199
*/
200
export function distinct(base: obj, target: obj): obj {
201
const result = Object.create(null);
202
203
if (!base || !target) {
204
return result;
205
}
206
207
const targetKeys = Object.keys(target);
208
targetKeys.forEach(k => {
209
const baseValue = base[k];
210
const targetValue = target[k];
211
212
if (!equals(baseValue, targetValue)) {
213
result[k] = targetValue;
214
}
215
});
216
217
return result;
218
}
219
220
export function getCaseInsensitive(target: obj, key: string): unknown {
221
const lowercaseKey = key.toLowerCase();
222
const equivalentKey = Object.keys(target).find(k => k.toLowerCase() === lowercaseKey);
223
return equivalentKey ? target[equivalentKey] : target[key];
224
}
225
226
export function filter(obj: obj, predicate: (key: string, value: any) => boolean): obj {
227
const result = Object.create(null);
228
for (const [key, value] of Object.entries(obj)) {
229
if (predicate(key, value)) {
230
result[key] = value;
231
}
232
}
233
return result;
234
}
235
236
export function mapValues<T extends {}, R>(obj: T, fn: (value: T[keyof T], key: string) => R): { [K in keyof T]: R } {
237
const result: { [key: string]: R } = {};
238
for (const [key, value] of Object.entries(obj)) {
239
result[key] = fn(<T[keyof T]>value, key);
240
}
241
return result as { [K in keyof T]: R };
242
}
243
244