planning
All checks were successful
Publish To Prod / deploy_and_publish (push) Successful in 35s

This commit is contained in:
2024-10-14 09:15:30 +02:00
parent bcba00a730
commit 6e64e138e2
21059 changed files with 2317811 additions and 1 deletions

View File

@@ -0,0 +1,47 @@
import { assign } from '../assign';
describe('assign', () => {
it('will merge many objects together', () => {
expect(assign({ a: 1 }, { b: 2 })).toEqual({ a: 1, b: 2 });
expect(assign({ a: 1 }, { b: 2 }, { c: 3 })).toEqual({
a: 1,
b: 2,
c: 3,
});
expect(assign({ a: 1 }, { b: 2 }, { c: 3 }, { d: 4 })).toEqual({
a: 1,
b: 2,
c: 3,
d: 4,
});
});
it('will merge many objects together shallowly', () => {
expect(assign({ x: { a: 1 } }, { x: { b: 2 } })).toEqual({ x: { b: 2 } });
expect(assign({ x: { a: 1 } }, { x: { b: 2 } }, { x: { c: 3 } })).toEqual({
x: { c: 3 },
});
expect(
assign(
{ x: { a: 1 } },
{ x: { b: 2 } },
{ x: { c: 3 } },
{ x: { d: 4 } },
),
).toEqual({ x: { d: 4 } });
});
it('will mutate and return the source objects', () => {
const source1 = { a: 1 };
const source2 = { a: 1 };
const source3 = { a: 1 };
expect(assign(source1, { b: 2 })).toEqual(source1);
expect(assign(source2, { b: 2 }, { c: 3 })).toEqual(source2);
expect(assign(source3, { b: 2 }, { c: 3 }, { d: 4 })).toEqual(source3);
expect(source1).toEqual({ a: 1, b: 2 });
expect(source2).toEqual({ a: 1, b: 2, c: 3 });
expect(source3).toEqual({ a: 1, b: 2, c: 3, d: 4 });
});
});

View File

@@ -0,0 +1,70 @@
import { cloneDeep } from '../cloneDeep';
describe('cloneDeep', () => {
it('will clone primitive values', () => {
expect(cloneDeep(undefined)).toEqual(undefined);
expect(cloneDeep(null)).toEqual(null);
expect(cloneDeep(true)).toEqual(true);
expect(cloneDeep(false)).toEqual(false);
expect(cloneDeep(-1)).toEqual(-1);
expect(cloneDeep(+1)).toEqual(+1);
expect(cloneDeep(0.5)).toEqual(0.5);
expect(cloneDeep('hello')).toEqual('hello');
expect(cloneDeep('world')).toEqual('world');
});
it('will clone objects', () => {
const value1 = {};
const value2 = { a: 1, b: 2, c: 3 };
const value3 = { x: { a: 1, b: 2, c: 3 }, y: { a: 1, b: 2, c: 3 } };
const clonedValue1 = cloneDeep(value1);
const clonedValue2 = cloneDeep(value2);
const clonedValue3 = cloneDeep(value3);
expect(clonedValue1).toEqual(value1);
expect(clonedValue2).toEqual(value2);
expect(clonedValue3).toEqual(value3);
expect(clonedValue1).toEqual(value1);
expect(clonedValue2).toEqual(value2);
expect(clonedValue3).toEqual(value3);
expect(clonedValue3.x).toEqual(value3.x);
expect(clonedValue3.y).toEqual(value3.y);
});
it('will clone arrays', () => {
const value1: Array<number> = [];
const value2 = [1, 2, 3];
const value3 = [[1, 2, 3], [1, 2, 3]];
const clonedValue1 = cloneDeep(value1);
const clonedValue2 = cloneDeep(value2);
const clonedValue3 = cloneDeep(value3);
expect(clonedValue1).toEqual(value1);
expect(clonedValue2).toEqual(value2);
expect(clonedValue3).toEqual(value3);
expect(clonedValue1).toEqual(value1);
expect(clonedValue2).toEqual(value2);
expect(clonedValue3).toEqual(value3);
expect(clonedValue3[0]).toEqual(value3[0]);
expect(clonedValue3[1]).toEqual(value3[1]);
});
it('should not attempt to follow circular references', () => {
const someObject = {
prop1: 'value1',
anotherObject: null,
};
const anotherObject = {
someObject,
};
someObject.anotherObject = anotherObject;
let chk;
expect(() => {
chk = cloneDeep(someObject);
}).not.toThrow();
});
});

