UNPKG

11 kBJavaScriptView Raw
1/* eslint-disable no-proto */
2/* global Deno */
3
4const canSetPrototype =
5 Object.setPrototypeOf || { __proto__: [] } instanceof Array;
6const greedyIntervalPacker = require('greedy-interval-packer');
7
8const setPrototypeOf =
9 Object.setPrototypeOf ||
10 function setPrototypeOf(obj, proto) {
11 obj.__proto__ = proto;
12 return obj;
13 };
14/* eslint-enable no-proto */
15
16const utils = (module.exports = {
17 objectIs:
18 Object.is ||
19 ((a, b) => {
20 // Polyfill from https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is
21 if (a === 0 && b === 0) {
22 return 1 / a === 1 / b;
23 }
24 // eslint-disable-next-line no-self-compare
25 if (a !== a) {
26 // eslint-disable-next-line no-self-compare
27 return b !== b;
28 }
29 return a === b;
30 }),
31
32 checkObjectEqualityUsingType(a, b, type, isEqual) {
33 if (a === b) {
34 return true;
35 }
36
37 if (b.constructor !== a.constructor) {
38 return false;
39 }
40
41 const actualKeys = type
42 .getKeys(a)
43 .filter(key => typeof type.valueForKey(a, key) !== 'undefined');
44 const expectedKeys = type
45 .getKeys(b)
46 .filter(key => typeof type.valueForKey(b, key) !== 'undefined');
47
48 // having the same number of owned properties (keys incorporates hasOwnProperty)
49 if (actualKeys.length !== expectedKeys.length) {
50 return false;
51 }
52
53 // the same set of keys (although not necessarily the same order),
54 actualKeys.sort(type.keyComparator);
55 expectedKeys.sort(type.keyComparator);
56 // cheap key test
57 for (let i = 0; i < actualKeys.length; i += 1) {
58 if (actualKeys[i] !== expectedKeys[i]) {
59 return false;
60 }
61 }
62
63 // equivalent values for every corresponding key, and
64 // possibly expensive deep test
65 for (let j = 0; j < actualKeys.length; j += 1) {
66 const key = actualKeys[j];
67 if (!isEqual(type.valueForKey(a, key), type.valueForKey(b, key))) {
68 return false;
69 }
70 }
71 return true;
72 },
73
74 duplicateArrayLikeUsingType(obj, type) {
75 const keys = type.getKeys(obj);
76
77 let numericalKeyLength = keys.length;
78 if (!type.numericalPropertiesOnly) {
79 let nonNumericalKeyLength = 0;
80 // find non-numerical keys in reverse order to keep iteration minimal
81 for (let i = keys.length - 1; i > -1; i -= 1) {
82 const key = keys[i];
83 if (typeof key === 'symbol' || !utils.numericalRegExp.test(key)) {
84 nonNumericalKeyLength += 1;
85 } else {
86 break;
87 }
88 }
89 // remove non-numerical keys to ensure the copy is sized correctly
90 numericalKeyLength -= nonNumericalKeyLength;
91 }
92
93 const arr = new Array(numericalKeyLength);
94
95 keys.forEach(function(key, index) {
96 const isNonNumericKey = index >= numericalKeyLength;
97 if (isNonNumericKey && !type.hasKey(obj, key)) {
98 // do not add non-numerical keys that are not actually attached
99 // to the array-like to ensure they will be treated as "missing"
100 return;
101 }
102 arr[key] = type.hasKey(obj, key) ? type.valueForKey(obj, key) : undefined;
103 });
104
105 return arr;
106 },
107
108 isArray:
109 Array.isArray ||
110 function(obj) {
111 return Object.prototype.toString.call(obj) === '[object Array]';
112 },
113
114 isPromise(obj) {
115 return obj && typeof obj.then === 'function';
116 },
117
118 isRegExp(re) {
119 return Object.prototype.toString.call(re) === '[object RegExp]';
120 },
121
122 isError(err) {
123 return (
124 typeof err === 'object' &&
125 (Object.prototype.toString.call(err) === '[object Error]' ||
126 err instanceof Error)
127 );
128 },
129
130 extend(target) {
131 for (let i = 1; i < arguments.length; i += 1) {
132 const source = arguments[i];
133 if (source) {
134 Object.keys(source).forEach(key => {
135 target[key] = source[key];
136 });
137 }
138 }
139 return target;
140 },
141
142 findFirst(arr, predicate) {
143 for (let i = 0; i < arr.length; i += 1) {
144 if (predicate(arr[i])) {
145 return arr[i];
146 }
147 }
148 return null;
149 },
150
151 leftPad(str, width, ch = ' ') {
152 while (str.length < width) {
153 str = ch + str;
154 }
155 return str;
156 },
157
158 escapeRegExpMetaChars(str) {
159 return str.replace(/[[\]{}()*+?.\\^$|]/g, '\\$&');
160 },
161
162 escapeChar(ch) {
163 if (ch === '\t') {
164 return '\\t';
165 } else if (ch === '\r') {
166 return '\\r';
167 } else {
168 const charCode = ch.charCodeAt(0);
169 const hexChars = charCode.toString(16).toUpperCase();
170 if (charCode < 256) {
171 return `\\x${utils.leftPad(hexChars, 2, '0')}`;
172 } else {
173 return `\\u${utils.leftPad(hexChars, 4, '0')}`;
174 }
175 }
176 },
177
178 getFunctionName(f) {
179 if (typeof f.name === 'string') {
180 return f.name;
181 }
182 const matchFunctionName = Function.prototype.toString
183 .call(f)
184 .match(/function ([^(]+)/);
185 if (matchFunctionName) {
186 return matchFunctionName[1];
187 }
188
189 if (f === Object) {
190 return 'Object';
191 }
192 if (f === Function) {
193 return 'Function';
194 }
195 return '';
196 },
197
198 wrapConstructorNameAroundOutput(output, obj) {
199 const constructor = obj.constructor;
200 const constructorName =
201 constructor &&
202 constructor !== Object &&
203 utils.getFunctionName(constructor);
204 if (constructorName && constructorName !== 'Object') {
205 return output
206 .clone()
207 .text(`${constructorName}(`)
208 .append(output)
209 .text(')');
210 } else {
211 return output;
212 }
213 },
214
215 setPrototypeOfOrExtend: canSetPrototype
216 ? setPrototypeOf
217 : function extend(target, source) {
218 for (const prop in source) {
219 if (Object.prototype.hasOwnProperty.call(source, prop)) {
220 target[prop] = source[prop];
221 }
222 }
223 return target;
224 },
225
226 uniqueStringsAndSymbols(...args) {
227 // [filterFn], item1, item2...
228 let filterFn;
229 if (typeof args[0] === 'function') {
230 filterFn = args[0];
231 }
232 const index = {};
233 const uniqueStringsAndSymbols = [];
234
235 function visit(item) {
236 if (Array.isArray(item)) {
237 item.forEach(visit);
238 } else if (
239 !Object.prototype.hasOwnProperty.call(index, item) &&
240 (!filterFn || filterFn(item))
241 ) {
242 index[item] = true;
243 uniqueStringsAndSymbols.push(item);
244 }
245 }
246
247 for (let i = filterFn ? 1 : 0; i < args.length; i += 1) {
248 visit(args[i]);
249 }
250 return uniqueStringsAndSymbols;
251 },
252
253 uniqueNonNumericalStringsAndSymbols(...args) {
254 // ...
255 return utils.uniqueStringsAndSymbols(
256 stringOrSymbol =>
257 typeof stringOrSymbol === 'symbol' ||
258 !utils.numericalRegExp.test(stringOrSymbol),
259 Array.prototype.slice.call(args)
260 );
261 },
262
263 forwardFlags(testDescriptionString, flags) {
264 return testDescriptionString
265 .replace(/\[(!?)([^\]]+)\] ?/g, (match, negate, flag) =>
266 Boolean(flags[flag]) !== Boolean(negate) ? `${flag} ` : ''
267 )
268 .trim();
269 },
270
271 numericalRegExp: /^(?:0|[1-9][0-9]*)$/,
272
273 packArrows(changes) {
274 const moveSourceAndTargetByActualIndex = {};
275 changes.forEach((diffItem, index) => {
276 if (diffItem.type === 'moveSource') {
277 diffItem.changeIndex = index;
278 (moveSourceAndTargetByActualIndex[diffItem.actualIndex] =
279 moveSourceAndTargetByActualIndex[diffItem.actualIndex] ||
280 {}).source = diffItem;
281 } else if (diffItem.type === 'moveTarget') {
282 diffItem.changeIndex = index;
283 (moveSourceAndTargetByActualIndex[diffItem.actualIndex] =
284 moveSourceAndTargetByActualIndex[diffItem.actualIndex] ||
285 {}).target = diffItem;
286 }
287 });
288 const moveIndices = Object.keys(moveSourceAndTargetByActualIndex);
289 if (moveIndices.length > 0) {
290 const arrowSpecs = [];
291 moveIndices
292 .sort(
293 (
294 a,
295 b // Order by distance between change indices descending
296 ) =>
297 Math.abs(
298 moveSourceAndTargetByActualIndex[b].source.changeIndex -
299 moveSourceAndTargetByActualIndex[b].target.changeIndex
300 ) -
301 Math.abs(
302 moveSourceAndTargetByActualIndex[a].source.changeIndex -
303 moveSourceAndTargetByActualIndex[a].target.changeIndex
304 )
305 )
306 .forEach((actualIndex, i, keys) => {
307 const moveSourceAndMoveTarget =
308 moveSourceAndTargetByActualIndex[actualIndex];
309 const firstChangeIndex = Math.min(
310 moveSourceAndMoveTarget.source.changeIndex,
311 moveSourceAndMoveTarget.target.changeIndex
312 );
313 const lastChangeIndex = Math.max(
314 moveSourceAndMoveTarget.source.changeIndex,
315 moveSourceAndMoveTarget.target.changeIndex
316 );
317
318 arrowSpecs.push({
319 start: firstChangeIndex,
320 end: lastChangeIndex,
321 direction:
322 moveSourceAndMoveTarget.source.changeIndex <
323 moveSourceAndMoveTarget.target.changeIndex
324 ? 'down'
325 : 'up'
326 });
327 });
328
329 const packing = greedyIntervalPacker(arrowSpecs);
330 while (packing.length > 3) {
331 // The arrow packing takes up too many lanes. Turn the moveSource/moveTarget items into inserts and removes
332 packing.shift().forEach(({ direction, start, end }) => {
333 changes[direction === 'up' ? start : end].type = 'insert';
334 changes[direction === 'up' ? end : start].type = 'remove';
335 });
336 }
337 return packing;
338 }
339 },
340
341 truncateSubjectStringForBegin(subject, value) {
342 var contextLength = value.length + 25;
343 if (subject.length <= contextLength) {
344 return null;
345 }
346 var truncationIndex = subject.indexOf(' ', value.length + 1);
347 if (truncationIndex > -1 && truncationIndex < contextLength) {
348 return subject.substring(0, truncationIndex);
349 } else {
350 return subject.substring(0, contextLength);
351 }
352 },
353
354 truncateSubjectStringForEnd(subject, value) {
355 var contextLength = subject.length - value.length - 25;
356 if (contextLength <= 0) {
357 return null;
358 }
359 var truncationIndex = subject.lastIndexOf(' ', value.length + 1);
360 if (truncationIndex > -1 && truncationIndex >= contextLength) {
361 return subject.substring(truncationIndex + 1, subject.length);
362 } else {
363 return subject.substring(contextLength, subject.length);
364 }
365 },
366
367 getEnv(varName) {
368 if (typeof Deno === 'object') {
369 try {
370 return Deno.env()[varName];
371 } catch (err) {
372 // Probably a permissions error because we don't have permission to read the environment variables
373 // Unfortunately the whole permissions API is async now:
374 // https://github.com/denoland/deno/pull/3200/files
375 // ... so we can't detect whether we do have access
376 }
377 } else if (typeof process === 'object' && process.env) {
378 return process.env[varName];
379 }
380 }
381});