From f19d3e63664dbb16ed986d2bb81aacf4316ab404 Mon Sep 17 00:00:00 2001 From: Steve Ruiz Date: Wed, 18 Aug 2021 00:11:00 +0100 Subject: [PATCH] Fixes database issues, fixes rendering issue --- package.json | 2 +- packages/core/package.json | 4 +- packages/core/src/utils/utils.ts | 28 ++++++- packages/dev/src/components/editor.tsx | 3 +- packages/dev/src/hooks/usePersistence.tsx | 13 ++-- .../tldraw/src/shape/shapes/arrow/arrow.tsx | 10 +++ packages/tldraw/src/state/tldr.ts | 2 - packages/tldraw/src/state/tlstate.spec.ts | 1 + packages/tldraw/src/state/tlstate.ts | 46 +++++------ packages/tldraw/src/state/utils.spec.ts | 19 +++++ packages/tldraw/src/types.ts | 15 ++-- packages/www/components/editor.tsx | 4 +- packages/www/hooks/usePersistence.tsx | 19 +++-- yarn.lock | 78 ++++++++++++++++++- 14 files changed, 185 insertions(+), 59 deletions(-) create mode 100644 packages/tldraw/src/state/utils.spec.ts diff --git a/package.json b/package.json index dd1afa185..3ac7e7fe3 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "test": "jest", "lerna": "lerna", "start": "lerna run start --stream --parallel", - "start:www": "lerna run start --stream --parallel & cd packages/www && yarn build", + "start:www": "lerna run start --stream --parallel & cd packages/www && yarn dev", "build": "yarn build:packages && cd packages/www && yarn build", "build:packages": "cd packages/core && yarn build && cd ../tldraw && yarn build", "publish:patch": "yarn build:packages && lerna publish patch" diff --git a/packages/core/package.json b/packages/core/package.json index f76013a0e..760ac79b1 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -43,10 +43,12 @@ "react-dom": "^17.0.2" }, "dependencies": { + "@types/merge-deep": "^3.0.0", "deepmerge": "^4.2.2", "ismobilejs": "^1.1.1", + "merge-deep": "^3.0.3", "react-error-boundary": "^3.1.3", "react-use-gesture": "^9.1.3" }, "gitHead": "a7dac0f83ad998e205c2aab58182cb4ba4e099a6" -} \ No newline at end of file +} diff --git a/packages/core/src/utils/utils.ts b/packages/core/src/utils/utils.ts index b3cc4ccb9..730eb4013 100644 --- a/packages/core/src/utils/utils.ts +++ b/packages/core/src/utils/utils.ts @@ -21,8 +21,32 @@ export class Utils { return Object.fromEntries((Object.entries(obj) as Entry[]).filter(fn)) as Partial } - static deepMerge(a: T, b: DeepPartial): T { - return deepmerge>(a, b, { arrayMerge: (_a, b) => b }) as T + static deepMerge(target: T, source: any): T { + return deepmerge(target, source, { arrayMerge: (a, b) => b, clone: false }) + + // const result = {} as T + + // for (const key of Object.keys(result)) { + // const tprop = target[key as keyof T] + // const sprop = source[key] + // if (tprop === sprop) { + // continue + // } else if (!(key in target) || target[key as keyof T] === undefined) { + // result[key as keyof T] = sprop + // } else if (!(key in source)) { + // continue + // } else if (source[key as keyof T] === undefined) { + // delete result[key as keyof T] + // } else { + // if (typeof tprop === 'object' && typeof sprop === 'object') { + // result[key as keyof T] = this.deepMerge(tprop, sprop) + // } else { + // result[key as keyof T] = sprop + // } + // } + // } + + // return result } /** diff --git a/packages/dev/src/components/editor.tsx b/packages/dev/src/components/editor.tsx index 2b188425b..c283f90a3 100644 --- a/packages/dev/src/components/editor.tsx +++ b/packages/dev/src/components/editor.tsx @@ -7,6 +7,7 @@ import { SizeStyle, TLDrawShapeType, TLDrawState, + TLDrawPatch, } from '@tldraw/tldraw' import { usePersistence } from '../hooks/usePersistence' @@ -88,7 +89,7 @@ export default function Editor(): JSX.Element { const { value, setValue, status } = usePersistence('doc', initialDoc) const handleChange = React.useCallback( - (tlstate: TLDrawState, reason: string) => { + (tlstate: TLDrawState, patch: TLDrawPatch, reason: string) => { if (reason.startsWith('session')) { return } diff --git a/packages/dev/src/hooks/usePersistence.tsx b/packages/dev/src/hooks/usePersistence.tsx index 0383f27b6..6b20868a7 100644 --- a/packages/dev/src/hooks/usePersistence.tsx +++ b/packages/dev/src/hooks/usePersistence.tsx @@ -1,9 +1,9 @@ /* eslint-disable @typescript-eslint/explicit-module-boundary-types */ import * as React from 'react' -import { openDB, DBSchema, deleteDB } from 'idb' +import { openDB, DBSchema } from 'idb' import type { TLDrawDocument } from '@tldraw/tldraw' -const VERSION = 1 +const VERSION = 4 interface TLDatabase extends DBSchema { documents: { @@ -57,11 +57,12 @@ export function usePersistence(id: string, doc: TLDrawDocument) { // the state. React.useEffect(() => { async function handleLoad() { - await deleteDB('db') - const db = await openDB('db', VERSION, { - upgrade(db) { - db.createObjectStore('documents') + upgrade(db, oldVersion, newVersion) { + if (newVersion) { + db.deleteObjectStore('documents') + db.createObjectStore('documents') + } }, }) diff --git a/packages/tldraw/src/shape/shapes/arrow/arrow.tsx b/packages/tldraw/src/shape/shapes/arrow/arrow.tsx index 0eb15687c..45e707ddd 100644 --- a/packages/tldraw/src/shape/shapes/arrow/arrow.tsx +++ b/packages/tldraw/src/shape/shapes/arrow/arrow.tsx @@ -760,6 +760,11 @@ function getCurvedArrowHeadPoints( sweep: boolean ) { const ints = Intersect.circle.circle(A, r1 * 0.618, C, r2).points + if (!ints) { + console.warn('Could not find an intersection for the arrow head.') + return { left: A, right: A } + } + const int = sweep ? ints[0] : ints[1] const left = Vec.nudge(Vec.rotWith(int, A, Math.PI / 6), A, r1 * -0.382) const right = Vec.nudge(Vec.rotWith(int, A, -Math.PI / 6), A, r1 * -0.382) @@ -768,6 +773,11 @@ function getCurvedArrowHeadPoints( function getStraightArrowHeadPoints(A: number[], B: number[], r: number) { const ints = Intersect.circle.lineSegment(A, r, A, B).points + if (!ints) { + console.warn('Could not find an intersection for the arrow head.') + return { left: A, right: A } + } + const int = ints[0] const left = Vec.rotWith(int, A, Math.PI / 6) const right = Vec.rotWith(int, A, -Math.PI / 6) diff --git a/packages/tldraw/src/state/tldr.ts b/packages/tldraw/src/state/tldr.ts index 83c04070b..29f625e28 100644 --- a/packages/tldraw/src/state/tldr.ts +++ b/packages/tldraw/src/state/tldr.ts @@ -414,7 +414,6 @@ export class TLDR { after: Record> data: Data } { - const page = { ...this.getPage(data, pageId) } const beforeShapes: Record> = {} const afterShapes: Record> = {} @@ -425,7 +424,6 @@ export class TLDR { Object.keys(change).map((key) => [key, shape[key as keyof T]]) ) as Partial afterShapes[id] = change - page.shapes[id] = this.getShapeUtils(shape).mutate(shape as T, change as Partial) }) const dataWithChildrenChanges = ids.reduce((cData, id) => { diff --git a/packages/tldraw/src/state/tlstate.spec.ts b/packages/tldraw/src/state/tlstate.spec.ts index 9edd99034..52e692b4d 100644 --- a/packages/tldraw/src/state/tlstate.spec.ts +++ b/packages/tldraw/src/state/tlstate.spec.ts @@ -1,5 +1,6 @@ import { TLDrawState } from './tlstate' import { mockDocument, TLStateUtils } from '~test' +import { Utils } from '@tldraw/core' describe('TLDrawState', () => { const tlstate = new TLDrawState() diff --git a/packages/tldraw/src/state/tlstate.ts b/packages/tldraw/src/state/tlstate.ts index 2602b9453..1a889ba7a 100644 --- a/packages/tldraw/src/state/tlstate.ts +++ b/packages/tldraw/src/state/tlstate.ts @@ -116,7 +116,7 @@ export class TLDrawState implements TLCallbacks { isCreating = false - _onChange?: (patch: DeepPartial, reason: string) => void + _onChange?: (tlstate: TLDrawState, patch: DeepPartial, reason: string) => void // Low API private getState = this.store.getState @@ -124,7 +124,7 @@ export class TLDrawState implements TLCallbacks { private produce(patch: DeepPartial, reason: string) { const next = Utils.deepMerge(this.data, patch) this.setState(next) - this._onChange?.(patch, reason) + this._onChange?.(this, patch, reason) return this } @@ -160,38 +160,31 @@ export class TLDrawState implements TLCallbacks { const prevPage = prev.document.pages[pageId] - const nextPage = { - ...page, - shapes: { ...page.shapes }, - bindings: { ...page.bindings }, - } + if (!prevPage || page.shapes !== prevPage.shapes || page.bindings !== prevPage.bindings) { + page.shapes = { ...page.shapes } + page.bindings = { ...page.bindings } - if ( - !prevPage || - nextPage.shapes !== prevPage.shapes || - nextPage.bindings !== prevPage.bindings - ) { - Object.keys(nextPage.shapes).forEach((id) => { - if (!nextPage.shapes[id]) delete nextPage.shapes[id] + Object.keys(page.shapes).forEach((id) => { + if (!page.shapes[id]) delete page.shapes[id] }) - Object.keys(nextPage.bindings).forEach((id) => { - if (!nextPage.bindings[id]) delete nextPage.bindings[id] + Object.keys(page.bindings).forEach((id) => { + if (!page.bindings[id]) delete page.bindings[id] }) - const changedShapeIds = Object.values(nextPage.shapes) - .filter((shape) => this.data.document.pages[pageId].shapes[shape.id] !== shape) + const changedShapeIds = Object.values(page.shapes) + .filter((shape) => prevPage.shapes[shape.id] !== shape) .map((shape) => shape.id) - this.data.document.pages[pageId] = nextPage + this.data.document.pages[pageId] = page // Get bindings related to the changed shapes const bindingsToUpdate = TLDR.getRelatedBindings(this.data, changedShapeIds, pageId) // Update all of the bindings we've just collected bindingsToUpdate.forEach((binding) => { - const toShape = nextPage.shapes[binding.toId] - const fromShape = nextPage.shapes[binding.fromId] + const toShape = page.shapes[binding.toId] + const fromShape = page.shapes[binding.fromId] const toUtils = TLDR.getShapeUtils(toShape) // We only need to update the binding's "from" shape @@ -211,7 +204,7 @@ export class TLDrawState implements TLCallbacks { ...fromDelta, } as TLDrawShape - nextPage.shapes[fromShape.id] = nextShape + page.shapes[fromShape.id] = nextShape } }) } @@ -222,21 +215,20 @@ export class TLDrawState implements TLCallbacks { ...this.data.document.pageStates[pageId], } - if (nextPageState.hoveredId && !nextPage.shapes[nextPageState.hoveredId]) { + if (nextPageState.hoveredId && !page.shapes[nextPageState.hoveredId]) { delete nextPageState.hoveredId } - if (nextPageState.bindingId && !nextPage.bindings[nextPageState.bindingId]) { + if (nextPageState.bindingId && !page.bindings[nextPageState.bindingId]) { console.warn('Could not find the binding shape!', pageId) delete nextPageState.bindingId } - if (nextPageState.editingId && !nextPage.bindings[nextPageState.editingId]) { + if (nextPageState.editingId && !page.bindings[nextPageState.editingId]) { console.warn('Could not find the editing shape!') delete nextPageState.editingId } - this.data.document.pages[pageId] = nextPage this.data.document.pageStates[pageId] = nextPageState }) } @@ -375,7 +367,7 @@ export class TLDrawState implements TLCallbacks { } this.setState(emptyData) - this._onChange?.(this.data, `reset`) + this._onChange?.(this, this.data, `reset`) return this } diff --git a/packages/tldraw/src/state/utils.spec.ts b/packages/tldraw/src/state/utils.spec.ts new file mode 100644 index 000000000..079e3e62e --- /dev/null +++ b/packages/tldraw/src/state/utils.spec.ts @@ -0,0 +1,19 @@ +import { Utils } from '@tldraw/core' + +describe('deep merge', () => { + it('merges an object', () => { + const a = { a: 1, b: 2 } + const b = { ...a, a: 2 } + const c = Utils.deepMerge(a, b) + expect(c.a).toBe(2) + expect(c.b).toBe(a.b) + }) + + it('merges a complex object', () => { + const a = { a: 1, b: { name: 'steve', age: 93 } } + const b = { a: 2 } + const c = Utils.deepMerge(a, b) + expect(c.a).toBe(2) + expect(c.b === a.b).toBeTruthy() + }) +}) diff --git a/packages/tldraw/src/types.ts b/packages/tldraw/src/types.ts index fc3854423..aa1fc01ea 100644 --- a/packages/tldraw/src/types.ts +++ b/packages/tldraw/src/types.ts @@ -40,6 +40,9 @@ export interface Data { status: { current: TLDrawStatus; previous: TLDrawStatus } } } + +export type TLDrawPatch = DeepPartial + export type PagePartial = { shapes: DeepPartial bindings: DeepPartial @@ -55,8 +58,8 @@ export type DeepPartial = T extends Function export interface Command { id: string - before: DeepPartial - after: DeepPartial + before: TLDrawPatch + after: TLDrawPatch } export interface History { @@ -72,10 +75,10 @@ export interface SelectHistory { export interface Session { id: string status: TLDrawStatus - start: (data: Readonly, ...args: any[]) => DeepPartial | void - update: (data: Readonly, ...args: any[]) => DeepPartial - complete: (data: Readonly, ...args: any[]) => DeepPartial | Command | undefined - cancel: (data: Readonly, ...args: any[]) => DeepPartial + start: (data: Readonly, ...args: any[]) => TLDrawPatch | void + update: (data: Readonly, ...args: any[]) => TLDrawPatch + complete: (data: Readonly, ...args: any[]) => TLDrawPatch | Command | undefined + cancel: (data: Readonly, ...args: any[]) => TLDrawPatch } export enum TLDrawStatus { diff --git a/packages/www/components/editor.tsx b/packages/www/components/editor.tsx index 8efb030ab..23607c7b5 100644 --- a/packages/www/components/editor.tsx +++ b/packages/www/components/editor.tsx @@ -1,6 +1,6 @@ import * as React from 'react' import { ColorStyle, DashStyle, SizeStyle, TLDrawShapeType, TLDrawState } from '@tldraw/tldraw' -import { TLDraw, TLDrawDocument } from '@tldraw/tldraw' +import { TLDraw, TLDrawDocument, TLDrawPatch } from '@tldraw/tldraw' import { usePersistence } from '../hooks/usePersistence' const initialDoc: TLDrawDocument = { @@ -81,7 +81,7 @@ export default function Editor(): JSX.Element { const { value, setValue, status } = usePersistence('doc', initialDoc) const handleChange = React.useCallback( - (tlstate: TLDrawState, reason: string) => { + (tlstate: TLDrawState, patch: TLDrawPatch, reason: string) => { if (reason.startsWith('session')) { return } diff --git a/packages/www/hooks/usePersistence.tsx b/packages/www/hooks/usePersistence.tsx index 82246a689..7110c5b09 100644 --- a/packages/www/hooks/usePersistence.tsx +++ b/packages/www/hooks/usePersistence.tsx @@ -9,7 +9,7 @@ interface TLDatabase extends DBSchema { } } -const VERSION = 2 +const VERSION = 4 /** * Persist a value in indexdb. This hook is designed to be used primarily through @@ -35,7 +35,7 @@ export function usePersistence(id: string, doc: TLDrawDocument) { _setValue(null) setStatus('loading') - openDB('db', VERSION).then((db) => + openDB('db1', VERSION).then((db) => db.get('documents', id).then((v) => { if (!v) throw Error(`Could not find document with id: ${id}`) _setValue(v) @@ -48,7 +48,7 @@ export function usePersistence(id: string, doc: TLDrawDocument) { // value in the database. const setValue = React.useCallback( (doc: TLDrawDocument) => { - openDB('db', VERSION).then((db) => db.put('documents', doc, id)) + openDB('db1', VERSION).then((db) => db.put('documents', doc, id)) }, [id] ) @@ -57,16 +57,19 @@ export function usePersistence(id: string, doc: TLDrawDocument) { // the state. React.useEffect(() => { async function handleLoad() { - const db = await openDB('db', VERSION, { - upgrade(db) { - db.createObjectStore('documents') + const db1 = await openDB('db1', VERSION, { + upgrade(db, oldVersion, newVersion) { + if (newVersion) { + db.deleteObjectStore('documents') + db.createObjectStore('documents') + } }, }) let savedDoc: TLDrawDocument try { - const restoredDoc = await db.get('documents', id) + const restoredDoc = await db1.get('documents', id) if (!restoredDoc) throw Error('No document') savedDoc = restoredDoc restoredDoc.pageStates = Object.fromEntries( @@ -80,7 +83,7 @@ export function usePersistence(id: string, doc: TLDrawDocument) { ]) ) } catch (e) { - await db.put('documents', doc, id) + await db1.put('documents', doc, id) savedDoc = doc } diff --git a/yarn.lock b/yarn.lock index 397c2dd95..e1b739bae 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2246,6 +2246,11 @@ resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== +"@types/merge-deep@^3.0.0": + version "3.0.0" + resolved "https://registry.yarnpkg.com/@types/merge-deep/-/merge-deep-3.0.0.tgz#3815fce13b2b0e9fadf5d71d13db5937a35f27fc" + integrity sha512-t5B5UfacpaP8opUvFGUwT0uQetFrD+qm1/I2ksxokJFLT0Tb4B2NI2G2LYz3ugMDKOE7adkNBZ6coK7RW6MAqA== + "@types/minimatch@*": version "3.0.5" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.5.tgz#1001cc5e6a3704b83c236027e77f2f58ea010f40" @@ -3402,6 +3407,17 @@ cliui@^7.0.2: strip-ansi "^6.0.0" wrap-ansi "^7.0.0" +clone-deep@^0.2.4: + version "0.2.4" + resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-0.2.4.tgz#4e73dd09e9fb971cc38670c5dced9c1896481cc6" + integrity sha1-TnPdCen7lxzDhnDF3O2cGJZIHMY= + dependencies: + for-own "^0.1.3" + is-plain-object "^2.0.1" + kind-of "^3.0.2" + lazy-cache "^1.0.3" + shallow-clone "^0.1.2" + clone-deep@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" @@ -4851,11 +4867,23 @@ flush-write-stream@^1.0.0: inherits "^2.0.3" readable-stream "^2.3.6" -for-in@^1.0.2: +for-in@^0.1.3: + version "0.1.8" + resolved "https://registry.yarnpkg.com/for-in/-/for-in-0.1.8.tgz#d8773908e31256109952b1fdb9b3fa867d2775e1" + integrity sha1-2Hc5COMSVhCZUrH9ubP6hn0ndeE= + +for-in@^1.0.1, for-in@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= +for-own@^0.1.3: + version "0.1.5" + resolved "https://registry.yarnpkg.com/for-own/-/for-own-0.1.5.tgz#5265c681a4f294dabbf17c9509b6763aa84510ce" + integrity sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4= + dependencies: + for-in "^1.0.1" + foreach@^2.0.5: version "2.0.5" resolved "https://registry.yarnpkg.com/foreach/-/foreach-2.0.5.tgz#0bee005018aeb260d0a3af3ae658dd0136ec1b99" @@ -5667,7 +5695,7 @@ is-boolean-object@^1.1.0: call-bind "^1.0.2" has-tostringtag "^1.0.0" -is-buffer@^1.1.5: +is-buffer@^1.0.2, is-buffer@^1.1.5: version "1.1.6" resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== @@ -5854,7 +5882,7 @@ is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= -is-plain-object@^2.0.3, is-plain-object@^2.0.4: +is-plain-object@^2.0.1, is-plain-object@^2.0.3, is-plain-object@^2.0.4: version "2.0.4" resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== @@ -6593,6 +6621,13 @@ jsprim@^1.2.2: array-includes "^3.1.2" object.assign "^4.1.2" +kind-of@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-2.0.1.tgz#018ec7a4ce7e3a86cb9141be519d24c8faa981b5" + integrity sha1-AY7HpM5+OobLkUG+UZ0kyPqpgbU= + dependencies: + is-buffer "^1.0.2" + kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: version "3.2.2" resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" @@ -6634,6 +6669,16 @@ language-tags@^1.0.5: dependencies: language-subtag-registry "~0.3.2" +lazy-cache@^0.2.3: + version "0.2.7" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-0.2.7.tgz#7feddf2dcb6edb77d11ef1d117ab5ffdf0ab1b65" + integrity sha1-f+3fLctu23fRHvHRF6tf/fCrG2U= + +lazy-cache@^1.0.3: + version "1.0.4" + resolved "https://registry.yarnpkg.com/lazy-cache/-/lazy-cache-1.0.4.tgz#a1d78fc3a50474cb80845d3b3b6e1da49a446e8e" + integrity sha1-odePw6UEdMuAhF07O24dpJpEbo4= + lerna@^3.15.0: version "3.22.1" resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.1.tgz#82027ac3da9c627fd8bf02ccfeff806a98e65b62" @@ -6997,6 +7042,15 @@ meow@^8.0.0: type-fest "^0.18.0" yargs-parser "^20.2.3" +merge-deep@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/merge-deep/-/merge-deep-3.0.3.tgz#1a2b2ae926da8b2ae93a0ac15d90cd1922766003" + integrity sha512-qtmzAS6t6grwEkNrunqTBdn0qKwFgNWvlxUbAV8es9M7Ot1EbyApytCnvE0jALPa46ZpKDUo527kKiaWplmlFA== + dependencies: + arr-union "^3.1.0" + clone-deep "^0.2.4" + kind-of "^3.0.2" + merge-stream@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" @@ -7147,6 +7201,14 @@ mixin-deep@^1.2.0: for-in "^1.0.2" is-extendable "^1.0.1" +mixin-object@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/mixin-object/-/mixin-object-2.0.1.tgz#4fb949441dab182540f1fe035ba60e1947a5e57e" + integrity sha1-T7lJRB2rGCVA8f4DW6YOGUel5X4= + dependencies: + for-in "^0.1.3" + is-extendable "^0.1.1" + mkdirp-promise@^5.0.1: version "5.0.1" resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" @@ -8878,6 +8940,16 @@ sha.js@^2.4.0, sha.js@^2.4.8: inherits "^2.0.1" safe-buffer "^5.0.1" +shallow-clone@^0.1.2: + version "0.1.2" + resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-0.1.2.tgz#5909e874ba77106d73ac414cfec1ffca87d97060" + integrity sha1-WQnodLp3EG1zrEFM/sH/yofZcGA= + dependencies: + is-extendable "^0.1.1" + kind-of "^2.0.1" + lazy-cache "^0.2.3" + mixin-object "^2.0.1" + shallow-clone@^3.0.0: version "3.0.1" resolved "https://registry.yarnpkg.com/shallow-clone/-/shallow-clone-3.0.1.tgz#8f2981ad92531f55035b01fb230769a40e02efa3"