View File

@@ -0,0 +1,70 @@
import { isEnv, isProduction, isDevelopment, isTest } from '../environment';
describe('environment', () => {
let keepEnv: string | undefined;
beforeEach(() => {
// save the NODE_ENV
keepEnv = process.env.NODE_ENV;
});
afterEach(() => {
// restore the NODE_ENV
process.env.NODE_ENV = keepEnv;
});
describe('isEnv', () => {
it(`should match when there's a value`, () => {
['production', 'development', 'test'].forEach(env => {
process.env.NODE_ENV = env;
expect(isEnv(env)).toBe(true);
});
});
it(`should treat no proces.env.NODE_ENV as it'd be in development`, () => {
delete process.env.NODE_ENV;
expect(isEnv('development')).toBe(true);
});
});
describe('isProduction', () => {
it('should return true if in production', () => {
process.env.NODE_ENV = 'production';
expect(isProduction()).toBe(true);
});
it('should return false if not in production', () => {
process.env.NODE_ENV = 'test';
expect(!isProduction()).toBe(true);
});
});
describe('isTest', () => {
it('should return true if in test', () => {
process.env.NODE_ENV = 'test';
expect(isTest()).toBe(true);
});
it('should return true if not in test', () => {
process.env.NODE_ENV = 'development';
expect(!isTest()).toBe(true);
});
});
describe('isDevelopment', () => {
it('should return true if in development', () => {
process.env.NODE_ENV = 'development';
expect(isDevelopment()).toBe(true);
});
it('should return true if not in development and environment is defined', () => {
process.env.NODE_ENV = 'test';
expect(!isDevelopment()).toBe(true);
});
it('should make development as the default environment', () => {
delete process.env.NODE_ENV;
expect(isDevelopment()).toBe(true);
});
});
});

View File

@@ -0,0 +1,174 @@
import { isEqual } from '../isEqual';
describe('isEqual', () => {
it('should return true for equal primitive values', () => {
expect(isEqual(undefined, undefined)).toBe(true);
expect(isEqual(null, null)).toBe(true);
expect(isEqual(true, true)).toBe(true);
expect(isEqual(false, false)).toBe(true);
expect(isEqual(-1, -1)).toBe(true);
expect(isEqual(+1, +1)).toBe(true);
expect(isEqual(42, 42)).toBe(true);
expect(isEqual(0, 0)).toBe(true);
expect(isEqual(0.5, 0.5)).toBe(true);
expect(isEqual('hello', 'hello')).toBe(true);
expect(isEqual('world', 'world')).toBe(true);
});
it('should return false for not equal primitive values', () => {
expect(!isEqual(undefined, null)).toBe(true);
expect(!isEqual(null, undefined)).toBe(true);
expect(!isEqual(true, false)).toBe(true);
expect(!isEqual(false, true)).toBe(true);
expect(!isEqual(-1, +1)).toBe(true);
expect(!isEqual(+1, -1)).toBe(true);
expect(!isEqual(42, 42.00000000000001)).toBe(true);
expect(!isEqual(0, 0.5)).toBe(true);
expect(!isEqual('hello', 'world')).toBe(true);
expect(!isEqual('world', 'hello')).toBe(true);
});
it('should return false when comparing primitives with objects', () => {
expect(!isEqual({}, null)).toBe(true);
expect(!isEqual(null, {})).toBe(true);
expect(!isEqual({}, true)).toBe(true);
expect(!isEqual(true, {})).toBe(true);
expect(!isEqual({}, 42)).toBe(true);
expect(!isEqual(42, {})).toBe(true);
expect(!isEqual({}, 'hello')).toBe(true);
expect(!isEqual('hello', {})).toBe(true);
});
it('should correctly compare shallow objects', () => {
expect(isEqual({}, {})).toBe(true);
expect(isEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2, c: 3 })).toBe(true);
expect(!isEqual({ a: 1, b: 2, c: 3 }, { a: 3, b: 2, c: 1 })).toBe(true);
expect(!isEqual({ a: 1, b: 2, c: 3 }, { a: 1, b: 2 })).toBe(true);
expect(!isEqual({ a: 1, b: 2 }, { a: 1, b: 2, c: 3 })).toBe(true);
});
it('should correctly compare deep objects', () => {
expect(isEqual({ x: {} }, { x: {} })).toBe(true);
expect(
isEqual({ x: { a: 1, b: 2, c: 3 } }, { x: { a: 1, b: 2, c: 3 } }),
).toBe(true);
expect(
!isEqual({ x: { a: 1, b: 2, c: 3 } }, { x: { a: 3, b: 2, c: 1 } }),
).toBe(true);
expect(!isEqual({ x: { a: 1, b: 2, c: 3 } }, { x: { a: 1, b: 2 } })).toBe(
true,
);
expect(!isEqual({ x: { a: 1, b: 2 } }, { x: { a: 1, b: 2, c: 3 } })).toBe(
true,
);
});
it('should correctly compare deep objects without object prototype ', () => {
// Solves https://github.com/apollographql/apollo-client/issues/2132
const objNoProto = Object.create(null);
objNoProto.a = { b: 2, c: [3, 4] };
objNoProto.e = Object.create(null);
objNoProto.e.f = 5;
expect(isEqual(objNoProto, { a: { b: 2, c: [3, 4] }, e: { f: 5 } })).toBe(
true,
);
expect(!isEqual(objNoProto, { a: { b: 2, c: [3, 4] }, e: { f: 6 } })).toBe(
true,
);
expect(!isEqual(objNoProto, { a: { b: 2, c: [3, 4] }, e: null })).toBe(
true,
);
expect(!isEqual(objNoProto, { a: { b: 2, c: [3] }, e: { f: 5 } })).toBe(
true,
);
expect(!isEqual(objNoProto, null)).toBe(true);
});
it('should correctly handle modified prototypes', () => {
Array.prototype.foo = null;
expect(isEqual([1, 2, 3], [1, 2, 3])).toBe(true);
expect(!isEqual([1, 2, 3], [1, 2, 4])).toBe(true);
delete Array.prototype.foo;
});
describe('comparing objects with circular refs', () => {
// copied with slight modification from lodash test suite
it('should compare objects with circular references', () => {
const object1 = {},
object2 = {};
object1.a = object1;
object2.a = object2;
expect(isEqual(object1, object2)).toBe(true);
object1.b = 0;
object2.b = Object(0);
expect(isEqual(object1, object2)).toBe(true);
object1.c = Object(1);
object2.c = Object(2);
expect(isEqual(object1, object2)).toBe(false);
object1 = { a: 1, b: 2, c: 3 };
object1.b = object1;
object2 = { a: 1, b: { a: 1, b: 2, c: 3 }, c: 3 };
expect(isEqual(object1, object2)).toBe(false);
});
it('should have transitive equivalence for circular references of objects', () => {
const object1 = {},
object2 = { a: object1 },
object3 = { a: object2 };
object1.a = object1;
expect(isEqual(object1, object2)).toBe(true);
expect(isEqual(object2, object3)).toBe(true);
expect(isEqual(object1, object3)).toBe(true);
});
it('should compare objects with multiple circular references', () => {
const array1 = [{}],
array2 = [{}];
(array1[0].a = array1).push(array1);
(array2[0].a = array2).push(array2);
expect(isEqual(array1, array2)).toBe(true);
array1[0].b = 0;
array2[0].b = Object(0);
expect(isEqual(array1, array2)).toBe(true);
array1[0].c = Object(1);
array2[0].c = Object(2);
expect(isEqual(array1, array2)).toBe(false);
});
it('should compare objects with complex circular references', () => {
const object1 = {
foo: { b: { c: { d: {} } } },
bar: { a: 2 },
};
const object2 = {
foo: { b: { c: { d: {} } } },
bar: { a: 2 },
};
object1.foo.b.c.d = object1;
object1.bar.b = object1.foo.b;
object2.foo.b.c.d = object2;
object2.bar.b = object2.foo.b;
expect(isEqual(object1, object2)).toBe(true);
});
});
});

View File

@@ -0,0 +1,17 @@
import { maybeDeepFreeze } from '../maybeDeepFreeze';
describe('maybeDeepFreeze', () => {
it('should deep freeze', () => {
const foo: any = { bar: undefined };
maybeDeepFreeze(foo);
expect(() => (foo.bar = 1)).toThrow();
expect(foo.bar).toBeUndefined();
});
it('should properly freeze objects without hasOwnProperty', () => {
const foo = Object.create(null);
foo.bar = undefined;
maybeDeepFreeze(foo);
expect(() => (foo.bar = 1)).toThrow();
});
});

View File

@@ -0,0 +1,139 @@
import { mergeDeep, mergeDeepArray } from '../mergeDeep';
describe('mergeDeep', function() {
it('should return an object if first argument falsy', function() {
expect(mergeDeep()).toEqual({});
expect(mergeDeep(null)).toEqual({});
expect(mergeDeep(null, { foo: 42 })).toEqual({ foo: 42 });
});
it('should preserve identity for single arguments', function() {
const arg = Object.create(null);
expect(mergeDeep(arg)).toBe(arg);
});
it('should preserve identity when merging non-conflicting objects', function() {
const a = { a: { name: 'ay' } };
const b = { b: { name: 'bee' } };
const c = mergeDeep(a, b);
expect(c.a).toBe(a.a);
expect(c.b).toBe(b.b);
expect(c).toEqual({
a: { name: 'ay' },
b: { name: 'bee' },
});
});
it('should shallow-copy conflicting fields', function() {
const a = { conflict: { fromA: [1, 2, 3] } };
const b = { conflict: { fromB: [4, 5] } };
const c = mergeDeep(a, b);
expect(c.conflict).not.toBe(a.conflict);
expect(c.conflict).not.toBe(b.conflict);
expect(c.conflict.fromA).toBe(a.conflict.fromA);
expect(c.conflict.fromB).toBe(b.conflict.fromB);
expect(c).toEqual({
conflict: {
fromA: [1, 2, 3],
fromB: [4, 5],
},
});
});
it('should resolve conflicts among more than two objects', function() {
const sources = [];
for (let i = 0; i < 100; ++i) {
sources.push({
['unique' + i]: { value: i },
conflict: {
['from' + i]: { value: i },
nested: {
['nested' + i]: { value: i },
},
},
});
}
const merged = mergeDeep(...sources);
sources.forEach((source, i) => {
expect(merged['unique' + i].value).toBe(i);
expect(source['unique' + i]).toBe(merged['unique' + i]);
expect(merged.conflict).not.toBe(source.conflict);
expect(merged.conflict['from' + i].value).toBe(i);
expect(merged.conflict['from' + i]).toBe(source.conflict['from' + i]);
expect(merged.conflict.nested).not.toBe(source.conflict.nested);
expect(merged.conflict.nested['nested' + i].value).toBe(i);
expect(merged.conflict.nested['nested' + i]).toBe(
source.conflict.nested['nested' + i],
);
});
});
it('can merge array elements', function() {
const a = [{ a: 1 }, { a: 'ay' }, 'a'];
const b = [{ b: 2 }, { b: 'bee' }, 'b'];
const c = [{ c: 3 }, { c: 'cee' }, 'c'];
const d = { 1: { d: 'dee' } };
expect(mergeDeep(a, b, c, d)).toEqual([
{ a: 1, b: 2, c: 3 },
{ a: 'ay', b: 'bee', c: 'cee', d: 'dee' },
'c',
]);
});
it('lets the last conflicting value win', function() {
expect(mergeDeep('a', 'b', 'c')).toBe('c');
expect(
mergeDeep(
{ a: 'a', conflict: 1 },
{ b: 'b', conflict: 2 },
{ c: 'c', conflict: 3 },
),
).toEqual({
a: 'a',
b: 'b',
c: 'c',
conflict: 3,
});
expect(mergeDeep(
['a', ['b', 'c'], 'd'],
[/*empty*/, ['B'], 'D'],
)).toEqual(
['a', ['B', 'c'], 'D'],
);
expect(mergeDeep(
['a', ['b', 'c'], 'd'],
['A', [/*empty*/, 'C']],
)).toEqual(
['A', ['b', 'C'], 'd'],
);
});
it('mergeDeep returns the intersection of its argument types', function() {
const abc = mergeDeep({ str: "hi", a: 1 }, { a: 3, b: 2 }, { b: 1, c: 2 });
// The point of this test is that the following lines type-check without
// resorting to any `any` loopholes:
expect(abc.str.slice(0)).toBe("hi");
expect(abc.a * 2).toBe(6);
expect(abc.b - 0).toBe(1);
expect(abc.c / 2).toBe(1);
});
it('mergeDeepArray returns the supertype of its argument types', function() {
class F {
check() { return "ok" };
}
const fs: F[] = [new F, new F, new F];
// Although mergeDeepArray doesn't have the same tuple type awareness as
// mergeDeep, it does infer that F should be the return type here:
expect(mergeDeepArray(fs).check()).toBe("ok");
});
});

View File

@@ -0,0 +1,15 @@
import { stripSymbols } from '../stripSymbols';
interface SymbolConstructor {
(description?: string | number): symbol;
}
declare const Symbol: SymbolConstructor;
describe('stripSymbols', () => {
it('should strip symbols (only)', () => {
const sym = Symbol('id');
const data = { foo: 'bar', [sym]: 'ROOT_QUERY' };
expect(stripSymbols(data)).toEqual({ foo: 'bar' });
});
});

View File

@@ -0,0 +1,61 @@
import { warnOnceInDevelopment } from '../warnOnce';
let lastWarning: string | null;
let keepEnv: string | undefined;
let numCalls = 0;
let oldConsoleWarn: any;
describe('warnOnce', () => {
beforeEach(() => {
keepEnv = process.env.NODE_ENV;
numCalls = 0;
lastWarning = null;
oldConsoleWarn = console.warn;
console.warn = (msg: any) => {
numCalls++;
lastWarning = msg;
};
});
afterEach(() => {
process.env.NODE_ENV = keepEnv;
console.warn = oldConsoleWarn;
});
it('actually warns', () => {
process.env.NODE_ENV = 'development';
warnOnceInDevelopment('hi');
expect(lastWarning).toBe('hi');
expect(numCalls).toEqual(1);
});
it('does not warn twice', () => {
process.env.NODE_ENV = 'development';
warnOnceInDevelopment('ho');
warnOnceInDevelopment('ho');
expect(lastWarning).toEqual('ho');
expect(numCalls).toEqual(1);
});
it('warns two different things once each', () => {
process.env.NODE_ENV = 'development';
warnOnceInDevelopment('slow');
expect(lastWarning).toEqual('slow');
warnOnceInDevelopment('mo');
expect(lastWarning).toEqual('mo');
expect(numCalls).toEqual(2);
});
it('does not warn in production', () => {
process.env.NODE_ENV = 'production';
warnOnceInDevelopment('lo');
warnOnceInDevelopment('lo');
expect(numCalls).toEqual(0);
});
it('warns many times in test', () => {
process.env.NODE_ENV = 'test';
warnOnceInDevelopment('yo');
warnOnceInDevelopment('yo');
expect(lastWarning).toEqual('yo');
expect(numCalls).toEqual(2);
});
});

31
node_modules/apollo-utilities/src/util/assign.ts generated vendored Normal file
View File

@@ -0,0 +1,31 @@
/**
* Adds the properties of one or more source objects to a target object. Works exactly like
* `Object.assign`, but as a utility to maintain support for IE 11.
*
* @see https://github.com/apollostack/apollo-client/pull/1009
*/
export function assign<A, B>(a: A, b: B): A & B;
export function assign<A, B, C>(a: A, b: B, c: C): A & B & C;
export function assign<A, B, C, D>(a: A, b: B, c: C, d: D): A & B & C & D;
export function assign<A, B, C, D, E>(
a: A,
b: B,
c: C,
d: D,
e: E,
): A & B & C & D & E;
export function assign(target: any, ...sources: Array<any>): any;
export function assign(
target: { [key: string]: any },
...sources: Array<{ [key: string]: any }>
): { [key: string]: any } {
sources.forEach(source => {
if (typeof source === 'undefined' || source === null) {
return;
}
Object.keys(source).forEach(key => {
target[key] = source[key];
});
});
return target;
}

4
node_modules/apollo-utilities/src/util/canUse.ts generated vendored Normal file
View File

@@ -0,0 +1,4 @@
export const canUseWeakMap = typeof WeakMap === 'function' && !(
typeof navigator === 'object' &&
navigator.product === 'ReactNative'
);

37
node_modules/apollo-utilities/src/util/cloneDeep.ts generated vendored Normal file
View File

@@ -0,0 +1,37 @@
const { toString } = Object.prototype;
/**
* Deeply clones a value to create a new instance.
*/
export function cloneDeep<T>(value: T): T {
return cloneDeepHelper(value, new Map());
}
function cloneDeepHelper<T>(val: T, seen: Map<any, any>): T {
switch (toString.call(val)) {
case "[object Array]": {
if (seen.has(val)) return seen.get(val);
const copy: T & any[] = (val as any).slice(0);
seen.set(val, copy);
copy.forEach(function (child, i) {
copy[i] = cloneDeepHelper(child, seen);
});
return copy;
}
case "[object Object]": {
if (seen.has(val)) return seen.get(val);
// High fidelity polyfills of Object.create and Object.getPrototypeOf are
// possible in all JS environments, so we will assume they exist/work.
const copy = Object.create(Object.getPrototypeOf(val));
seen.set(val, copy);
Object.keys(val).forEach(key => {
copy[key] = cloneDeepHelper((val as any)[key], seen);
});
return copy;
}
default:
return val;
}
}

24
node_modules/apollo-utilities/src/util/environment.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
export function getEnv(): string | undefined {
if (typeof process !== 'undefined' && process.env.NODE_ENV) {
return process.env.NODE_ENV;
}
// default environment
return 'development';
}
export function isEnv(env: string): boolean {
return getEnv() === env;
}
export function isProduction(): boolean {
return isEnv('production') === true;
}
export function isDevelopment(): boolean {
return isEnv('development') === true;
}
export function isTest(): boolean {
return isEnv('test') === true;
}

View File

@@ -0,0 +1,15 @@
import { ExecutionResult } from 'graphql';
export function tryFunctionOrLogError(f: Function) {
try {
return f();
} catch (e) {
if (console.error) {
console.error(e);
}
}
}
export function graphQLResultHasError(result: ExecutionResult) {
return result.errors && result.errors.length;
}

View File

@@ -0,0 +1,14 @@
export function filterInPlace<T>(
array: T[],
test: (elem: T) => boolean,
context?: any,
): T[] {
let target = 0;
array.forEach(function (elem, i) {
if (test.call(this, elem, i, array)) {
array[target++] = elem;
}
}, context);
array.length = target;
return array;
}

1
node_modules/apollo-utilities/src/util/isEqual.ts generated vendored Normal file
View File

@@ -0,0 +1 @@
export { equal as isEqual } from '@wry/equality';

View File

@@ -0,0 +1,33 @@
import { isDevelopment, isTest } from './environment';
// Taken (mostly) from https://github.com/substack/deep-freeze to avoid
// import hassles with rollup.
function deepFreeze(o: any) {
Object.freeze(o);
Object.getOwnPropertyNames(o).forEach(function(prop) {
if (
o[prop] !== null &&
(typeof o[prop] === 'object' || typeof o[prop] === 'function') &&
!Object.isFrozen(o[prop])
) {
deepFreeze(o[prop]);
}
});
return o;
}
export function maybeDeepFreeze(obj: any) {
if (isDevelopment() || isTest()) {
// Polyfilled Symbols potentially cause infinite / very deep recursion while deep freezing
// which is known to crash IE11 (https://github.com/apollographql/apollo-client/issues/3043).
const symbolIsPolyfilled =
typeof Symbol === 'function' && typeof Symbol('') === 'string';
if (!symbolIsPolyfilled) {
return deepFreeze(obj);
}
}
return obj;
}

115
node_modules/apollo-utilities/src/util/mergeDeep.ts generated vendored Normal file
View File

@@ -0,0 +1,115 @@
const { hasOwnProperty } = Object.prototype;
// These mergeDeep and mergeDeepArray utilities merge any number of objects
// together, sharing as much memory as possible with the source objects, while
// remaining careful to avoid modifying any source objects.
// Logically, the return type of mergeDeep should be the intersection of
// all the argument types. The binary call signature is by far the most
// common, but we support 0- through 5-ary as well. After that, the
// resulting type is just the inferred array element type. Note to nerds:
// there is a more clever way of doing this that converts the tuple type
// first to a union type (easy enough: T[number]) and then converts the
// union to an intersection type using distributive conditional type
// inference, but that approach has several fatal flaws (boolean becomes
// true & false, and the inferred type ends up as unknown in many cases),
// in addition to being nearly impossible to explain/understand.
export type TupleToIntersection<T extends any[]> =
T extends [infer A] ? A :
T extends [infer A, infer B] ? A & B :
T extends [infer A, infer B, infer C] ? A & B & C :
T extends [infer A, infer B, infer C, infer D] ? A & B & C & D :
T extends [infer A, infer B, infer C, infer D, infer E] ? A & B & C & D & E :
T extends (infer U)[] ? U : any;
export function mergeDeep<T extends any[]>(
...sources: T
): TupleToIntersection<T> {
return mergeDeepArray(sources);
}
// In almost any situation where you could succeed in getting the
// TypeScript compiler to infer a tuple type for the sources array, you
// could just use mergeDeep instead of mergeDeepArray, so instead of
// trying to convert T[] to an intersection type we just infer the array
// element type, which works perfectly when the sources array has a
// consistent element type.
export function mergeDeepArray<T>(sources: T[]): T {
let target = sources[0] || {} as T;
const count = sources.length;
if (count > 1) {
const pastCopies: any[] = [];
target = shallowCopyForMerge(target, pastCopies);
for (let i = 1; i < count; ++i) {
target = mergeHelper(target, sources[i], pastCopies);
}
}
return target;
}
function isObject(obj: any): obj is Record<string | number, any> {
return obj !== null && typeof obj === 'object';
}
function mergeHelper(
target: any,
source: any,
pastCopies: any[],
) {
if (isObject(source) && isObject(target)) {
// In case the target has been frozen, make an extensible copy so that
// we can merge properties into the copy.
if (Object.isExtensible && !Object.isExtensible(target)) {
target = shallowCopyForMerge(target, pastCopies);
}
Object.keys(source).forEach(sourceKey => {
const sourceValue = source[sourceKey];
if (hasOwnProperty.call(target, sourceKey)) {
const targetValue = target[sourceKey];
if (sourceValue !== targetValue) {
// When there is a key collision, we need to make a shallow copy of
// target[sourceKey] so the merge does not modify any source objects.
// To avoid making unnecessary copies, we use a simple array to track
// past copies, since it's safe to modify copies created earlier in
// the merge. We use an array for pastCopies instead of a Map or Set,
// since the number of copies should be relatively small, and some
// Map/Set polyfills modify their keys.
target[sourceKey] = mergeHelper(
shallowCopyForMerge(targetValue, pastCopies),
sourceValue,
pastCopies,
);
}
} else {
// If there is no collision, the target can safely share memory with
// the source, and the recursion can terminate here.
target[sourceKey] = sourceValue;
}
});
return target;
}
// If source (or target) is not an object, let source replace target.
return source;
}
function shallowCopyForMerge<T>(value: T, pastCopies: any[]): T {
if (
value !== null &&
typeof value === 'object' &&
pastCopies.indexOf(value) < 0
) {
if (Array.isArray(value)) {
value = (value as any).slice(0);
} else {
value = {
__proto__: Object.getPrototypeOf(value),
...value,
};
}
pastCopies.push(value);
}
return value;
}

14
node_modules/apollo-utilities/src/util/stripSymbols.ts generated vendored Normal file
View File

@@ -0,0 +1,14 @@
/**
* In order to make assertions easier, this function strips `symbol`'s from
* the incoming data.
*
* This can be handy when running tests against `apollo-client` for example,
* since it adds `symbol`'s to the data in the store. Jest's `toEqual`
* function now covers `symbol`'s (https://github.com/facebook/jest/pull/3437),
* which means all test data used in a `toEqual` comparison would also have to
* include `symbol`'s, to pass. By stripping `symbol`'s from the cache data
* we can compare against more simplified test data.
*/
export function stripSymbols<T>(data: T): T {
return JSON.parse(JSON.stringify(data));
}

24
node_modules/apollo-utilities/src/util/warnOnce.ts generated vendored Normal file
View File

@@ -0,0 +1,24 @@
import { isProduction, isTest } from './environment';
const haveWarned = Object.create({});
/**
* Print a warning only once in development.
* In production no warnings are printed.
* In test all warnings are printed.
*
* @param msg The warning message
* @param type warn or error (will call console.warn or console.error)
*/
export function warnOnceInDevelopment(msg: string, type = 'warn') {
if (!isProduction() && !haveWarned[msg]) {
if (!isTest()) {
haveWarned[msg] = true;
}
if (type === 'error') {
console.error(msg);
} else {
console.warn(msg);
}
}
}