diff --git a/.circleci/config.yml b/.circleci/config.yml index bf591a3ed..a0326cad3 100755 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,113 +1,99 @@ version: 2.1 executors: - my-executor: - docker: - - image: cimg/node:14.18.1 - environment: - CI: true + my-executor: + docker: + - image: cimg/node:14.18.1 + environment: + CI: true orbs: - node: circleci/node@4.7.0 + node: circleci/node@4.7.0 jobs: - # mobx-state-tree build - build: - executor: my-executor - steps: - - checkout - - - node/install-packages: - pkg-manager: yarn - - - run: yarn build - - - persist_to_workspace: - root: . - paths: - - ./* - - # mobx-state-tree tests - test-mst-dev: - executor: my-executor - steps: - - attach_workspace: - at: . - - - run: yarn test:mst:dev -i --coverage - - store_test_results: - path: ./test-results - - - persist_to_workspace: - root: . - paths: - - packages/mobx-state-tree/coverage/* - - test-mst-prod: - executor: my-executor - steps: - - attach_workspace: - at: . - - - run: yarn test:mst:prod -i - - store_test_results: - path: ./test-results - - test-mst-others: - executor: my-executor - steps: - - attach_workspace: - at: . - - - run: yarn test:mst:others - - store_test_results: - path: ./test-results - - test-size: - executor: my-executor - steps: - - attach_workspace: - at: . - - - run: yarn size - - # upload coverage - upload-codecov: - executor: my-executor - steps: - - attach_workspace: - at: . - # only run codecov if the token is present (it is not present for fork PRs for security reasons) - - run: - name: upload codecov - command: | - if [[ -v CODECOV_TOKEN ]] - then - ./node_modules/.bin/codecov - else - echo "Warning - Codecov info could NOT be uploaded since the CODECOV_TOKEN was not available" - fi + # mobx-state-tree build + build: + executor: my-executor + steps: + - checkout + + - node/install-packages: + pkg-manager: yarn + + - run: yarn build + + - persist_to_workspace: + root: . + paths: + - ./* + + # mobx-state-tree tests + test-mst-dev: + executor: my-executor + steps: + - attach_workspace: + at: . + + - run: yarn test:dev -i --coverage + - store_test_results: + path: ./test-results + + - persist_to_workspace: + root: . + paths: + - ./coverage/* + + test-mst-prod: + executor: my-executor + steps: + - attach_workspace: + at: . + + - run: yarn test:prod -i + - store_test_results: + path: ./test-results + + test-size: + executor: my-executor + steps: + - attach_workspace: + at: . + + - run: yarn size + + # upload coverage + upload-codecov: + executor: my-executor + steps: + - attach_workspace: + at: . + # only run codecov if the token is present (it is not present for fork PRs for security reasons) + - run: + name: upload codecov + command: | + if [[ -v CODECOV_TOKEN ]] + then + ./node_modules/.bin/codecov + else + echo "Warning - Codecov info could NOT be uploaded since the CODECOV_TOKEN was not available" + fi workflows: - version: 2 - build-and-test: - jobs: + version: 2 + build-and-test: + jobs: + - build + + - test-mst-dev: + requires: + - build + - test-mst-prod: + requires: + - build + - test-size: + requires: - build - - test-mst-dev: - requires: - - build - - test-mst-prod: - requires: - - build - - test-mst-others: - requires: - - build - - - test-size: - requires: - - build - - - upload-codecov: - requires: - - test-mst-dev + - upload-codecov: + requires: + - test-mst-dev diff --git a/.gitignore b/.gitignore index b5f3407ec..9fc50cc43 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ package-lock.json /test-results/**/*.xml /website/build .DS_Store +junit.xml \ No newline at end of file diff --git a/.prettierrc b/.prettierrc deleted file mode 100644 index 3e9ddfc27..000000000 --- a/.prettierrc +++ /dev/null @@ -1,7 +0,0 @@ -{ - "printWidth": 100, - "tabWidth": 4, - "singleQuote": false, - "trailingComma": "none", - "semi": false -} diff --git a/.size-limit.json b/.size-limit.json deleted file mode 100644 index a946b2f84..000000000 --- a/.size-limit.json +++ /dev/null @@ -1,8 +0,0 @@ -[ - { - "path": "packages/mobx-state-tree/dist/mobx-state-tree.min.js", - "limit": "25 KB", - "webpack": false, - "running": false - } -] diff --git a/.watchmanconfig b/.watchmanconfig deleted file mode 100644 index 0967ef424..000000000 --- a/.watchmanconfig +++ /dev/null @@ -1 +0,0 @@ -{} diff --git a/packages/mobx-state-tree/__tests__/core/__snapshots__/async.test.ts.snap b/__tests__/core/__snapshots__/async.test.ts.snap similarity index 100% rename from packages/mobx-state-tree/__tests__/core/__snapshots__/async.test.ts.snap rename to __tests__/core/__snapshots__/async.test.ts.snap diff --git a/packages/mobx-state-tree/__tests__/core/__snapshots__/custom-type.test.ts.snap b/__tests__/core/__snapshots__/custom-type.test.ts.snap similarity index 100% rename from packages/mobx-state-tree/__tests__/core/__snapshots__/custom-type.test.ts.snap rename to __tests__/core/__snapshots__/custom-type.test.ts.snap diff --git a/packages/mobx-state-tree/__tests__/core/__snapshots__/reference-custom.test.ts.snap b/__tests__/core/__snapshots__/reference-custom.test.ts.snap similarity index 100% rename from packages/mobx-state-tree/__tests__/core/__snapshots__/reference-custom.test.ts.snap rename to __tests__/core/__snapshots__/reference-custom.test.ts.snap diff --git a/__tests__/core/action.test.ts b/__tests__/core/action.test.ts new file mode 100644 index 000000000..152252a5c --- /dev/null +++ b/__tests__/core/action.test.ts @@ -0,0 +1,454 @@ +import { configure } from "mobx" +import { + recordActions, + types, + getSnapshot, + onAction, + applyPatch, + applySnapshot, + addMiddleware, + getRoot, + cast, + IMiddlewareEvent, + ISerializedActionCall, + Instance +} from "../../src" + +/// Simple action replay and invocation +const Task = types + .model({ + done: false + }) + .actions((self) => { + function toggle() { + self.done = !self.done + return self.done + } + return { + toggle + } + }) +test("it should be possible to invoke a simple action", () => { + const t1 = Task.create() + expect(t1.done).toBe(false) + expect(t1.toggle()).toBe(true) + expect(t1.done).toBe(true) +}) +test("it should be possible to record & replay a simple action", () => { + const t1 = Task.create() + const t2 = Task.create() + expect(t1.done).toBe(false) + expect(t2.done).toBe(false) + const recorder = recordActions(t1) + t1.toggle() + t1.toggle() + t1.toggle() + expect(recorder.actions).toEqual([ + { name: "toggle", path: "", args: [] }, + { name: "toggle", path: "", args: [] }, + { name: "toggle", path: "", args: [] } + ]) + recorder.replay(t2) + expect(t2.done).toBe(true) +}) +test("applying patches should be recordable and replayable", () => { + const t1 = Task.create() + const t2 = Task.create() + const recorder = recordActions(t1) + expect(t1.done).toBe(false) + applyPatch(t1, { op: "replace", path: "/done", value: true }) + expect(t1.done).toBe(true) + expect(recorder.actions).toEqual([ + { + name: "@APPLY_PATCHES", + path: "", + args: [[{ op: "replace", path: "/done", value: true }]] + } + ]) + recorder.replay(t2) + expect(t2.done).toBe(true) +}) +test("applying patches should be replacing the root store", () => { + const t1 = Task.create() + const recorder = recordActions(t1) + expect(t1.done).toBe(false) + applyPatch(t1, { op: "replace", path: "", value: { done: true } }) + expect(t1.done).toBe(true) + expect(recorder.actions).toEqual([ + { + name: "@APPLY_PATCHES", + path: "", + args: [[{ op: "replace", path: "", value: { done: true } }]] + } + ]) +}) +test("applying snapshots should be recordable and replayable", () => { + const t1 = Task.create() + const t2 = Task.create() + const recorder = recordActions(t1) + expect(t1.done).toBe(false) + applySnapshot(t1, { done: true }) + expect(t1.done).toBe(true) + expect(recorder.actions).toEqual([ + { + name: "@APPLY_SNAPSHOT", + path: "", + args: [{ done: true }] + } + ]) + recorder.replay(t2) + expect(t2.done).toBe(true) +}) +// Complex actions +const Customer = types.model("Customer", { + id: types.identifierNumber, + name: types.string +}) +const Order = types + .model("Order", { + customer: types.maybeNull(types.reference(Customer)) + }) + .actions((self) => { + function setCustomer(customer: Instance) { + self.customer = customer + } + function noopSetCustomer(_: Instance) { + // noop + } + return { + setCustomer, + noopSetCustomer + } + }) +const OrderStore = types.model("OrderStore", { + customers: types.array(Customer), + orders: types.array(Order) +}) +function createTestStore() { + const store = OrderStore.create({ + customers: [{ id: 1, name: "Mattia" }], + orders: [ + { + customer: null + } + ] + }) + onAction(store, () => {}) + return store +} +test("it should not be possible to pass a complex object", () => { + const store = createTestStore() + const recorder = recordActions(store) + expect(store.customers[0].name).toBe("Mattia") + store.orders[0].setCustomer(store.customers[0]) + expect(store.orders[0].customer!.name).toBe("Mattia") + expect(store.orders[0].customer).toBe(store.customers[0]) + expect(getSnapshot(store)).toEqual({ + customers: [ + { + id: 1, + name: "Mattia" + } + ], + orders: [ + { + customer: 1 + } + ] + }) + expect(recorder.actions).toEqual([ + { + name: "setCustomer", + path: "/orders/0", + args: [{ $MST_UNSERIALIZABLE: true, type: "[MSTNode: Customer]" }] + } + ]) +}) +if (process.env.NODE_ENV !== "production") { + test("it should not be possible to set the wrong type", () => { + const store = createTestStore() + expect(() => { + store.orders[0].setCustomer(store.orders[0] as any) + }).toThrowError( + "Error while converting to `(reference(Customer) | null)`:\n\n " + + "value of type Order: is not assignable to type: `(reference(Customer) | null)`, expected an instance of `(reference(Customer) | null)` or a snapshot like `(reference(Customer) | null?)` instead." + ) // wrong type! + }) +} +test("it should not be possible to pass the element of another tree", () => { + const store1 = createTestStore() + const store2 = createTestStore() + const recorder = recordActions(store2) + store2.orders[0].setCustomer(store1.customers[0]) + expect(recorder.actions).toEqual([ + { + name: "setCustomer", + path: "/orders/0", + args: [ + { + $MST_UNSERIALIZABLE: true, + type: "[MSTNode: Customer]" + } + ] + } + ]) +}) +test("it should not be possible to pass an unserializable object", () => { + const store = createTestStore() + const circular = { a: null as any } + circular.a = circular + const recorder = recordActions(store) + store.orders[0].noopSetCustomer(circular as any) + store.orders[0].noopSetCustomer(Buffer.from("bla") as any) + + // fix for newer node versions, which include extra data on dev mode + if ( + recorder.actions[0].args![0].type.startsWith("TypeError: Converting circular structure to JSON") + ) { + recorder.actions[0].args![0].type = "TypeError: Converting circular structure to JSON" + } + + expect(recorder.actions).toEqual([ + { + args: [ + { + $MST_UNSERIALIZABLE: true, + type: "TypeError: Converting circular structure to JSON" + } + ], + name: "noopSetCustomer", + path: "/orders/0" + }, + { + args: [ + { + $MST_UNSERIALIZABLE: true, + type: "[object Buffer]" + } + ], + name: "noopSetCustomer", + path: "/orders/0" + } + ]) +}) +test("it should be possible to pass a complex plain object", () => { + const t1 = Task.create() + const t2 = Task.create() + const recorder = recordActions(t1) + ;(t1 as any).toggle({ bla: ["nuff", ["said"]] }) // nonsense, but serializable! + expect(recorder.actions).toEqual([ + { name: "toggle", path: "", args: [{ bla: ["nuff", ["said"]] }] } + ]) + recorder.replay(t2) + expect(t2.done).toBe(true) +}) +test("action should be bound", () => { + const task = Task.create() + const f = task.toggle + expect(f()).toBe(true) + expect(task.done).toBe(true) +}) +test("snapshot should be available and updated during an action", () => { + const Model = types + .model({ + x: types.number + }) + .actions((self) => { + function inc() { + self.x += 1 + const res = getSnapshot(self).x + self.x += 1 + return res + } + return { + inc + } + }) + const a = Model.create({ x: 2 }) + expect(a.inc()).toBe(3) + expect(a.x).toBe(4) + expect(getSnapshot(a).x).toBe(4) +}) + +test("indirectly called private functions should be able to modify state", () => { + const Model = types + .model({ + x: 3 + }) + .actions((self) => { + function incrementBy(delta: number) { + self.x += delta + } + return { + inc() { + incrementBy(1) + }, + dec() { + incrementBy(-1) + } + } + }) + const cnt = Model.create() + expect(cnt.x).toBe(3) + cnt.dec() + expect(cnt.x).toBe(2) + expect((cnt as any).incrementBy).toBe(undefined) +}) +test("volatile state survives reonciliation", () => { + const Model = types.model({ x: 3 }).actions((self) => { + let incrementor = 1 + return { + setIncrementor(value: number) { + incrementor = value + }, + inc() { + self.x += incrementor + } + } + }) + const Store = types.model({ + cnt: types.optional(Model, {}) + }) + const store = Store.create() + store.cnt.inc() + expect(store.cnt.x).toBe(4) + store.cnt.setIncrementor(3) + store.cnt.inc() + expect(store.cnt.x).toBe(7) + applySnapshot(store, { cnt: { x: 2 } }) + expect(store.cnt.x).toBe(2) + store.cnt.inc() + expect(store.cnt.x).toBe(5) // incrementor was not lost +}) +test("middleware events are correct", () => { + configure({ + useProxies: "never" + }) + + const A = types.model({}).actions((self) => ({ + a(x: number) { + return this.b(x * 2) + }, + b(y: number) { + return y + 1 + } + })) + const a = A.create() + const events: IMiddlewareEvent[] = [] + addMiddleware(a, function (call, next) { + events.push(call) + return next(call) + }) + a.a(7) + const event1 = { + args: [7], + context: {}, + id: process.env.NODE_ENV !== "production" ? 29 : 28, + name: "a", + parentId: 0, + rootId: process.env.NODE_ENV !== "production" ? 29 : 28, + allParentIds: [], + tree: {}, + type: "action", + parentEvent: undefined, + parentActionEvent: undefined + } + const event2 = { + args: [14], + context: {}, + id: process.env.NODE_ENV !== "production" ? 30 : 29, + name: "b", + parentId: process.env.NODE_ENV !== "production" ? 29 : 28, + rootId: process.env.NODE_ENV !== "production" ? 29 : 28, + allParentIds: [process.env.NODE_ENV !== "production" ? 29 : 28], + tree: {}, + type: "action", + parentEvent: event1, + parentActionEvent: event1 + } + expect(events).toEqual([event1, event2]) +}) + +test("actions are mockable", () => { + configure({ + useProxies: "never" + }) + + const M = types + .model() + .actions((self) => ({ + method(): number { + return 3 + } + })) + .views((self) => ({ + view(): number { + return 3 + } + })) + const m = M.create() + if (process.env.NODE_ENV === "production") { + expect(() => { + m.method = function () { + return 3 + } + }).toThrowError(TypeError) + expect(() => { + m.view = function () { + return 3 + } + }).toThrowError(TypeError) + } else { + m.method = function () { + return 4 + } + expect(m.method()).toBe(4) + m.view = function () { + return 4 + } + expect(m.view()).toBe(4) + } +}) + +test("after attach action should work correctly", () => { + const Todo = types + .model({ + title: "test" + }) + .actions((self) => ({ + remove() { + getRoot(self).remove(cast(self)) + } + })) + const S = types + .model({ + todos: types.array(Todo) + }) + .actions((self) => ({ + remove(todo: Instance) { + self.todos.remove(todo) + } + })) + + const s = S.create({ + todos: [{ title: "todo" }] + }) + const events: ISerializedActionCall[] = [] + onAction( + s, + (call) => { + events.push(call) + }, + true + ) + + s.todos[0].remove() + + expect(events).toEqual([ + { + args: [], + name: "remove", + path: "/todos/0" + } + ]) +}) diff --git a/__tests__/core/actionTrackingMiddleware2.test.ts b/__tests__/core/actionTrackingMiddleware2.test.ts new file mode 100644 index 000000000..cad16ed15 --- /dev/null +++ b/__tests__/core/actionTrackingMiddleware2.test.ts @@ -0,0 +1,432 @@ +import { + addMiddleware, + createActionTrackingMiddleware2, + types, + flow, + IActionTrackingMiddleware2Call +} from "../../src" + +function createTestMiddleware(m: any, actionName: string, value: number, calls: string[]) { + function checkCall(call: IActionTrackingMiddleware2Call) { + expect(call.name).toBe(actionName) + expect(call.args).toEqual([value]) + expect(call.context).toBe(m) + expect(call.env).toBe(call.id) + } + + const mware = createActionTrackingMiddleware2({ + filter(call) { + return call.name === actionName + }, + onStart(call) { + call.env = call.id // just to check env is copied properly down + calls.push(`${call.name} (${call.id}) - onStart`) + checkCall(call) + }, + onFinish(call, error) { + calls.push(`${call.name} (${call.id}) - onFinish (error: ${!!error})`) + checkCall(call) + } + }) + + addMiddleware(m, mware, false) +} + +async function doTest(m: any, mode: "success" | "fail") { + const calls: string[] = [] + + createTestMiddleware(m, "setX", 10, calls) + createTestMiddleware(m, "setY", 9, calls) + + try { + await m.setZ(8) // -> setY(9) -> setX(10) + if (mode === "fail") { + fail("should have failed") + } + } catch (e) { + if (mode === "fail") { + expect(e).toBe("error") + } else { + throw e + // fail("should have succeeded") + } + } + + return calls +} + +async function syncTest(mode: "success" | "fail") { + const M = types + .model({ + x: 1, + y: 2, + z: 3 + }) + .actions((self) => ({ + setX(v: number) { + self.x = v + if (mode === "fail") { + throw "error" + } + }, + setY(v: number) { + self.y = v + this.setX(v + 1) + }, + setZ(v: number) { + self.z = v + this.setY(v + 1) + } + })) + + const m = M.create() + + const calls = await doTest(m, mode) + + if (mode === "success") { + expect(calls).toEqual([ + "setY (2) - onStart", + "setX (3) - onStart", + "setX (3) - onFinish (error: false)", + "setY (2) - onFinish (error: false)" + ]) + } else { + expect(calls).toEqual([ + "setY (5) - onStart", + "setX (6) - onStart", + "setX (6) - onFinish (error: true)", + "setY (5) - onFinish (error: true)" + ]) + } +} + +test("sync action", async () => { + await syncTest("success") + await syncTest("fail") +}) + +async function flowTest(mode: "success" | "fail") { + const _subFlow = flow(function* subFlow() { + yield Promise.resolve() + }) + + const M = types + .model({ + x: 1, + y: 2, + z: 3 + }) + .actions((self) => ({ + setX: flow(function* flowSetX(v: number) { + yield Promise.resolve() + yield _subFlow() + self.x = v + if (mode === "fail") { + throw "error" + } + }), + setY: flow(function* flowSetY(v: number) { + self.y = v + yield (self as any).setX(v + 1) + }), + setZ: flow(function* flowSetZ(v: number) { + self.z = v + yield (self as any).setY(v + 1) + }) + })) + + const m = M.create() + + const calls = await doTest(m, mode) + + if (mode === "success") { + expect(calls).toEqual([ + "setY (9) - onStart", + "setX (11) - onStart", + "setX (11) - onFinish (error: false)", + "setY (9) - onFinish (error: false)" + ]) + } else { + expect(calls).toEqual([ + "setY (16) - onStart", + "setX (18) - onStart", + "setX (18) - onFinish (error: true)", + "setY (16) - onFinish (error: true)" + ]) + } +} + +test("flow action", async () => { + await flowTest("success") + await flowTest("fail") +}) + +test("#1250", async () => { + const M = types + .model({ + x: 0, + y: 0 + }) + .actions((self) => ({ + setX: flow(function* () { + self.x = 10 + yield new Promise((resolve) => setTimeout(resolve, 1000)) + }), + setY() { + self.y = 10 + } + })) + + const calls: string[] = [] + const mware = createActionTrackingMiddleware2({ + filter(call) { + calls.push(`${call.name} (${call.id}) <- (${call.parentCall && call.parentCall.id}) - filter`) + return true + }, + onStart(call) { + calls.push( + `${call.name} (${call.id}) <- (${call.parentCall && call.parentCall.id}) - onStart` + ) + }, + onFinish(call, error) { + calls.push( + `${call.name} (${call.id}) <- (${ + call.parentCall && call.parentCall.id + }) - onFinish (error: ${!!error})` + ) + } + }) + + const model = M.create({}) + + addMiddleware(model, mware, false) + + expect(model.x).toBe(0) + expect(model.y).toBe(0) + expect(calls).toEqual([]) + + const p = model.setX() + expect(model.x).toBe(10) + expect(model.y).toBe(0) + expect(calls).toEqual(["setX (21) <- (undefined) - filter", "setX (21) <- (undefined) - onStart"]) + calls.length = 0 + + await new Promise((r) => + setTimeout(() => { + model.setY() + r() + }, 500) + ) + expect(model.x).toBe(10) + expect(model.y).toBe(10) + expect(calls).toEqual([ + "setY (23) <- (undefined) - filter", + "setY (23) <- (undefined) - onStart", + "setY (23) <- (undefined) - onFinish (error: false)" + ]) + calls.length = 0 + + await p + expect(model.x).toBe(10) + expect(model.y).toBe(10) + expect(calls).toEqual(["setX (21) <- (undefined) - onFinish (error: false)"]) + calls.length = 0 +}) + +/** + * Test that when createActionTrackingMiddleware2 is called with valid hooks and a synchronous action, it runs onStart and onFinish hooks. + */ +test("successful execution", () => { + const M = types.model({}).actions((self) => ({ + test() {} + })) + + const calls: string[] = [] + + const mware = createActionTrackingMiddleware2({ + filter(call) { + calls.push(`${call.name} - filter`) + return true + }, + onStart(call) { + calls.push(`${call.name} - onStart`) + }, + onFinish(call, error) { + calls.push(`${call.name} - onFinish (error: ${!!error})`) + } + }) + + const model = M.create({}) + addMiddleware(model, mware, false) + + model.test() + + expect(calls).toEqual(["test - filter", "test - onStart", "test - onFinish (error: false)"]) +}) + +/** + * Test that when createActionTrackingMiddleware2 is called with valid hooks and an asynchronous action, it runs onStart and onFinish hooks. + */ +test("successful execution with async action", async () => { + const M = types.model({}).actions((self) => ({ + async test() {} + })) + + const calls: string[] = [] + + const mware = createActionTrackingMiddleware2({ + filter(call) { + calls.push(`${call.name} - filter`) + return true + }, + onStart(call) { + calls.push(`${call.name} - onStart`) + }, + onFinish(call, error) { + calls.push(`${call.name} - onFinish (error: ${!!error})`) + } + }) + + const model = M.create({}) + addMiddleware(model, mware, false) + + await model.test() + + expect(calls).toEqual(["test - filter", "test - onStart", "test - onFinish (error: false)"]) +}) + +/** + * Test the filter for createActionTrackingMiddleware2 when it passes, and when it fails. + */ +describe("filtering", () => { + /** + * Test that when the filter returns true, the action is tracked. We check + * this by checking that the onStart and onFinish hooks are called for `runThisOne`, + * which is the name provided to the `filter` function. + */ + it("calls onStart and onFinish hooks for actions that pass the filter", () => { + const M = types.model({}).actions((self) => ({ + trackThisOne() {}, + doNotTrackThisOne() {} + })) + + const calls: string[] = [] + + const mware = createActionTrackingMiddleware2({ + filter(call) { + return call.name === "trackThisOne" + }, + onStart(call) { + calls.push(`${call.name} - onStart`) + }, + onFinish(call, error) { + calls.push(`${call.name} - onFinish (error: ${!!error})`) + } + }) + + const model = M.create({}) + addMiddleware(model, mware, false) + + model.trackThisOne() + // We call this action to prove that it is not tracked since it fails - there's also a test for this below. + model.doNotTrackThisOne() + + expect(calls).toEqual(["trackThisOne - onStart", "trackThisOne - onFinish (error: false)"]) + }) + /** + * Test that when the filter returns false, the action is not tracked. We check + * this by checking that the onStart and onFinish hooks are not called for `doNotTrackThisOne`, + */ + it("does not call onStart and onFinish hooks for actions that do not pass the filter", () => { + const M = types.model({}).actions((self) => ({ + trackThisOne() {}, + doNotTrackThisOne() {} + })) + + const calls: string[] = [] + + const mware = createActionTrackingMiddleware2({ + filter(call) { + return call.name === "trackThisOne" + }, + onStart(call) { + calls.push(`${call.name} - onStart`) + }, + onFinish(call, error) { + calls.push(`${call.name} - onFinish (error: ${!!error})`) + } + }) + + const model = M.create({}) + addMiddleware(model, mware, false) + + model.doNotTrackThisOne() + + expect(calls).toEqual([]) + }) +}) + +/** + * Test that parent actions and child actions have the expected order of operations - + * if we had an action `a` that called an action `b1`, then `b2` inside `a`, the flow would be: + * + * - `filter(a)` + * - `onStart(a)` + * - `filter(b1)` + * - `onStart(b1)` + * - `onFinish(b1)` + * - `filter(b2)` + * - `onStart(b2)` + * - `onFinish(b2)` + * - `onFinish(a)` + * + * See https://mobx-state-tree.js.org/API/#createactiontrackingmiddleware2 + */ +describe("nested actions", () => { + test("complete in the expected recursive order", () => { + const M = types + .model({}) + .actions((self) => ({ + childAction1() {}, + childAction2() {} + })) + .actions((self) => ({ + parentAction() { + self.childAction1() + self.childAction2() + } + })) + + const calls: string[] = [] + + const mware = createActionTrackingMiddleware2({ + filter(call) { + calls.push(`${call.name} - filter`) + return true + }, + onStart(call) { + calls.push(`${call.name} - onStart`) + }, + onFinish(call, error) { + calls.push(`${call.name} - onFinish (error: ${!!error})`) + } + }) + + const model = M.create({}) + addMiddleware(model, mware, false) + + model.parentAction() + + expect(calls).toEqual([ + "parentAction - filter", + "parentAction - onStart", + "childAction1 - filter", + "childAction1 - onStart", + "childAction1 - onFinish (error: false)", + "childAction2 - filter", + "childAction2 - onStart", + "childAction2 - onFinish (error: false)", + "parentAction - onFinish (error: false)" + ]) + }) +}) diff --git a/packages/mobx-state-tree/__tests__/core/api.test.ts b/__tests__/core/api.test.ts similarity index 70% rename from packages/mobx-state-tree/__tests__/core/api.test.ts rename to __tests__/core/api.test.ts index 14eb78aef..acce22763 100644 --- a/packages/mobx-state-tree/__tests__/core/api.test.ts +++ b/__tests__/core/api.test.ts @@ -2,7 +2,7 @@ import * as mst from "../../src" import { readFileSync } from "fs" function stringToArray(s: string): string[] { - return s.split(",").map((str) => str.trim()) + return s.split(",").map((str) => str.trim()) } const METHODS_AND_INTERNAL_TYPES = stringToArray(` @@ -125,35 +125,35 @@ const TYPES = stringToArray(` `) test("correct api exposed", () => { - expect( - Object.keys(mst) - .sort() - .filter((key) => (mst as any)[key] !== undefined) // filter out interfaces - .filter((s) => !DEPRECATED_METHODS_AND_INTERNAL_TYPES.includes(s)) - ).toEqual([...METHODS, ...INTERNAL_TYPES].sort()) + expect( + Object.keys(mst) + .sort() + .filter((key) => (mst as any)[key] !== undefined) // filter out interfaces + .filter((s) => !DEPRECATED_METHODS_AND_INTERNAL_TYPES.includes(s)) + ).toEqual([...METHODS, ...INTERNAL_TYPES].sort()) }) test("correct types exposed", () => { - expect(Object.keys(mst.types).sort()).toEqual(TYPES.sort()) + expect(Object.keys(mst.types).sort()).toEqual(TYPES.sort()) }) test("all methods mentioned in API docs", () => { - const apimd = readFileSync(__dirname + "/../../../../docs/API/index.md", "utf8") - const missing = TYPES.map((type) => "types." + type).filter( - (identifier) => apimd.indexOf(identifier) === -1 - ) - missing.push( - ...METHODS.filter((identifier) => apimd.indexOf("#" + identifier.toLowerCase()) === -1) - ) - expect(missing).toEqual(["types.lazy", "types"]) + const apimd = readFileSync(__dirname + "/../../docs/API/index.md", "utf8") + const missing = TYPES.map((type) => "types." + type).filter( + (identifier) => apimd.indexOf(identifier) === -1 + ) + missing.push( + ...METHODS.filter((identifier) => apimd.indexOf("#" + identifier.toLowerCase()) === -1) + ) + expect(missing).toEqual(["types.lazy", "types"]) }) test("only accepted dependencies", () => { - const validDeps: string[] = [] + const validDeps: string[] = [] - const deps = - JSON.parse(readFileSync(__dirname + "/../../package.json", "utf8")).dependencies || {} + const deps = + JSON.parse(readFileSync(__dirname + "/../../package.json", "utf8")).dependencies || {} - const depNames = Object.keys(deps) || [] - expect(depNames.sort()).toEqual(validDeps.sort()) + const depNames = Object.keys(deps) || [] + expect(depNames.sort()).toEqual(validDeps.sort()) }) diff --git a/__tests__/core/array.test.ts b/__tests__/core/array.test.ts new file mode 100644 index 000000000..0a81ffff2 --- /dev/null +++ b/__tests__/core/array.test.ts @@ -0,0 +1,569 @@ +import { + unprotect, + onSnapshot, + onPatch, + clone, + isAlive, + applyPatch, + getPath, + applySnapshot, + getSnapshot, + types, + IJsonPatch, + setLivelinessChecking, + detach, + cast +} from "../../src" +import { observable, autorun, configure } from "mobx" + +const createTestFactories = () => { + const ItemFactory = types.optional( + types.model({ + to: "world" + }), + {} + ) + const Factory = types.array(ItemFactory) + return { Factory, ItemFactory } +} +// === FACTORY TESTS === +test("it should create a factory", () => { + const { Factory } = createTestFactories() + expect(getSnapshot(Factory.create())).toEqual([]) +}) +test("it should succeed if not optional and no default provided", () => { + const Factory = types.array(types.string) + expect(getSnapshot(Factory.create())).toEqual([]) +}) +test("it should restore the state from the snapshot", () => { + configure({ + useProxies: "never" + }) + + const { Factory } = createTestFactories() + const instance = Factory.create([{ to: "universe" }]) + expect(getSnapshot(instance)).toEqual([{ to: "universe" }]) + expect("" + instance).toBe("AnonymousModel@/0") // just the normal to string +}) +// === SNAPSHOT TESTS === +test("it should emit snapshots", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let snapshots: typeof Factory.SnapshotType[] = [] + onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) + doc.push(ItemFactory.create()) + expect(snapshots).toEqual([[{ to: "world" }]]) +}) +test("it should apply snapshots", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applySnapshot(doc, [{ to: "universe" }]) + expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) +}) +test("it should return a snapshot", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.push(ItemFactory.create()) + expect(getSnapshot(doc)).toEqual([{ to: "world" }]) +}) +// === PATCHES TESTS === +test("it should emit add patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.push(ItemFactory.create({ to: "universe" })) + expect(patches).toEqual([{ op: "add", path: "/0", value: { to: "universe" } }]) +}) +test("it should apply an add patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, { op: "add", path: "/0", value: { to: "universe" } }) + expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) +}) +test("it should emit update patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.push(ItemFactory.create()) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc[0] = ItemFactory.create({ to: "universe" }) + expect(patches).toEqual([{ op: "replace", path: "/0", value: { to: "universe" } }]) +}) +test("it should apply an update patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, { op: "replace", path: "/0", value: { to: "universe" } }) + expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) +}) +test("it should emit remove patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.push(ItemFactory.create()) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.splice(0) + expect(patches).toEqual([{ op: "remove", path: "/0" }]) +}) +test("it should apply a remove patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.push(ItemFactory.create()) + doc.push(ItemFactory.create({ to: "universe" })) + applyPatch(doc, { op: "remove", path: "/0" }) + expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) +}) +test("it should apply patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, [ + { op: "add", path: "/0", value: { to: "mars" } }, + { op: "replace", path: "/0", value: { to: "universe" } } + ]) + expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) +}) +// === TYPE CHECKS === +test("it should check the type correctly", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + expect(Factory.is(doc)).toEqual(true) + expect(Factory.is([])).toEqual(true) + expect(Factory.is({})).toEqual(false) + expect(Factory.is([{ to: "mars" }])).toEqual(true) + expect(Factory.is([{ wrongKey: true }])).toEqual(true) + expect(Factory.is([{ to: true }])).toEqual(false) +}) +test("paths shoud remain correct when splicing", () => { + const Task = types.model("Task", { + done: false + }) + const store = types + .model({ + todos: types.array(Task) + }) + .create({ + todos: [{}] + }) + unprotect(store) + expect(store.todos.map(getPath)).toEqual(["/todos/0"]) + store.todos.push({}) + expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) + store.todos.unshift({}) + expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) + store.todos.splice(0, 2) + expect(store.todos.map(getPath)).toEqual(["/todos/0"]) + store.todos.splice(0, 1, {}, {}, {}) + expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) + store.todos.remove(store.todos[1]) + expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) +}) +test("items should be reconciled correctly when splicing - 1", () => { + configure({ + useProxies: "never" + }) + + const Task = types.model("Task", { + x: types.string + }) + const a = Task.create({ x: "a" }), + b = Task.create({ x: "b" }), + c = Task.create({ x: "c" }), + d = Task.create({ x: "d" }) + const store = types + .model({ + todos: types.array(Task) + }) + .create({ + todos: [a] + }) + unprotect(store) + expect(store.todos.slice()).toEqual([a]) + expect(isAlive(a)).toBe(true) + store.todos.push(b) + expect(store.todos.slice()).toEqual([a, b]) + store.todos.unshift(c) + expect(store.todos.slice()).toEqual([c, a, b]) + store.todos.splice(0, 2) + expect(store.todos.slice()).toEqual([b]) + expect(isAlive(a)).toBe(false) + expect(isAlive(b)).toBe(true) + expect(isAlive(c)).toBe(false) + + setLivelinessChecking("error") + expect(() => store.todos.splice(0, 1, a, c, d)).toThrowError( + "You are trying to read or write to an object that is no longer part of a state tree. (Object type: 'Task', Path upon death: '/todos/1', Subpath: '', Action: ''). Either detach nodes first, or don't use objects after removing / replacing them in the tree." + ) + store.todos.splice(0, 1, clone(a), clone(c), clone(d)) + expect(store.todos.map((_) => _.x)).toEqual(["a", "c", "d"]) +}) +test("items should be reconciled correctly when splicing - 2", () => { + const Task = types.model("Task", { + x: types.string + }) + const a = Task.create({ x: "a" }), + b = Task.create({ x: "b" }), + c = Task.create({ x: "c" }), + d = Task.create({ x: "d" }) + const store = types + .model({ + todos: types.array(Task) + }) + .create({ + todos: [a, b, c, d] + }) + unprotect(store) + store.todos.splice(2, 1, { x: "e" }, { x: "f" }) + // becomes, a, b, e, f, d + expect(store.todos.length).toBe(5) + expect(store.todos[0] === a).toBe(true) + expect(store.todos[1] === b).toBe(true) + expect(store.todos[2] !== c).toBe(true) + expect(store.todos[2].x).toBe("e") + expect(store.todos[3] !== d).toBe(true) + expect(store.todos[3].x).toBe("f") + expect(store.todos[4] === d).toBe(true) // preserved and moved + expect(store.todos[4].x).toBe("d") + expect(store.todos.map(getPath)).toEqual([ + "/todos/0", + "/todos/1", + "/todos/2", + "/todos/3", + "/todos/4" + ]) + store.todos.splice(1, 3, { x: "g" }) + // becomes a, g, d + expect(store.todos.length).toBe(3) + expect(store.todos[0] === a).toBe(true) + expect(store.todos[1].x).toBe("g") + expect(store.todos[2].x).toBe("d") + expect(store.todos[1] !== b).toBe(true) + expect(store.todos[2] === d).toBe(true) // still original d + expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) +}) +test("it should reconciliate keyed instances correctly", () => { + const Store = types.model({ + todos: types.optional( + types.array( + types.model("Task", { + id: types.identifier, + task: "", + done: false + }) + ), + [] + ) + }) + const store = Store.create({ + todos: [ + { id: "1", task: "coffee", done: false }, + { id: "2", task: "tea", done: false }, + { id: "3", task: "biscuit", done: false } + ] + }) + expect(store.todos.map((todo) => todo.task)).toEqual(["coffee", "tea", "biscuit"]) + expect(store.todos.map((todo) => todo.done)).toEqual([false, false, false]) + expect(store.todos.map((todo) => todo.id)).toEqual(["1", "2", "3"]) + const coffee = store.todos[0] + const tea = store.todos[1] + const biscuit = store.todos[2] + applySnapshot(store, { + todos: [ + { id: "2", task: "Tee", done: true }, + { id: "1", task: "coffee", done: true }, + { id: "4", task: "biscuit", done: false }, + { id: "5", task: "stuffz", done: false } + ] + }) + expect(store.todos.map((todo) => todo.task)).toEqual(["Tee", "coffee", "biscuit", "stuffz"]) + expect(store.todos.map((todo) => todo.done)).toEqual([true, true, false, false]) + expect(store.todos.map((todo) => todo.id)).toEqual(["2", "1", "4", "5"]) + expect(store.todos[0] === tea).toBe(true) + expect(store.todos[1] === coffee).toBe(true) + expect(store.todos[2] === biscuit).toBe(false) +}) +test("it correctly reconciliate when swapping", () => { + const Task = types.model("Task", {}) + const Store = types.model({ + todos: types.optional(types.array(Task), []) + }) + const s = Store.create() + unprotect(s) + const a = Task.create() + const b = Task.create() + s.todos.push(a, b) + s.todos.replace([b, a]) + expect(s.todos[0] === b).toBe(true) + expect(s.todos[1] === a).toBe(true) + expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) +}) +test("it correctly reconciliate when swapping using snapshots", () => { + const Task = types.model("Task", {}) + const Store = types.model({ + todos: types.array(Task) + }) + const s = Store.create() + unprotect(s) + const a = Task.create() + const b = Task.create() + s.todos.push(a, b) + s.todos.replace([getSnapshot(b), getSnapshot(a)]) + expect(s.todos[0] === b).toBe(true) + expect(s.todos[1] === a).toBe(true) + expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) + s.todos.push({}) + expect(s.todos[0] === b).toBe(true) + expect(s.todos[1] === a).toBe(true) + expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) +}) +test("it should not be allowed to add the same item twice to the same store", () => { + const Task = types.model("Task", {}) + const Store = types.model({ + todos: types.optional(types.array(Task), []) + }) + const s = Store.create() + unprotect(s) + const a = Task.create() + s.todos.push(a) + expect(() => { + s.todos.push(a) + }).toThrowError( + "Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/todos/1', but it lives already at '/todos/0'" + ) + const b = Task.create() + expect(() => { + s.todos.push(b, b) + }).toThrowError( + "Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/todos/2', but it lives already at '/todos/1'" + ) +}) +test("it should support observable arrays", () => { + const TestArray = types.array(types.number) + const testArray = TestArray.create(observable([1, 2])) + expect(testArray[0] === 1).toBe(true) + expect(testArray.length === 2).toBe(true) + expect(Array.isArray(testArray.slice())).toBe(true) +}) + +test("it should support observable arrays, array should be real when useProxies eq 'always'", () => { + configure({ + useProxies: "always" + }) + + const TestArray = types.array(types.number) + const testArray = TestArray.create(observable([1, 2])) + expect(testArray[0] === 1).toBe(true) + expect(testArray.length === 2).toBe(true) + expect(Array.isArray(testArray)).toBe(true) +}) + +test("it should support observable arrays, array should be not real when useProxies eq 'never'", () => { + configure({ + useProxies: "never" + }) + + const TestArray = types.array(types.number) + const testArray = TestArray.create(observable([1, 2])) + expect(testArray[0] === 1).toBe(true) + expect(testArray.length === 2).toBe(true) + expect(Array.isArray(testArray.slice())).toBe(true) + expect(Array.isArray(testArray)).toBe(false) +}) + +test("it should correctly handle re-adding of the same objects", () => { + const Store = types + .model("Task", { + objects: types.array(types.maybe(types.frozen())) + }) + .actions((self) => ({ + setObjects(objects: {}[]) { + self.objects.replace(objects) + } + })) + const store = Store.create({ + objects: [] + }) + expect(store.objects.slice()).toEqual([]) + const someObject = {} + store.setObjects([someObject]) + expect(store.objects.slice()).toEqual([someObject]) + store.setObjects([someObject]) + expect(store.objects.slice()).toEqual([someObject]) +}) +test("it should work correctly for splicing primitive array", () => { + const store = types.array(types.number).create([1, 2, 3]) + unprotect(store) + store.splice(0, 1) + expect(store.slice()).toEqual([2, 3]) + store.unshift(1) + expect(store.slice()).toEqual([1, 2, 3]) + store.replace([4, 5]) + expect(store.slice()).toEqual([4, 5]) + store.clear() + expect(store.slice()).toEqual([]) +}) +test("it should keep unchanged for structrual equalled snapshot", () => { + const Store = types.model({ + todos: types.array( + types.model("Task", { + id: types.identifier, + task: "", + done: false + }) + ), + numbers: types.array(types.number) + }) + const store = Store.create({ + todos: [ + { id: "1", task: "coffee", done: false }, + { id: "2", task: "tea", done: false }, + { id: "3", task: "biscuit", done: false } + ], + numbers: [1, 2, 3] + }) + + const values: boolean[][] = [] + autorun(() => { + values.push(store.todos.map((todo) => todo.done)) + }) + applySnapshot(store.todos, [ + { id: "1", task: "coffee", done: false }, + { id: "2", task: "tea", done: false }, + { id: "3", task: "biscuit", done: true } + ]) + applySnapshot(store.todos, [ + { id: "1", task: "coffee", done: false }, + { id: "2", task: "tea", done: false }, + { id: "3", task: "biscuit", done: true } + ]) + expect(values).toEqual([ + [false, false, false], + [false, false, true] + ]) + + const values1: number[][] = [] + autorun(() => { + values1.push(store.numbers.slice()) + }) + applySnapshot(store.numbers, [1, 2, 4]) + applySnapshot(store.numbers, [1, 2, 4]) + expect(values1).toEqual([ + [1, 2, 3], + [1, 2, 4] + ]) +}) + +// === OPERATIONS TESTS === +test("#1105 - it should return pop/shift'ed values for scalar arrays", () => { + const ScalarArray = types + .model({ + array: types.array(types.number) + }) + .actions((self) => { + return { + shift() { + return self.array.shift() + } + } + }) + + const test = ScalarArray.create({ array: [3, 5] }) + + expect(test.shift()).toEqual(3) + expect(test.shift()).toEqual(5) +}) + +test("it should return pop/shift'ed values for object arrays", () => { + const TestObject = types.model({ id: types.string }) + const ObjectArray = types + .model({ + array: types.array(TestObject) + }) + .actions((self) => { + return { + shift() { + return self.array.shift() + }, + pop() { + return self.array.pop() + } + } + }) + + const test = ObjectArray.create({ + array: [{ id: "foo" }, { id: "mid" }, { id: "bar" }] + }) + + const foo = test.shift()! + expect(isAlive(foo)).toBe(false) + const bar = test.pop()! + expect(isAlive(bar)).toBe(false) + + // we have to use clone or getSnapshot to access dead nodes data + expect(clone(foo)).toEqual({ id: "foo" }) + expect(getSnapshot(bar)).toEqual({ id: "bar" }) +}) + +test("#1173 - detaching an array should not eliminate its children", () => { + const M = types.model({}) + const AM = types.array(M) + const Store = types.model({ items: AM }) + const s = Store.create({ items: [{}, {}, {}] }) + const n0 = s.items[0] + + unprotect(s) + + const detachedItems = detach(s.items) + expect(s.items).not.toBe(detachedItems) + expect(s.items.length).toBe(0) + expect(detachedItems.length).toBe(3) + expect(detachedItems[0]).toBe(n0) +}) + +test("initializing an array instance from another array instance should end up in the same instance", () => { + const A = types.array(types.number) + const a1 = A.create([1, 2, 3]) + const a2 = A.create(a1) + expect(a1).toBe(a2) + expect(getSnapshot(a1)).toEqual([1, 2, 3]) +}) + +test("assigning filtered instances works", () => { + const Task = types.model("Task", { + done: false + }) + const store = types + .model({ + todos: types.array(Task) + }) + .actions((self) => ({ + clearFinishedTodos() { + self.todos = cast(self.todos.filter((todo) => !todo.done)) + } + })) + .create({ + todos: [{ done: true }, { done: false }, { done: true }] + }) + + expect(store.todos.length).toBe(3) + const done = store.todos.filter((t) => t.done) + const notDone = store.todos.filter((t) => !t.done) + expect(store.todos.every((t) => isAlive(t))) + store.clearFinishedTodos() + expect(store.todos.length).toBe(1) + expect(store.todos[0]).toBe(notDone[0]) + expect(done.every((t) => !isAlive(t))).toBe(true) + expect(notDone.every((t) => isAlive(t))).toBe(true) +}) + +test("#1676 - should accept read-only arrays", () => { + const ArrayType = types.array(types.string) + const data = ["foo", "bar"] as const + const instance = ArrayType.create(data) + expect(getSnapshot(instance)).toEqual(["foo", "bar"]) +}) diff --git a/__tests__/core/async.test.ts b/__tests__/core/async.test.ts new file mode 100644 index 000000000..ee8571cb0 --- /dev/null +++ b/__tests__/core/async.test.ts @@ -0,0 +1,436 @@ +import { configure, reaction } from "mobx" +import { + addMiddleware, + decorate, + destroy, + flow, + IMiddlewareEvent, + IMiddlewareEventType, + IMiddlewareHandler, + recordActions, + toGenerator, + // TODO: export IRawActionCall + toGeneratorFunction, + types +} from "../../src" + +function delay(time: number, value: TV, shouldThrow = false): Promise { + return new Promise((resolve, reject) => { + setTimeout(() => { + if (shouldThrow) reject(value) + else resolve(value) + }, time) + }) +} + +function testCoffeeTodo( + done: () => void, + generator: ( + self: any + ) => (str: string) => Generator, string | void | undefined, undefined>, + shouldError: boolean, + resultValue: string | undefined, + producedCoffees: any[] +) { + configure({ enforceActions: "observed" }) + const Todo = types + .model({ + title: "get coffee" + }) + .actions((self) => ({ + startFetch: flow(generator(self)) + })) + const events: IMiddlewareEvent[] = [] + const coffees: any[] = [] + const t1 = Todo.create({}) + addMiddleware(t1, (c, next) => { + events.push(c) + return next(c) + }) + reaction( + () => t1.title, + (coffee) => coffees.push(coffee) + ) + function handleResult(res: string | undefined | void) { + expect(res).toBe(resultValue) + expect(coffees).toEqual(producedCoffees) + const filtered = filterRelevantStuff(events) + expect(filtered).toMatchSnapshot() + configure({ enforceActions: "never" }) + done() + } + t1.startFetch("black").then( + (r) => { + expect(shouldError).toBe(false) + handleResult(r) + }, + (r) => { + expect(shouldError).toBe(true) + handleResult(r) + } + ) +} +test("flow happens in single ticks", (done) => { + const X = types + .model({ + y: 1 + }) + .actions((self) => ({ + p: flow(function* () { + self.y++ + self.y++ + yield delay(1, true, false) + self.y++ + self.y++ + }) + })) + const x = X.create() + const values: number[] = [] + reaction( + () => x.y, + (v) => values.push(v) + ) + x.p().then(() => { + expect(x.y).toBe(5) + expect(values).toEqual([3, 5]) + done() + }) +}) +test("can handle async actions", (done) => { + testCoffeeTodo( + done, + (self) => + function* fetchData(kind: string) { + self.title = "getting coffee " + kind + self.title = yield delay(100, "drinking coffee") + return "awake" + }, + false, + "awake", + ["getting coffee black", "drinking coffee"] + ) +}) +test("can handle erroring actions", (done) => { + testCoffeeTodo( + done, + (self) => + function* fetchData(kind: string) { + throw kind + }, + true, + "black", + [] + ) +}) +test("can handle try catch", (t) => { + testCoffeeTodo( + t, + (self) => + function* fetchData(kind: string) { + try { + yield delay(10, "tea", true) + return undefined + } catch (e) { + self.title = e + return "biscuit" + } + }, + false, + "biscuit", + ["tea"] + ) +}) +test("empty sequence works", (t) => { + testCoffeeTodo(t, () => function* fetchData(kind: string) {}, false, undefined, []) +}) +test("can handle throw from yielded promise works", (t) => { + testCoffeeTodo( + t, + () => + function* fetchData(kind: string) { + yield delay(10, "x", true) + }, + true, + "x", + [] + ) +}) +test("typings", (done) => { + const M = types.model({ title: types.string }).actions((self) => { + function* a(x: string) { + yield delay(10, "x", false) + self.title = "7" + return 23 + } + // tslint:disable-next-line:no-shadowed-variable + const b = flow(function* b(x: string) { + yield delay(10, "x", false) + self.title = "7" + return 24 + }) + return { a: flow(a), b } + }) + const m1 = M.create({ title: "test " }) + const resA = m1.a("z") + const resB = m1.b("z") + Promise.all([resA, resB]).then(([x1, x2]) => { + expect(x1).toBe(23) + expect(x2).toBe(24) + done() + }) +}) +test("typings", (done) => { + const M = types.model({ title: types.string }).actions((self) => { + function* a(x: string) { + yield delay(10, "x", false) + self.title = "7" + return 23 + } + // tslint:disable-next-line:no-shadowed-variable + const b = flow(function* b(x: string) { + yield delay(10, "x", false) + self.title = "7" + return 24 + }) + return { a: flow(a), b } + }) + const m1 = M.create({ title: "test " }) + const resA = m1.a("z") + const resB = m1.b("z") + Promise.all([resA, resB]).then(([x1, x2]) => { + expect(x1).toBe(23) + expect(x2).toBe(24) + done() + }) +}) +test("recordActions should only emit invocation", (done) => { + let calls = 0 + const M = types + .model({ + title: types.string + }) + .actions((self) => { + function* a(x: string) { + yield delay(10, "x", false) + calls++ + return 23 + } + return { + a: flow(a) + } + }) + const m1 = M.create({ title: "test " }) + const recorder = recordActions(m1) + m1.a("x").then(() => { + recorder.stop() + expect(recorder.actions).toEqual([ + { + args: ["x"], + name: "a", + path: "" + } + ]) + expect(calls).toBe(1) + recorder.replay(m1) + setTimeout(() => { + expect(calls).toBe(2) + done() + }, 50) + }) +}) +test("can handle nested async actions", (t) => { + // tslint:disable-next-line:no-shadowed-variable + const uppercase = flow(function* uppercase(value: string) { + const res = yield delay(20, value.toUpperCase()) + return res + }) + testCoffeeTodo( + t, + (self) => + function* fetchData(kind: string) { + self.title = yield uppercase("drinking " + kind) + return self.title + }, + false, + "DRINKING BLACK", + ["DRINKING BLACK"] + ) +}) +test("can handle nested async actions when using decorate", (done) => { + const events: [IMiddlewareEventType, string][] = [] + const middleware: IMiddlewareHandler = (call, next) => { + events.push([call.type, call.name]) + return next(call) + } + // tslint:disable-next-line:no-shadowed-variable + const uppercase = flow(function* uppercase(value: string) { + const res = yield delay(20, value.toUpperCase()) + return res + }) + const Todo = types.model({}).actions((self) => { + // tslint:disable-next-line:no-shadowed-variable + const act = flow(function* act(value: string) { + return yield uppercase(value) + }) + return { act: decorate(middleware, act) } + }) + Todo.create() + .act("x") + .then((res) => { + expect(res).toBe("X") + expect(events).toEqual([ + ["action", "act"], + ["flow_spawn", "act"], + ["flow_resume", "act"], + ["flow_resume", "act"], + ["flow_return", "act"] + ]) + done() + }) +}) + +test("flow gain back control when node become not alive during yield", async () => { + expect.assertions(2) + const rejectError = new Error("Reject Error") + const MyModel = types.model({}).actions(() => { + return { + doAction() { + return flow(function* () { + try { + yield delay(20, "").then(() => Promise.reject(rejectError)) + } catch (e) { + expect(e).toEqual(rejectError) + throw e + } + })() + } + } + }) + + const m = MyModel.create({}) + const p = m.doAction() + destroy(m) + try { + await p + } catch (e) { + expect(e).toEqual(rejectError) + } +}) + +function filterRelevantStuff(stuff: IMiddlewareEvent[]) { + return stuff.map((x: any) => { + delete x.context + delete x.tree + return x + }) +} + +test("flow typings", async () => { + const promise = Promise.resolve() + + const M = types.model({ x: 5 }).actions((self) => ({ + // should be () => Promise + voidToVoid: flow(function* () { + yield promise + }), // should be (val: number) => Promise + numberToNumber: flow(function* (val: number) { + yield promise + return val + }), // should be () => Promise + voidToNumber: flow(function* () { + yield promise + return Promise.resolve(2) + }) + })) + + const m = M.create() + + // these should compile + const a: void = await m.voidToVoid() + expect(a).toBe(undefined) + const b: number = await m.numberToNumber(4) + expect(b).toBe(4) + const c: number = await m.voidToNumber() + expect(c).toBe(2) + await m.voidToNumber().then((d) => { + const _d: number = d + expect(_d).toBe(2) + }) +}) + +/** + * Detect explicit `any` type. + * https://stackoverflow.com/a/55541672/4289902 + */ +type IfAny = 0 extends 1 & T ? Y : N + +/** + * Ensure that the type of the passed value is of the expected type, and is NOT the TypeScript `any` type + */ +function ensureNotAnyType(value: IfAny) {} + +test("yield* typings for toGeneratorFunction", async () => { + const voidPromise = () => Promise.resolve() + const numberPromise = () => Promise.resolve(7) + const stringWithArgsPromise = (input1: string, input2: boolean) => Promise.resolve("test-result") + + const voidGen = toGeneratorFunction(voidPromise) + const numberGen = toGeneratorFunction(numberPromise) + const stringWithArgsGen = toGeneratorFunction(stringWithArgsPromise) + + const M = types.model({ x: 5 }).actions((self) => { + function* testAction() { + const voidResult = yield* voidGen() + ensureNotAnyType(voidResult) + + const numberResult = yield* numberGen() + ensureNotAnyType(numberResult) + + const stringResult = yield* stringWithArgsGen("input", true) + ensureNotAnyType(stringResult) + + return stringResult + } + + return { + testAction: flow(testAction) + } + }) + + const m = M.create() + + const result = await m.testAction() + ensureNotAnyType(result) + expect(result).toBe("test-result") +}) + +test("yield* typings for toGenerator", async () => { + const voidPromise = () => Promise.resolve() + const numberPromise = () => Promise.resolve(7) + const stringWithArgsPromise = (input1: string, input2: boolean) => Promise.resolve("test-result") + + const M = types.model({ x: 5 }).actions((self) => { + function* testAction() { + const voidResult = yield* toGenerator(voidPromise()) + ensureNotAnyType(voidResult) + + const numberResult = yield* toGenerator(numberPromise()) + ensureNotAnyType(numberResult) + + const stringResult = yield* toGenerator(stringWithArgsPromise("input", true)) + ensureNotAnyType(stringResult) + + return stringResult + } + + return { + testAction: flow(testAction) + } + }) + + const m = M.create() + + const result = await m.testAction() + ensureNotAnyType(result) + expect(result).toBe("test-result") +}) diff --git a/__tests__/core/boxes-store.test.ts b/__tests__/core/boxes-store.test.ts new file mode 100644 index 000000000..c5d0473ce --- /dev/null +++ b/__tests__/core/boxes-store.test.ts @@ -0,0 +1,164 @@ +import { values } from "mobx" +import { + types, + getParent, + hasParent, + recordPatches, + unprotect, + getSnapshot, + Instance +} from "../../src" + +export const Box = types + .model("Box", { + id: types.identifier, + name: "", + x: 0, + y: 0 + }) + .views((self) => ({ + get width() { + return self.name.length * 15 + }, + get isSelected(): boolean { + if (!hasParent(self)) return false + return getParent(getParent(self)).selection === self + } + })) + .actions((self) => { + function move(dx: number, dy: number) { + self.x += dx + self.y += dy + } + function setName(newName: string) { + self.name = newName + } + return { + move, + setName + } + }) +export const Arrow = types.model("Arrow", { + id: types.identifier, + from: types.reference(Box), + to: types.reference(Box) +}) +export const Store = types + .model("Store", { + boxes: types.map(Box), + arrows: types.array(Arrow), + selection: types.reference(Box) + }) + .actions((self) => { + function afterCreate() { + unprotect(self) + } + function addBox(id: string, name: string, x: number, y: number) { + const box = Box.create({ name, x, y, id }) + self.boxes.put(box) + return box + } + function addArrow(id: string, from: string, to: string) { + self.arrows.push(Arrow.create({ id, from, to })) + } + function setSelection(selection: Instance) { + self.selection = selection + } + function createBox( + id: string, + name: string, + x: number, + y: number, + source: Instance | null | undefined, + arrowId: string | null + ) { + const box = addBox(id, name, x, y) + setSelection(box) + if (source) addArrow(arrowId!, source.id, box.id) + } + return { + afterCreate, + addBox, + addArrow, + setSelection, + createBox + } + }) +function createStore() { + return Store.create({ + boxes: { + cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, + aa: { id: "aa", name: "Bratislava", x: 650, y: 300 } + }, + arrows: [{ id: "dd", from: "cc", to: "aa" }], + selection: "aa" + }) +} +test("store is deserialized correctly", () => { + const s = createStore() + expect(s.boxes.size).toBe(2) + expect(s.arrows.length).toBe(1) + expect(s.selection === s.boxes.get("aa")).toBe(true) + expect(s.arrows[0].from.name).toBe("Rotterdam") + expect(s.arrows[0].to.name).toBe("Bratislava") + expect(values(s.boxes).map((b) => b.isSelected)).toEqual([false, true]) +}) +test("store emits correct patch paths", () => { + const s = createStore() + const recorder1 = recordPatches(s) + const recorder2 = recordPatches(s.boxes) + const recorder3 = recordPatches(s.boxes.get("cc")!) + s.arrows[0].from.x += 117 + expect(recorder1.patches).toEqual([{ op: "replace", path: "/boxes/cc/x", value: 217 }]) + expect(recorder2.patches).toEqual([{ op: "replace", path: "/cc/x", value: 217 }]) + expect(recorder3.patches).toEqual([{ op: "replace", path: "/x", value: 217 }]) +}) +test("box operations works correctly", () => { + const s = createStore() + s.createBox("a", "A", 0, 0, null, null) + s.createBox("b", "B", 100, 100, s.boxes.get("aa"), "aa2b") + expect(getSnapshot(s)).toEqual({ + boxes: { + cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, + aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, + a: { id: "a", name: "A", x: 0, y: 0 }, + b: { id: "b", name: "B", x: 100, y: 100 } + }, + arrows: [ + { id: "dd", from: "cc", to: "aa" }, + { id: "aa2b", from: "aa", to: "b" } + ], + selection: "b" + }) + s.boxes.get("a")!.setName("I'm groot") + expect(getSnapshot(s)).toEqual({ + boxes: { + cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, + aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, + a: { id: "a", name: "I'm groot", x: 0, y: 0 }, + b: { id: "b", name: "B", x: 100, y: 100 } + }, + arrows: [ + { id: "dd", from: "cc", to: "aa" }, + { id: "aa2b", from: "aa", to: "b" } + ], + selection: "b" + }) + expect(JSON.stringify(s)).toEqual(JSON.stringify(getSnapshot(s))) + s.boxes.get("a")!.move(50, 50) + expect(getSnapshot(s)).toEqual({ + boxes: { + cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, + aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, + a: { id: "a", name: "I'm groot", x: 50, y: 50 }, + b: { id: "b", name: "B", x: 100, y: 100 } + }, + arrows: [ + { id: "dd", from: "cc", to: "aa" }, + { id: "aa2b", from: "aa", to: "b" } + ], + selection: "b" + }) + expect(s.boxes.get("b")!.width).toBe(15) + expect(Box.create({ id: "hello" }).isSelected).toBe(false) +}) diff --git a/__tests__/core/circular1.test.ts b/__tests__/core/circular1.test.ts new file mode 100644 index 000000000..0844de2d6 --- /dev/null +++ b/__tests__/core/circular1.test.ts @@ -0,0 +1,25 @@ +import { types } from "../../src" +import { LateTodo2, LateStore2 } from "./circular2.test" +// combine function hosting with types.late to support circular refs between files! +export function LateStore1() { + return types.model({ + todo: types.late(LateTodo2) + }) +} +export function LateTodo1() { + return types.model({ + done: types.boolean + }) +} +test("circular test 1 should work", () => { + const Store1 = types.late(LateStore1) + const Store2 = types.late(LateStore2) + expect(Store1.is({})).toBe(false) + expect(Store1.is({ todo: { done: true } })).toBe(true) + const s1 = Store1.create({ todo: { done: true } }) + expect(s1.todo.done).toBe(true) + expect(Store2.is({})).toBe(false) + expect(Store2.is({ todo: { done: true } })).toBe(true) + const s2 = Store2.create({ todo: { done: true } }) + expect(s2.todo.done).toBe(true) +}) diff --git a/__tests__/core/circular2.test.ts b/__tests__/core/circular2.test.ts new file mode 100644 index 000000000..1e071ea9c --- /dev/null +++ b/__tests__/core/circular2.test.ts @@ -0,0 +1,25 @@ +import { types } from "../../src" +import { LateTodo1, LateStore1 } from "./circular1.test" +// combine function hosting with types.late to support circular refs between files! +export function LateTodo2() { + return types.model({ + done: types.boolean + }) +} +export function LateStore2() { + return types.model({ + todo: types.late(LateTodo1) + }) +} +test("circular test 2 should work", () => { + const Store1 = types.late(LateStore1) + const Store2 = types.late(LateStore2) + expect(Store1.is({})).toBe(false) + expect(Store1.is({ todo: { done: true } })).toBe(true) + const s1 = Store1.create({ todo: { done: true } }) + expect(s1.todo.done).toBe(true) + expect(Store2.is({})).toBe(false) + expect(Store2.is({ todo: { done: true } })).toBe(true) + const s2 = Store2.create({ todo: { done: true } }) + expect(s2.todo.done).toBe(true) +}) diff --git a/__tests__/core/custom-type.test.ts b/__tests__/core/custom-type.test.ts new file mode 100644 index 000000000..0622d4247 --- /dev/null +++ b/__tests__/core/custom-type.test.ts @@ -0,0 +1,204 @@ +import { + types, + recordPatches, + onSnapshot, + unprotect, + applySnapshot, + applyPatch, + SnapshotOut +} from "../../src" + +class Decimal { + public number: number + public fraction: number + + constructor(value: string) { + const parts = value.split(".") + this.number = Number(parts[0]) + this.fraction = Number(parts[1]) + } + + toNumber() { + return this.number + Number("0." + this.fraction) + } + + toString() { + return `${this.number}.${this.fraction}` + } +} + +{ + const DecimalPrimitive = types.custom({ + name: "Decimal", + fromSnapshot(value: string, env: any) { + if (env && env.test) env.test(value) + return new Decimal(value) + }, + toSnapshot(value: Decimal) { + return value.toString() + }, + isTargetType(value: string | Decimal): value is Decimal { + return value instanceof Decimal + }, + getValidationMessage(value: string): string { + if (/^-?\d+\.\d+$/.test(value)) return "" // OK + return `'${value}' doesn't look like a valid decimal number` + } + }) + + const Wallet = types.model({ + balance: DecimalPrimitive, + lastTransaction: types.maybeNull(DecimalPrimitive) + }) + + test("it should allow for custom primitive types", () => { + const w1 = Wallet.create({ + balance: new Decimal("2.5") + }) + + expect(w1.balance.number).toBe(2) + expect(w1.balance.fraction).toBe(5) + + const w2 = Wallet.create({ balance: "3.5" }) + expect(w2.balance.number).toBe(3) + expect(w2.balance.fraction).toBe(5) + + if (process.env.NODE_ENV !== "production") + expect(() => Wallet.create({ balance: "two point one" })).toThrow( + "(Invalid value for type 'Decimal': 'two point one' doesn't look like a valid decimal number)" + ) + }) + + // test reassignment / reconcilation / conversion works + test("reassignments will work", () => { + const w1 = Wallet.create({ balance: "2.5" }) + unprotect(w1) + + const p = recordPatches(w1) + const snapshots: SnapshotOut[] = [] + onSnapshot(w1, (s) => { + snapshots.push(s) + }) + + const b1 = w1.balance + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = "2.5" as any // TODO: make cast work with custom types + expect(b1).toBeInstanceOf(Decimal) + expect(w1.balance).toBe(b1) // reconciled + + w1.balance = new Decimal("2.5") // not reconciling! // TODO: introduce custom hook for that? + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = new Decimal("3.5") + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = "4.5" as any + expect(b1).toBeInstanceOf(Decimal) + + w1.lastTransaction = b1 + expect(w1.lastTransaction).toBe(b1) + + w1.lastTransaction = null + expect(w1.lastTransaction).toBe(null) + + // patches & snapshots + expect(snapshots).toMatchSnapshot() + p.stop() + expect(p.patches).toMatchSnapshot() + }) + + test("passes environment to fromSnapshot", () => { + const env = { test: jest.fn() } + Wallet.create({ balance: "3.0" }, env) + expect(env.test).toBeCalledWith("3.0") + }) +} + +{ + test("complex representation", () => {}) + + const DecimalTuple = types.custom<[number, number], Decimal>({ + name: "DecimalTuple", + fromSnapshot(value: [number, number]) { + return new Decimal(value[0] + "." + value[1]) + }, + toSnapshot(value: Decimal) { + return [value.number, value.fraction] + }, + isTargetType(value: [number, number] | Decimal): value is Decimal { + return value instanceof Decimal + }, + getValidationMessage(value: [number, number]): string { + if (Array.isArray(value) && value.length === 2) return "" // OK + return `'${JSON.stringify(value)}' doesn't look like a valid decimal number` + } + }) + + const Wallet = types.model({ balance: DecimalTuple }) + + test("it should allow for complex custom primitive types", () => { + const w1 = Wallet.create({ + balance: new Decimal("2.5") + }) + + expect(w1.balance.number).toBe(2) + expect(w1.balance.fraction).toBe(5) + + const w2 = Wallet.create({ balance: [3, 5] }) + expect(w2.balance.number).toBe(3) + expect(w2.balance.fraction).toBe(5) + + if (process.env.NODE_ENV !== "production") + expect(() => Wallet.create({ balance: "two point one" } as any)).toThrow( + "(Invalid value for type 'DecimalTuple': '\"two point one\"' doesn't look like a valid decimal number)" + ) + }) + + // test reassignment / reconcilation / conversion works + test("complex reassignments will work", () => { + const w1 = Wallet.create({ balance: [2, 5] }) + unprotect(w1) + + const p = recordPatches(w1) + const snapshots: SnapshotOut[] = [] + onSnapshot(w1, (s) => { + snapshots.push(s) + }) + + const b1 = w1.balance + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = [2, 5] as any + expect(b1).toBeInstanceOf(Decimal) + expect(w1.balance).not.toBe(b1) // not reconciled, balance is not deep equaled (TODO: future feature?) + + w1.balance = new Decimal("2.5") // not reconciling! + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = new Decimal("3.5") + expect(b1).toBeInstanceOf(Decimal) + + w1.balance = [4, 5] as any + expect(b1).toBeInstanceOf(Decimal) + + // patches & snapshots + expect(snapshots).toMatchSnapshot() + p.stop() + expect(p.patches).toMatchSnapshot() + }) + + test("can apply snapshot and patch", () => { + const w1 = Wallet.create({ balance: [3, 0] }) + applySnapshot(w1, { balance: [4, 5] }) + expect(w1.balance).toBeInstanceOf(Decimal) + expect(w1.balance.toString()).toBe("4.5") + + applyPatch(w1, { + op: "replace", + path: "/balance", + value: [5, 0] + }) + expect(w1.balance.toString()).toBe("5.0") + }) +} diff --git a/__tests__/core/deprecated.test.ts b/__tests__/core/deprecated.test.ts new file mode 100644 index 000000000..ef5d6d60c --- /dev/null +++ b/__tests__/core/deprecated.test.ts @@ -0,0 +1,39 @@ +import { deprecated } from "../../src/utils" +import { flow, createFlowSpawner } from "../../src/core/flow" +import { process as mstProcess, createProcessSpawner } from "../../src/core/process" + +function createDeprecationListener() { + // clear previous deprecation dedupe keys + deprecated.ids = {} + // save console.warn native implementation + const originalWarn = console.warn + // create spy to track warning call + const spyWarn = (console.warn = jest.fn()) + // return callback to check if warn was called properly + return function isDeprecated() { + // replace original implementation + console.warn = originalWarn + // test for correct log message, if in development + if (process.env.NODE_ENV !== "production") { + expect(spyWarn).toHaveBeenCalledTimes(1) + expect(spyWarn.mock.calls[0][0].message).toMatch(/Deprecation warning:/) + } + } +} +test("`process` should mirror `flow`", () => { + const isDeprecated = createDeprecationListener() + const generator = function* () {} + const flowResult = flow(generator) + const processResult = mstProcess(generator) + expect(processResult.name).toBe(flowResult.name) + isDeprecated() +}) +test("`createProcessSpawner` should mirror `createFlowSpawner`", () => { + const isDeprecated = createDeprecationListener() + const alias = "generatorAlias" + const generator = function* (): IterableIterator {} + const flowSpawnerResult = createFlowSpawner(alias, generator) + const processSpawnerResult = createProcessSpawner(alias, generator) + expect(processSpawnerResult.name).toBe(flowSpawnerResult.name) + isDeprecated() +}) diff --git a/__tests__/core/enum.test.ts b/__tests__/core/enum.test.ts new file mode 100644 index 000000000..95278049f --- /dev/null +++ b/__tests__/core/enum.test.ts @@ -0,0 +1,74 @@ +import { types, unprotect } from "../../src" + +enum ColorEnum { + Red = "Red", + Orange = "Orange", + Green = "Green" +} +const colorEnumValues = Object.values(ColorEnum) as ColorEnum[] + +test("should support enums", () => { + const TrafficLight = types.model({ color: types.enumeration("Color", colorEnumValues) }) + expect(TrafficLight.is({ color: ColorEnum.Green })).toBe(true) + expect(TrafficLight.is({ color: "Blue" })).toBe(false) + expect(TrafficLight.is({ color: undefined })).toBe(false) + const l = TrafficLight.create({ color: ColorEnum.Orange }) + unprotect(l) + l.color = ColorEnum.Red + expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') + if (process.env.NODE_ENV !== "production") { + expect(() => (l.color = "Blue" as any)).toThrowError( + /Error while converting `"Blue"` to `Color`/ + ) + } +}) +test("should support anonymous enums", () => { + const TrafficLight = types.model({ color: types.enumeration(colorEnumValues) }) + const l = TrafficLight.create({ color: ColorEnum.Orange }) + unprotect(l) + l.color = ColorEnum.Red + expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') + if (process.env.NODE_ENV !== "production") { + expect(() => (l.color = "Blue" as any)).toThrowError( + /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ + ) + } +}) +test("should support optional enums", () => { + const TrafficLight = types.optional(types.enumeration(colorEnumValues), ColorEnum.Orange) + const l = TrafficLight.create() + expect(l).toBe(ColorEnum.Orange) +}) +test("should support optional enums inside a model", () => { + const TrafficLight = types.model({ + color: types.optional(types.enumeration(colorEnumValues), ColorEnum.Orange) + }) + const l = TrafficLight.create({}) + expect(l.color).toBe(ColorEnum.Orange) +}) +test("should support plain string[] arrays", () => { + const colorOptions: string[] = ["Red", "Orange", "Green"] + const TrafficLight = types.model({ color: types.enumeration(colorOptions) }) + const l = TrafficLight.create({ color: "Orange" }) + unprotect(l) + l.color = "Red" + expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') + if (process.env.NODE_ENV !== "production") { + expect(() => (l.color = "Blue" as any)).toThrowError( + /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ + ) + } +}) +test("should support readonly enums as const", () => { + const colorOptions = ["Red", "Orange", "Green"] as const + const TrafficLight = types.model({ color: types.enumeration(colorOptions) }) + const l = TrafficLight.create({ color: "Orange" }) + unprotect(l) + l.color = "Red" + expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') + if (process.env.NODE_ENV !== "production") { + expect(() => (l.color = "Blue" as any)).toThrowError( + /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ + ) + } +}) diff --git a/__tests__/core/env.test.ts b/__tests__/core/env.test.ts new file mode 100644 index 000000000..5e06a4969 --- /dev/null +++ b/__tests__/core/env.test.ts @@ -0,0 +1,307 @@ +import { configure } from "mobx" +import { + types, + getEnv, + clone, + detach, + unprotect, + walk, + getPath, + castToSnapshot, + hasParent, + Instance, + destroy, + getParent, + IAnyStateTreeNode, + isStateTreeNode, + isAlive +} from "../../src" + +// tslint:disable: no-unused-expression + +const Todo = types + .model({ + title: "test" + }) + .views((self) => ({ + get description() { + return getEnv(self).useUppercase ? self.title.toUpperCase() : self.title + } + })) +const Store = types.model({ + todos: types.array(Todo) +}) +function createEnvironment() { + return { + useUppercase: true + } +} +test("it should be possible to use environments", () => { + const env = createEnvironment() + const todo = Todo.create({}, env) + expect(todo.description).toBe("TEST") + env.useUppercase = false + expect(todo.description).toBe("test") +}) +test("it should be possible to inherit environments", () => { + const env = createEnvironment() + const store = Store.create({ todos: [{}] }, env) + expect(store.todos[0].description).toBe("TEST") + env.useUppercase = false + expect(store.todos[0].description).toBe("test") +}) +test("getEnv returns empty object without environment", () => { + const todo = Todo.create() + expect(getEnv(todo)).toEqual({}) +}) +test("detach should preserve environment", () => { + const env = createEnvironment() + const store = Store.create({ todos: [{}] }, env) + unprotect(store) + const todo = detach(store.todos[0]) + expect(todo.description).toBe("TEST") + env.useUppercase = false + expect(todo.description).toBe("test") +}) +test("it is possible to assign instance with the same environment as the parent to a tree", () => { + const env = createEnvironment() + const store = Store.create({ todos: [] }, env) + const todo = Todo.create({}, env) + unprotect(store) + store.todos.push(todo) + expect(store.todos.length === 1).toBe(true) + expect(getEnv(store.todos) === getEnv(store.todos[0])).toBe(true) + expect(getEnv(todo) === getEnv(store.todos[0])).toBe(true) +}) +test("it is not possible to assign instance with a different environment than the parent to a tree", () => { + if (process.env.NODE_ENV !== "production") { + const env1 = createEnvironment() + const env2 = createEnvironment() + const store = Store.create({ todos: [] }, env1) + const todo = Todo.create({}, env2) + unprotect(store) + expect(() => store.todos.push(todo)).toThrowError( + "[mobx-state-tree] A state tree cannot be made part of another state tree as long as their environments are different." + ) + } +}) +test("it is possible to set a value inside a map of a map when using the same environment", () => { + const env = createEnvironment() + const EmptyModel = types.model({}) + const MapOfEmptyModel = types.model({ + map: types.map(EmptyModel) + }) + const MapOfMapOfEmptyModel = types.model({ + map: types.map(MapOfEmptyModel) + }) + const mapOfMap = MapOfMapOfEmptyModel.create( + { + map: { + whatever: { + map: {} + } + } + }, + env + ) + unprotect(mapOfMap) + // this should not throw + mapOfMap.map.get("whatever")!.map.set("1234", EmptyModel.create({}, env)) + expect(getEnv(mapOfMap) === env).toBe(true) + expect(getEnv(mapOfMap.map.get("whatever")!.map.get("1234")!) === env).toBe(true) +}) +test("clone preserves environnment", () => { + const env = createEnvironment() + const store = Store.create({ todos: [{}] }, env) + { + const todo = clone(store.todos[0]) + expect(getEnv(todo) === env).toBe(true) + } + { + const todo = clone(store.todos[0], true) + expect(getEnv(todo) === env).toBe(true) + } + { + const todo = clone(store.todos[0], false) + expect(getEnv(todo)).toEqual({}) + } + { + const env2 = createEnvironment() + const todo = clone(store.todos[0], env2) + expect(env2 === getEnv(todo)).toBe(true) + } +}) + +test("#1231", () => { + configure({ + useProxies: "never" + }) + + const envObj = createEnvironment() + const logs: string[] = [] + + function nofParents(node: IAnyStateTreeNode) { + let parents = 0 + let parent = node + while (hasParent(parent)) { + parents++ + parent = getParent(parent) + } + return parents + } + + function leafsFirst(root: IAnyStateTreeNode) { + const nodes: IAnyStateTreeNode[] = [] + walk(root, (i) => { + if (isStateTreeNode(i)) { + nodes.push(i) + } + }) + // sort by number of parents + nodes.sort((a, b) => { + return nofParents(b) - nofParents(a) + }) + return nodes + } + + function check(root: Instance, name: string, mode: "detach" | "destroy") { + function logFail(operation: string, n: any) { + logs.push(`fail: (${name}) ${operation}: ${getPath(n)}, ${n}`) + } + function log(operation: string, n: any) { + logs.push(`ok: (${name}) ${operation}: ${getPath(n)}, ${n}`) + } + + // make sure all nodes are there + root.s1.arr[0].title + root.s1.m.get("one")!.title + root.s2 + const nodes = leafsFirst(root) + expect(nodes.length).toBe(7) + + nodes.forEach((i) => { + const env = getEnv(i) + const parent = hasParent(i) + if (!parent && i !== root) { + logFail("expected a parent, but none found", i) + } else { + log("had parent or was root", i) + } + if (env !== envObj) { + logFail("expected same env as root, but was different", i) + } else { + log("same env as root", i) + } + }) + + unprotect(root) + nodes.forEach((i) => { + const optional = optionalPaths.includes(getPath(i)) + if (mode === "detach") { + log("detaching node", i) + detach(i) + } else { + log("destroying node", i) + destroy(i) + } + const env = getEnv(i) + const parent = hasParent(i) + const alive = isAlive(i) + if (mode === "detach") { + if (parent) { + logFail(`expected no parent after detach, but one was found`, i) + } else { + log(`no parent after detach`, i) + } + if (env !== envObj) { + logFail("expected same env as root after detach, but it was not", i) + } else { + log("env kept after detach", i) + } + if (!alive) { + logFail("expected to be alive after detach, but it was not", i) + } else { + log("alive after detach", i) + } + } else { + // destroy might or might not keep the env, but doesn't matter so we don't check + if (optional) { + // optional (undefined) nodes will be assigned undefined and reconciled, therefore they will be kept alive + if (!parent) { + logFail(`expected a parent after destroy (since it is optional), but none was found`, i) + } else { + log(`had parent after destroy (since it is optional)`, i) + } + if (!alive) { + logFail("expected to be alive after destroy (since it is optional), but it was not", i) + } else { + log("alive after destroy (since it is optional)", i) + } + } else { + if (parent) { + logFail(`expected no parent after destroy, but one was found`, i) + } else { + log(`no parent after destroy`, i) + } + if (alive) { + logFail("expected to be dead after destroy, but it was not", i) + } else { + log("dead after destroy", i) + } + } + } + }) + } + + const T = types.model("T", { title: "some title" }) + + const S1Arr = types.array(T) + const S1Map = types.map(T) + const S1 = types.model("S1", { + arr: S1Arr, + m: S1Map + }) + + const S2 = types.model("S2", {}) + + const RS = types.model("RS", { + s1: types.optional(S1, {}), + s2: types.optional(S2, {}) + }) + + const optionalPaths = ["/s1", "/s2", "/s1/m", "/s1/arr"] + + const data = { + s1: castToSnapshot( + S1.create({ + arr: S1Arr.create([T.create({})]), + m: castToSnapshot(S1Map.create({ one: T.create({}) })) + }) + ), + s2: S2.create() + } + const rsCreate = RS.create(data, envObj) + const rsCreate2 = clone(rsCreate, true) + + const rsSnap = RS.create( + { + s1: { + arr: [{}], + m: { one: {} } + }, + s2: {} + }, + envObj + ) + const rsSnap2 = clone(rsCreate, true) + + check(rsCreate, "using create", "detach") + check(rsSnap, "using snapshot", "detach") + check(rsCreate2, "using create", "destroy") + check(rsSnap2, "using snapshot", "destroy") + + const fails = logs.filter((l) => l.startsWith("fail:")) + if (fails.length > 0) { + fail(`\n${fails.join("\n")}`) + } +}) diff --git a/__tests__/core/frozen.test.ts b/__tests__/core/frozen.test.ts new file mode 100644 index 000000000..a9ecf9c78 --- /dev/null +++ b/__tests__/core/frozen.test.ts @@ -0,0 +1,91 @@ +import { getSnapshot, types, unprotect } from "../../src" + +test("it should accept any serializable value", () => { + const Factory = types.model({ + value: types.frozen<{ a: number; b: number } | undefined>() + }) + const doc = Factory.create() + unprotect(doc) + doc.value = { a: 1, b: 2 } + expect(getSnapshot(doc)).toEqual({ value: { a: 1, b: 2 } }) +}) + +if (process.env.NODE_ENV !== "production") { + test("it should throw if value is not serializable", () => { + const Factory = types.model({ + value: types.frozen() + }) + const doc = Factory.create() + unprotect(doc) + expect(() => { + doc.value = function IAmUnserializable() {} + }).toThrowError(/Error while converting to `frozen`/) + }) +} + +test("it should accept any default value value", () => { + const Factory = types.model({ + value: types.frozen(3) + }) + const doc = Factory.create() + expect(Factory.is({})).toBeTruthy() + expect(getSnapshot(doc)).toEqual({ value: 3 }) +}) + +test("it should type strongly", () => { + type Point = { x: number; y: number } + const Mouse = types + .model({ + loc: types.frozen() + }) + .actions((self) => ({ + moveABit() { + // self.loc.x += 1; // compile error, x is readonly! + ;(self.loc as any).x += 1 // throws, frozen! + } + })) + + expect(Mouse.is({})).toBeTruthy() // any value is acceptable to frozen, even undefined... + + const m = Mouse.create({ + // loc: 3 // type error! + loc: { x: 2, y: 3 } + }) + + if (process.env.NODE_ENV !== "production") { + expect(() => { + m.moveABit() + }).toThrow("Cannot assign to read only property 'x'") + } +}) + +if (process.env.NODE_ENV !== "production") { + test("it should be capable of using another MST type", () => { + const Point = types.model("Point", { x: types.number, y: types.number }) + const Mouse = types.model({ + loc: types.frozen(Point) + }) + + expect(Mouse.is({})).toBeFalsy() + expect(Mouse.is({ loc: {} })).toBeFalsy() + expect(Mouse.is({ loc: { x: 3, y: 2 } })).toBeTruthy() + + expect(() => { + ;(Mouse.create as any)() + }).toThrow( + 'at path "/loc" value `undefined` is not assignable to type: `frozen(Point)` (Value is not a plain object)' + ) + expect(() => { + Mouse.create({ loc: { x: 4 } } as any) + }).toThrow( + 'at path "/loc/y" value `undefined` is not assignable to type: `number` (Value is not a number)' + ) + + const m = Mouse.create({ + loc: { x: 3, y: 2 } + }) + + const x = m.loc.x + expect(x).toBe(3) + }) +} diff --git a/__tests__/core/hooks.test.ts b/__tests__/core/hooks.test.ts new file mode 100644 index 000000000..7702ddc98 --- /dev/null +++ b/__tests__/core/hooks.test.ts @@ -0,0 +1,456 @@ +import { + addDisposer, + destroy, + detach, + types, + unprotect, + getSnapshot, + applySnapshot, + onSnapshot, + isAlive, + hasParent, + cast, + resolvePath, + getParent +} from "../../src" + +function createTestStore(listener: (s: string) => void) { + const Todo = types + .model("Todo", { + title: "" + }) + .actions((self) => { + function afterCreate() { + listener("new todo: " + self.title) + addDisposer(self, () => { + listener("custom disposer 1 for " + self.title) + }) + addDisposer(self, () => { + listener("custom disposer 2 for " + self.title) + }) + } + function beforeDestroy() { + listener("destroy todo: " + self.title) + } + function afterAttach() { + listener("attach todo: " + self.title) + } + function beforeDetach() { + listener("detach todo: " + self.title) + } + return { + afterCreate, + beforeDestroy, + afterAttach, + beforeDetach + } + }) + const Store = types + .model("Store", { + todos: types.array(Todo) + }) + .actions((self) => { + function afterCreate() { + unprotect(self) + listener("new store: " + self.todos.length) + addDisposer(self, () => { + listener("custom disposer for store") + }) + } + function beforeDestroy() { + listener("destroy store: " + self.todos.length) + } + return { + afterCreate, + beforeDestroy + } + }) + return { + store: Store.create({ + todos: [{ title: "Get coffee" }, { title: "Get biscuit" }, { title: "Give talk" }] + }), + Store, + Todo + } +} + +// NOTE: as we defer creation (and thus, hooks) till first real access, +// some of original hooks do not fire at all +test("it should trigger lifecycle hooks", () => { + const events: string[] = [] + // new store: 3 + const { store, Todo } = createTestStore((e) => events.push(e)) + + events.push("-") + // access (new, attach), then detach "Give Talk" + const talk = detach(store.todos[2]) + expect(isAlive(talk)).toBe(true) + expect(hasParent(talk)).toBe(false) + + events.push("--") + + // access (new, attach), then destroy biscuit + const oldBiscuit = store.todos.pop()! + expect(isAlive(oldBiscuit)).toBe(false) + + events.push("---") + // new and then attach "add sugar" + const sugar = Todo.create({ + title: "add sugar" + }) + store.todos.push(sugar) + + events.push("----") + // destroy elements in the array ("add sugar"), then store + destroy(store) + expect(isAlive(store)).toBe(false) + + events.push("-----") + // destroy "Give talk" + destroy(talk) + expect(isAlive(talk)).toBe(false) + + expect(events).toEqual([ + "new store: 3", + "-", + "new todo: Give talk", + "attach todo: Give talk", + "detach todo: Give talk", + "--", + "new todo: Get biscuit", + "attach todo: Get biscuit", + "destroy todo: Get biscuit", + "custom disposer 2 for Get biscuit", + "custom disposer 1 for Get biscuit", + "---", + "new todo: add sugar", + "attach todo: add sugar", + "----", + "destroy todo: add sugar", + "custom disposer 2 for add sugar", + "custom disposer 1 for add sugar", + "destroy store: 2", + "custom disposer for store", + "-----", + "destroy todo: Give talk", + "custom disposer 2 for Give talk", + "custom disposer 1 for Give talk" + ]) +}) + +test("lifecycle hooks can access their children", () => { + const events: string[] = [] + function listener(e: string) { + events.push(e) + } + + const Child = types + .model("Todo", { + title: "" + }) + .actions((self) => ({ + afterCreate() { + listener("new child: " + self.title) + }, + afterAttach() { + listener("parent available: " + !!getParent(self)) + } + })) + + const Parent = types + .model("Parent", { + child: Child + }) + .actions((self) => ({ + afterCreate() { + // **This the key line**: it is trying to access the child + listener("new parent, child.title: " + self.child?.title) + } + })) + + const Store = types.model("Store", { + parent: types.maybe(Parent) + }) + + const store = Store.create({ + parent: { + child: { title: "Junior" } + } + }) + // As expected no hooks are called. + // The `parent` is not accessed it is just loaded. + events.push("-") + + // Simple access does a sensible thing + const parent = store.parent + expect(events).toEqual([ + "-", + "new child: Junior", + "new parent, child.title: Junior", + "parent available: true" + ]) + + // Clear the events and make a new store + events.length = 0 + const store2 = Store.create({ + parent: { + child: { title: "Junior" } + } + }) + events.push("-") + + // Previously resolvePath would cause problems because the parent hooks + // would be called before the child was fully created + const child = resolvePath(store2, "/parent/child") + expect(events).toEqual([ + "-", + "new child: Junior", + "new parent, child.title: Junior", + "parent available: true" + ]) +}) + +type CarSnapshot = { id: string } +const Car = types + .model("Car", { + id: types.number + }) + .preProcessSnapshot((snapshot) => + Object.assign({}, snapshot, { id: Number(snapshot.id) * 2 }) + ) + .postProcessSnapshot((snapshot) => + Object.assign({}, snapshot, { id: "" + snapshot.id / 2 }) + ) + +const Factory = types.model("Factory", { + car: Car +}) + +const Motorcycle = types + .model("Motorcycle", { + id: types.string + }) + .preProcessSnapshot((snapshot) => + Object.assign({}, snapshot, { id: snapshot.id.toLowerCase() }) + ) + .postProcessSnapshot((snapshot) => + Object.assign({}, snapshot, { id: snapshot.id.toUpperCase() }) + ) +const MotorcycleFactory = types.model("MotorcycleFactory", { + motorcycles: types.array(Motorcycle) +}) + +test("it should preprocess snapshots when creating", () => { + const car = Car.create({ id: "1" }) + expect(car.id).toBe(2) +}) +test("it should preprocess snapshots when updating", () => { + const car = Car.create({ id: "1" }) + expect(car.id).toBe(2) + applySnapshot(car, { id: "6" }) + expect(car.id).toBe(12) +}) +test("it should postprocess snapshots when generating snapshot - 1", () => { + const car = Car.create({ id: "1" }) + expect(car.id).toBe(2) + expect(getSnapshot(car)).toEqual({ id: "1" }) +}) +test("it should not apply postprocessor to snapshot on getSnapshot", () => { + const car = Car.create({ id: "1" }) + let error = false + onSnapshot(car, (snapshot) => { + error = true + }) + expect(getSnapshot(car)).toEqual({ id: "1" }) + expect(getSnapshot(car, false)).toEqual({ id: 2 }) + expect(error).toBeFalsy() +}) +test("it should preprocess snapshots when creating as property type", () => { + const f = Factory.create({ car: { id: "1" } }) + expect(f.car.id).toBe(2) +}) +test("it should preprocess snapshots when updating", () => { + const f = Factory.create({ car: { id: "1" } }) + expect(f.car.id).toBe(2) + applySnapshot(f, { car: { id: "6" } }) + expect(f.car.id).toBe(12) +}) +test("it should postprocess snapshots when generating snapshot - 2", () => { + const f = Factory.create({ car: { id: "1" } }) + expect(f.car.id).toBe(2) + expect(getSnapshot(f)).toEqual({ car: { id: "1" } }) +}) + +test("it should postprocess non-initialized children", () => { + const f = MotorcycleFactory.create({ motorcycles: [{ id: "a" }, { id: "b" }] }) + expect(getSnapshot(f)).toEqual({ motorcycles: [{ id: "A" }, { id: "B" }] }) +}) + +test("base hooks can be composed", () => { + const events: string[] = [] + function listener(message: string) { + events.push(message) + } + const Todo = types + .model("Todo", { title: "" }) + .actions((self) => { + function afterCreate() { + listener("aftercreate1") + } + function beforeDestroy() { + listener("beforedestroy1") + } + function afterAttach() { + listener("afterattach1") + } + function beforeDetach() { + listener("beforedetach1") + } + return { afterCreate, beforeDestroy, afterAttach, beforeDetach } + }) + .actions((self) => { + function afterCreate() { + listener("aftercreate2") + } + function beforeDestroy() { + listener("beforedestroy2") + } + function afterAttach() { + listener("afterattach2") + } + function beforeDetach() { + listener("beforedetach2") + } + return { afterCreate, beforeDestroy, afterAttach, beforeDetach } + }) + const Store = types.model("Store", { todos: types.array(Todo) }) + const store = Store.create({ todos: [] }) + const todo = Todo.create() + unprotect(store) + store.todos.push(todo) + detach(todo) + destroy(todo) + expect(events).toEqual([ + "aftercreate1", + "aftercreate2", + "afterattach1", + "afterattach2", + "beforedetach1", + "beforedetach2", + "beforedestroy1", + "beforedestroy2" + ]) +}) +test("snapshot processors can be composed", () => { + const X = types + .model({ + x: 1 + }) + .preProcessSnapshot((s) => ({ + x: s.x! - 3 + })) + .preProcessSnapshot((s) => ({ + x: s.x! / 5 + })) + .postProcessSnapshot((s) => { + return { x: s.x + 3 } + }) + .postProcessSnapshot((s) => { + return { x: s.x * 5 } + }) + + const x = X.create({ x: 25 }) + expect(x.x).toBe(2) + expect(getSnapshot(x).x).toBe(25) +}) + +test("addDisposer must return the passed disposer", () => { + const listener = jest.fn() + const M = types.model({}).actions((self) => { + expect(addDisposer(self, listener)).toBe(listener) + return {} + }) + M.create() +}) + +test("array calls all hooks", () => { + const events: string[] = [] + function listener(message: string) { + events.push(message) + } + const Item = types.model("Item", { id: types.string }) + const Collection = types.array(Item).hooks((self) => ({ + afterCreate() { + listener("afterCreate") + }, + afterAttach() { + listener("afterAttach") + }, + beforeDetach() { + listener("beforeDetach") + }, + beforeDestroy() { + listener("beforeDestroy") + } + })) + const Holder = types.model("Holder", { items: types.maybe(Collection) }) + + const collection = Collection.create([{ id: "1" }, { id: "2" }, { id: "3" }]) + expect(events).toStrictEqual(["afterCreate"]) + const holder = Holder.create({ items: collection }) + unprotect(holder) + expect(events).toStrictEqual(["afterCreate", "afterAttach"]) + detach(holder.items!) + expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach"]) + holder.items = collection + expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach", "afterAttach"]) + holder.items = undefined + expect(events).toStrictEqual([ + "afterCreate", + "afterAttach", + "beforeDetach", + "afterAttach", + "beforeDestroy" + ]) +}) + +test("map calls all hooks", () => { + const events: string[] = [] + function listener(message: string) { + events.push(message) + } + const Item = types.model("Item", { id: types.string }) + const Collection = types.map(Item).hooks((self) => ({ + afterCreate() { + listener("afterCreate") + }, + afterAttach() { + listener("afterAttach") + }, + beforeDetach() { + listener("beforeDetach") + }, + beforeDestroy() { + listener("beforeDestroy") + } + })) + const Holder = types.model("Holder", { items: types.maybe(Collection) }) + + const collection = Collection.create({ "1": { id: "1" }, "2": { id: "2" }, "3": { id: "3" } }) + expect(events).toStrictEqual(["afterCreate"]) + const holder = Holder.create({ items: cast(collection) }) + unprotect(holder) + expect(events).toStrictEqual(["afterCreate", "afterAttach"]) + detach(holder.items!) + expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach"]) + holder.items = collection + expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach", "afterAttach"]) + holder.items = undefined + expect(events).toStrictEqual([ + "afterCreate", + "afterAttach", + "beforeDetach", + "afterAttach", + "beforeDestroy" + ]) +}) diff --git a/__tests__/core/identifier.test.ts b/__tests__/core/identifier.test.ts new file mode 100644 index 000000000..e3fd3eb4e --- /dev/null +++ b/__tests__/core/identifier.test.ts @@ -0,0 +1,316 @@ +import { + types, + tryResolve, + resolvePath, + SnapshotOrInstance, + IAnyModelType, + IAnyComplexType, + resolveIdentifier, + getIdentifier, + detach +} from "../../src" + +if (process.env.NODE_ENV !== "production") { + test("#275 - Identifiers should check refinement", () => { + const Model = types + .model("Model", { + id: types.refinement("id", types.string, (identifier) => identifier.indexOf("Model_") === 0) + }) + .actions((self) => ({ + setId(id: string) { + self.id = id + } + })) + const ParentModel = types + .model("ParentModel", { + models: types.array(Model) + }) + .actions((self) => ({ + addModel(model: SnapshotOrInstance) { + self.models.push(model) + } + })) + expect(() => { + ParentModel.create({ models: [{ id: "WrongId_1" }] }) + }).toThrow() + expect(() => { + const parentStore = ParentModel.create({ models: [] }) + parentStore.addModel({ id: "WrongId_2" }) + }).toThrow() + expect(() => { + const model = Model.create({ id: "Model_1" }) + model.setId("WrongId_3") + }).toThrow() + expect(() => { + Model.create({ id: "WrongId_4" }) + }).toThrow() + }) +} +test("#158 - #88 - Identifiers should accept any string character", () => { + const Todo = types.model("Todo", { + id: types.identifier, + title: types.string + }) + expect(() => { + ;["coffee", "cof$fee", "cof|fee", "cof/fee"].forEach((id) => { + Todo.create({ + id: id, + title: "Get coffee" + }) + }) + }).not.toThrow() +}) +test("#187 - identifiers should not break late types", () => { + expect(() => { + const MstNode = types.model("MstNode", { + value: types.number, + next: types.maybe(types.late((): IAnyModelType => MstNode)) + }) + }).not.toThrow() +}) +if (process.env.NODE_ENV !== "production") { + test("should throw if multiple identifiers provided", () => { + expect(() => { + const Model = types.model("Model", { + id: types.identifierNumber, + pk: types.identifierNumber + }) + Model.create({ id: 1, pk: 2 }) + }).toThrowError( + `[mobx-state-tree] Cannot define property 'pk' as object identifier, property 'id' is already defined as identifier property` + ) + }) + test("should throw if identifier of wrong type", () => { + expect(() => { + const Model = types.model("Model", { id: types.identifier }) + Model.create({ id: 1 as any as string }) + }).toThrowError( + 'at path "/id" value `1` is not assignable to type: `identifier` (Value is not a valid identifier, expected a string).' + ) + }) + test("identifier should be used only on model types - no parent provided", () => { + expect(() => { + const Model = types.identifierNumber + Model.create(1) + }).toThrowError( + `[mobx-state-tree] Identifier types can only be instantiated as direct child of a model type` + ) + }) +} + +{ + const Foo = types.model("Foo", { + id: types.identifier, + name: types.string + }) + + const Bar = types.model("Bar", { + mimi: types.string, + fooRef: types.reference(Foo) + }) + + const Root = types.model("Root", { + foos: types.map(Foo), + bar: Bar + }) + + const root = Root.create({ + foos: {}, + bar: { + mimi: "mimi", + fooRef: "123" + } + }) + + test("try resolve doesn't work #686", () => { + expect(tryResolve(root, "/bar/fooRef")).toBe(undefined) + expect(tryResolve(root, "/bar/fooRef/name")).toBe(undefined) + }) + + test("try resolve shouldn't fail with a complex object node #2071", () => { + const array = types.array(types.number).create([]) + const model = types.model().create({}) + const map = types.map(types.number).create({}) + expect(tryResolve(array, "/boop")).toBeUndefined() + expect(tryResolve(model, "/boop")).toBeUndefined() + expect(tryResolve(map, "/boop")).toBeUndefined() + }) + + test("failing to resolve throws sane errors", () => { + expect(() => { + resolvePath(root, "/bar/mimi/oopsie") + }).toThrow( + "[mobx-state-tree] Could not resolve 'oopsie' in path '/bar/mimi' while resolving '/bar/mimi/oopsie'" + ) + + expect(() => { + resolvePath(root, "/zoomba/moomba") + }).toThrow( + "[mobx-state-tree] Could not resolve 'zoomba' in path '/' while resolving '/zoomba/moomba'" + ) + + expect(() => resolvePath(root, "/bar/fooRef")).toThrow( + "[mobx-state-tree] Failed to resolve reference '123' to type 'Foo' (from node: /bar/fooRef)" + ) + expect(() => resolvePath(root, "/bar/fooRef/name")).toThrow( + "[mobx-state-tree] Failed to resolve reference '123' to type 'Foo' (from node: /bar/fooRef)" + ) + }) +} + +test("it can resolve through references", () => { + const Folder = types.model("Folder", { + type: types.literal("folder"), + name: types.identifier, + children: types.array(types.late((): IAnyComplexType => types.union(Folder, SymLink))) + }) + const SymLink = types.model({ + type: types.literal("link"), + target: types.reference(Folder) + }) + + const root = Folder.create({ + type: "folder", + name: "root", + children: [ + { + type: "folder", + name: "a", + children: [] + }, + { + type: "folder", + name: "b", + children: [ + { + type: "folder", + name: "c", + children: [] + } + ] + }, + { + type: "link", + target: "b" + }, + { + type: "link", + target: "e" + } + ] + }) + + expect(resolvePath(root, "/children/1/children/0").name).toBe("c") + + expect(resolvePath(root, "/children/2/target/children/0").name).toBe("c") + + expect(resolvePath(root, "/children/2/target/children/../children/./0").name).toBe("c") + + expect(() => resolvePath(root, "/children/3/target/children/0").name).toThrow( + "[mobx-state-tree] Failed to resolve reference 'e' to type 'Folder' (from node: /children/3/target)" + ) +}) + +test("#1019", () => { + let calls = 0 + function randomUuid() { + calls++ + let pattern = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" + return pattern.replace(/[xy]/g, function (cc) { + const r = (Math.random() * 16) | 0, + v = cc === "x" ? r : (r & 0x3) | 0x8 + return v.toString(16) + }) + } + + const TOptionalId = types.optional( + types.refinement(types.identifier, (identifier) => + /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(identifier) + ), + randomUuid + ) + + const CommentModel = types.model("CommentModel", { + uid: TOptionalId + }) + + const CommentStore = types + .model("CommentStore", { + items: types.array(CommentModel) + }) + .actions((self) => ({ + test1() { + expect(calls).toBe(0) + const comment = CommentModel.create({}) + expect(calls).toBe(1) + + self.items.push(comment) + const item = resolveIdentifier(CommentModel, self.items, comment.uid) + const item2 = self.items.find((i) => i.uid === comment.uid) + expect(item).toBe(item2) + } + })) + + const c = CommentStore.create({}) + c.test1() +}) + +test("#1019-2", () => { + const Item = types.model({ + id: types.optional(types.identifier, "dummykey") + }) + expect(getIdentifier(Item.create())).toBe("dummykey") + expect(Item.create().id).toBe("dummykey") +}) + +test("identifierAttribute of the type", () => { + const M1 = types.model({}) + expect(M1.identifierAttribute).toBe(undefined) + + const M2 = types.model({ myId: types.identifier }) + expect(M2.identifierAttribute).toBe("myId") + + const M3 = types.model({ myId: types.optional(types.identifier, () => "hi") }) + expect(M3.identifierAttribute).toBe("myId") +}) + +test("items detached from arrays don't corrupt identifierCache", () => { + const Item = types.model("Item", { id: types.identifier }) + const ItemArray = types.model("ItemArray", { items: types.array(Item) }).actions((self) => ({ + removeSecondItemWithDetach() { + detach(self.items[1]) + } + })) + + const smallArray = ItemArray.create({ + items: [{ id: "A" }, { id: "B" }, { id: "C" }, { id: "D" }, { id: "E" }] + }) + expect(resolveIdentifier(Item, smallArray, "E")).toBeDefined() + smallArray.removeSecondItemWithDetach() + expect(smallArray.items.length).toBe(4) + expect(resolveIdentifier(Item, smallArray, "B")).toBeUndefined() + expect(resolveIdentifier(Item, smallArray, "E")).toBeDefined() + + const largeArray = ItemArray.create({ + items: [ + { id: "A" }, + { id: "B" }, + { id: "C" }, + { id: "D" }, + { id: "E" }, + { id: "F" }, + { id: "G" }, + { id: "H" }, + { id: "I" }, + { id: "J" }, + { id: "K" } + ] + }) + expect(resolveIdentifier(Item, largeArray, "K")).toBeDefined() + largeArray.removeSecondItemWithDetach() + expect(largeArray.items.length).toBe(10) + expect(resolveIdentifier(Item, largeArray, "B")).toBeUndefined() + expect(resolveIdentifier(Item, largeArray, "J")).toBeDefined() + // The following expectation was failing in version 5.1.8 and earlier + expect(resolveIdentifier(Item, largeArray, "K")).toBeDefined() +}) diff --git a/__tests__/core/jsonpatch.test.ts b/__tests__/core/jsonpatch.test.ts new file mode 100644 index 000000000..3d8bb9110 --- /dev/null +++ b/__tests__/core/jsonpatch.test.ts @@ -0,0 +1,479 @@ +import { + getSnapshot, + unprotect, + recordPatches, + types, + IType, + IJsonPatch, + Instance, + cast, + IAnyModelType, + IMSTMap, + escapeJsonPath, + getPath, + resolvePath, + splitJsonPath, + joinJsonPath +} from "../../src" + +function testPatches( + type: IType, + snapshot: C, + fn: any, + expectedPatches: IJsonPatch[] +) { + const instance = type.create(snapshot) + const baseSnapshot = getSnapshot(instance) + const recorder = recordPatches(instance) + unprotect(instance) + fn(instance) + recorder.stop() + expect(recorder.patches).toEqual(expectedPatches) + const clone = type.create(snapshot) + recorder.replay(clone) + expect(getSnapshot(clone)).toEqual(getSnapshot(instance)) + recorder.undo() + expect(getSnapshot(instance)).toEqual(baseSnapshot) +} +const Node = types.model("Node", { + id: types.identifierNumber, + text: "Hi", + children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) +}) + +test("it should apply simple patch", () => { + testPatches( + Node, + { id: 1 }, + (n: Instance) => { + n.text = "test" + }, + [ + { + op: "replace", + path: "/text", + value: "test" + } + ] + ) +}) + +test("it should apply deep patches to arrays", () => { + testPatches( + Node, + { id: 1, children: [{ id: 2 }] }, + (n: Instance) => { + const children = n.children as unknown as Instance[] + children[0].text = "test" // update + children[0] = cast({ id: 2, text: "world" }) // this reconciles; just an update + children[0] = cast({ id: 4, text: "coffee" }) // new object + children[1] = cast({ id: 3, text: "world" }) // addition + children.splice(0, 1) // removal + }, + [ + { + op: "replace", + path: "/children/0/text", + value: "test" + }, + { + op: "replace", + path: "/children/0/text", + value: "world" + }, + { + op: "replace", + path: "/children/0", + value: { + id: 4, + text: "coffee", + children: [] + } + }, + { + op: "add", + path: "/children/1", + value: { + id: 3, + text: "world", + children: [] + } + }, + { + op: "remove", + path: "/children/0" + } + ] + ) +}) + +test("it should apply deep patches to arrays with object instances", () => { + testPatches( + Node, + { id: 1, children: [{ id: 2 }] }, + (n: Instance) => { + const children = n.children as unknown as Instance[] + children[0].text = "test" // update + children[0] = Node.create({ id: 2, text: "world" }) // this does not reconcile, new instance is provided + children[0] = Node.create({ id: 4, text: "coffee" }) // new object + }, + [ + { + op: "replace", + path: "/children/0/text", + value: "test" + }, + { + op: "replace", + path: "/children/0", + value: { + id: 2, + text: "world", + children: [] + } + }, + { + op: "replace", + path: "/children/0", + value: { + id: 4, + text: "coffee", + children: [] + } + } + ] + ) +}) + +test("it should apply non flat patches", () => { + testPatches( + Node, + { id: 1 }, + (n: Instance) => { + const children = n.children as unknown as Instance[] + children.push( + cast({ + id: 2, + children: [{ id: 4 }, { id: 5, text: "Tea" }] + }) + ) + }, + [ + { + op: "add", + path: "/children/0", + value: { + id: 2, + text: "Hi", + children: [ + { + id: 4, + text: "Hi", + children: [] + }, + { + id: 5, + text: "Tea", + children: [] + } + ] + } + } + ] + ) +}) + +test("it should apply non flat patches with object instances", () => { + testPatches( + Node, + { id: 1 }, + (n: Instance) => { + const children = n.children as unknown as Instance[] + children.push( + Node.create({ + id: 2, + children: [{ id: 5, text: "Tea" }] + }) + ) + }, + [ + { + op: "add", + path: "/children/0", + value: { + id: 2, + text: "Hi", + children: [ + { + id: 5, + text: "Tea", + children: [] + } + ] + } + } + ] + ) +}) + +test("it should apply deep patches to maps", () => { + // If user does not transpile const/let to var, trying to call Late' subType + // property getter during map's tryCollectModelTypes() will throw ReferenceError. + // But if it's transpiled to var, then subType will become 'undefined'. + const NodeMap = types.model("NodeMap", { + id: types.identifierNumber, + text: "Hi", + children: types.optional(types.map(types.late((): IAnyModelType => NodeMap)), {}) + }) + testPatches( + NodeMap, + { id: 1, children: { 2: { id: 2 } } }, + (n: Instance) => { + const children = n.children as IMSTMap + children.get("2")!.text = "test" // update + children.put({ id: 2, text: "world" }) // this reconciles; just an update + children.set("4", NodeMap.create({ id: 4, text: "coffee", children: { 23: { id: 23 } } })) // new object + children.put({ id: 3, text: "world", children: { 7: { id: 7 } } }) // addition + children.delete("2") // removal + }, + [ + { + op: "replace", + path: "/children/2/text", + value: "test" + }, + { + op: "replace", + path: "/children/2/text", + value: "world" + }, + { + op: "add", + path: "/children/4", + value: { + children: { + 23: { + children: {}, + id: 23, + text: "Hi" + } + }, + id: 4, + text: "coffee" + } + }, + { + op: "add", + path: "/children/3", + value: { + children: { + 7: { + children: {}, + id: 7, + text: "Hi" + } + }, + id: 3, + text: "world" + } + }, + { + op: "remove", + path: "/children/2" + } + ] + ) +}) + +test("it should apply deep patches to objects", () => { + const NodeObject = types.model("NodeObject", { + id: types.identifierNumber, + text: "Hi", + child: types.maybe(types.late((): IAnyModelType => NodeObject)) + }) + testPatches( + NodeObject, + { id: 1, child: { id: 2 } }, + (n: Instance) => { + n.child!.text = "test" // update + n.child = cast({ id: 2, text: "world" }) // this reconciles; just an update + n.child = NodeObject.create({ id: 2, text: "coffee", child: { id: 23 } }) + n.child = cast({ id: 3, text: "world", child: { id: 7 } }) // addition + n.child = undefined // removal + }, + [ + { + op: "replace", + path: "/child/text", + value: "test" + }, + { + op: "replace", + path: "/child/text", + value: "world" + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 23, + text: "Hi" + }, + id: 2, + text: "coffee" + } + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 7, + text: "Hi" + }, + id: 3, + text: "world" + } + }, + { + op: "replace", + path: "/child", + value: undefined + } + ] + ) +}) + +test("it should correctly split/join json patches", () => { + function isValid(str: string, array: string[], altStr?: string) { + expect(splitJsonPath(str)).toEqual(array) + expect(joinJsonPath(array)).toBe(altStr !== undefined ? altStr : str) + } + + isValid("", []) + isValid("/", [""]) + isValid("//", ["", ""]) + isValid("/a", ["a"]) + isValid("/a/", ["a", ""]) + isValid("/a//", ["a", "", ""]) + isValid(".", ["."]) + isValid("..", [".."]) + isValid("./a", [".", "a"]) + isValid("../a", ["..", "a"]) + isValid("/.a", [".a"]) + isValid("/..a", ["..a"]) + + // rooted relatives are equivalent to plain relatives + isValid("/.", ["."], ".") + isValid("/..", [".."], "..") + isValid("/./a", [".", "a"], "./a") + isValid("/../a", ["..", "a"], "../a") + + function isInvalid(str: string) { + expect(() => { + splitJsonPath(str) + }).toThrow("a json path must be either rooted, empty or relative") + } + + isInvalid("a") + isInvalid("a/") + isInvalid("a//") + isInvalid(".a") + isInvalid(".a/") + isInvalid("..a") + isInvalid("..a/") +}) + +test("it should correctly escape/unescape json patches", () => { + expect(escapeJsonPath("http://example.com")).toBe("http:~1~1example.com") + + const AppStore = types.model({ + items: types.map(types.frozen()) + }) + testPatches( + AppStore, + { items: {} }, + (store: typeof AppStore.Type) => { + store.items.set("with/slash~tilde", 1) + }, + [{ op: "add", path: "/items/with~1slash~0tilde", value: 1 }] + ) +}) + +test("weird keys are handled correctly", () => { + const Store = types.model({ + map: types.map( + types.model({ + model: types.model({ + value: types.string + }) + }) + ) + }) + + const store = Store.create({ + map: { + "": { model: { value: "val1" } }, + "/": { model: { value: "val2" } }, + "~": { model: { value: "val3" } } + } + }) + + { + const target = store.map.get("")!.model + const path = getPath(target) + expect(path).toBe("/map//model") + expect(resolvePath(store, path)).toBe(target) + } + { + const target = store.map.get("/")!.model + const path = getPath(target) + expect(path).toBe("/map/~1/model") + expect(resolvePath(store, path)).toBe(target) + } + { + const target = store.map.get("~")!.model + const path = getPath(target) + expect(path).toBe("/map/~0/model") + expect(resolvePath(store, path)).toBe(target) + } +}) + +test("relativePath with a different base than the root works correctly", () => { + const Store = types.model({ + map: types.map( + types.model({ + model: types.model({ + value: types.string + }) + }) + ) + }) + + const store = Store.create({ + map: { + "1": { model: { value: "val1" } }, + "2": { model: { value: "val2" } } + } + }) + + { + const target = store.map.get("1")!.model + expect(resolvePath(store.map, "./1/model")).toBe(target) + expect(resolvePath(store.map, "../map/1/model")).toBe(target) + // rooted relative should resolve to the given base as root + expect(resolvePath(store.map, "/./1/model")).toBe(target) + expect(resolvePath(store.map, "/../map/1/model")).toBe(target) + } + { + const target = store.map.get("2")!.model + expect(resolvePath(store.map, "./2/model")).toBe(target) + expect(resolvePath(store.map, "../map/2/model")).toBe(target) + // rooted relative should resolve to the given base as root + expect(resolvePath(store.map, "/./2/model")).toBe(target) + expect(resolvePath(store.map, "/../map/2/model")).toBe(target) + } +}) diff --git a/__tests__/core/late.test.ts b/__tests__/core/late.test.ts new file mode 100644 index 000000000..5dccea10b --- /dev/null +++ b/__tests__/core/late.test.ts @@ -0,0 +1,133 @@ +import { types, typecheck, IAnyModelType } from "../../src" + +if (process.env.NODE_ENV !== "production") { + test("it should throw if late doesnt received a function as parameter", () => { + expect(() => { + types.model({ + after: types.late(1 as any) + }) + }).toThrow() + }) +} +test("it should accept a type and infer it correctly", () => { + const Before = types.model({ + after: types.late(() => After) + }) + const After = types.model({ + name: types.maybe(types.string) + }) + expect(() => Before.create({ after: { name: "Hello, it's me." } })).not.toThrow() +}) +test("late should allow circular references", () => { + // TypeScript is'nt smart enough to infer self referencing types. + const Node = types.model({ + childs: types.optional(types.array(types.late((): IAnyModelType => Node)), []) + }) + expect(() => Node.create()).not.toThrow() + expect(() => Node.create({ childs: [{}, { childs: [] }] })).not.toThrow() +}) +test("late should describe correctly circular references", () => { + // TypeScript is'nt smart enough to infer self referencing types. + const Node = types.model("Node", { + childs: types.array(types.late((): IAnyModelType => Node)) + }) + expect(Node.describe()).toEqual("{ childs: late(() => Node)[]? }") +}) +test("should typecheck", () => { + const NodeObject = types.model("NodeObject", { + id: types.identifierNumber, + text: "Hi", + child: types.maybe(types.late((): IAnyModelType => NodeObject)) + }) + const x = NodeObject.create({ id: 1 }) + try { + ;(x as any).child = 3 + ;(x as any).floepie = 3 + } catch (e) { + // ignore, this is about TS + } +}) + +test("typecheck should throw an Error when called at runtime, but not log the error", () => { + const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}) + + const NodeObject = types.model("NodeObject", { + id: types.identifierNumber, + text: types.string + }) + + expect(() => { + typecheck(NodeObject, { id: 1, text: 1 } as any) + }).toThrow() + + try { + typecheck(NodeObject, { id: 1, text: 1 } as any) + } catch (error) { + expect(error).toBeDefined() + expect(consoleSpy).not.toHaveBeenCalled() + } +}) + +test("#825, late type checking ", () => { + const Product = types.model({ + details: types.late(() => types.optional(Details, {})) + }) + const Details = types.model({ + name: types.maybe(types.string) + }) + + const p2 = Product.create({}) + const p = Product.create({ details: { name: "bla" } }) +}) + +test("#916 - 0", () => { + const Todo = types.model("Todo", { + title: types.string, + newTodo: types.optional( + types.late((): IAnyModelType => Todo), + {} + ) // N.B. this definition is never instantiateable! + }) +}) + +test("#916 - 1", () => { + const Todo = types.model("Todo", { + title: types.string, + newTodo: types.maybe(types.late((): IAnyModelType => Todo)) + }) + const t = Todo.create({ + title: "Get Coffee" + }) +}) + +test("#916 - 2", () => { + const Todo = types.model("Todo", { + title: types.string, + newTodo: types.maybe(types.late((): IAnyModelType => Todo)) + }) + expect( + Todo.is({ + title: "A", + newTodo: { title: " test" } + }) + ).toBe(true) + expect( + Todo.is({ + title: "A", + newTodo: { title: 7 } + }) + ).toBe(false) +}) + +test("#916 - 3", () => { + const Todo = types.model("Todo", { + title: types.string, + newTodo: types.maybe(types.late((): IAnyModelType => Todo)) + }) + const t = Todo.create({ + title: "Get Coffee", + newTodo: { title: "test" } + }) + + expect(t.newTodo!.title).toBe("test") +}) diff --git a/__tests__/core/lazy.test.ts b/__tests__/core/lazy.test.ts new file mode 100644 index 000000000..75162ab34 --- /dev/null +++ b/__tests__/core/lazy.test.ts @@ -0,0 +1,111 @@ +import { when } from "mobx" +import { getRoot, types } from "../../src" + +interface IRootModel { + shouldLoad: boolean +} + +test("it should load the correct type", async () => { + const LazyModel = types + .model("LazyModel", { + width: types.number, + height: types.number + }) + .views((self) => ({ + get area() { + return self.height * self.width + } + })) + + const Root = types + .model("Root", { + shouldLoad: types.optional(types.boolean, false), + lazyModel: types.lazy("lazy", { + loadType: () => Promise.resolve(LazyModel), + shouldLoadPredicate: (parent) => parent.shouldLoad == true + }) + }) + .actions((self) => ({ + load: () => { + self.shouldLoad = true + } + })) + + const store = Root.create({ + lazyModel: { + width: 3, + height: 2 + } + }) + + expect(store.lazyModel.width).toBe(3) + expect(store.lazyModel.height).toBe(2) + expect(store.lazyModel.area).toBeUndefined() + store.load() + const promise = new Promise((resolve, reject) => { + when( + () => store.lazyModel && store.lazyModel.area !== undefined, + () => resolve(store.lazyModel.area) + ) + + setTimeout(reject, 2000) + }) + + await expect(promise).resolves.toBe(6) +}) + +test("maintains the tree structure when loaded", async () => { + const LazyModel = types + .model("LazyModel", { + width: types.number, + height: types.number + }) + .views((self) => ({ + get area() { + const root = getRoot<{ rootValue: number }>(self) + return self.height * self.width * root.rootValue + } + })) + + const Root = types + .model("Root", { + shouldLoad: types.optional(types.boolean, false), + lazyModel: types.lazy("lazy", { + loadType: () => Promise.resolve(LazyModel), + shouldLoadPredicate: (parent) => parent.shouldLoad == true + }) + }) + .views(() => ({ + get rootValue() { + return 5 + } + })) + .actions((self) => ({ + load: () => { + self.shouldLoad = true + } + })) + + const store = Root.create({ + lazyModel: { + width: 3, + height: 2 + } + }) + + expect(store.lazyModel.width).toBe(3) + expect(store.lazyModel.height).toBe(2) + expect(store.rootValue).toEqual(5) + expect(store.lazyModel.area).toBeUndefined() + store.load() + const promise = new Promise((resolve, reject) => { + when( + () => store.lazyModel && store.lazyModel.area !== undefined, + () => resolve(store.lazyModel.area) + ) + + setTimeout(reject, 2000) + }) + + await expect(promise).resolves.toBe(30) +}) diff --git a/__tests__/core/literal.test.ts b/__tests__/core/literal.test.ts new file mode 100644 index 000000000..2807a276d --- /dev/null +++ b/__tests__/core/literal.test.ts @@ -0,0 +1,50 @@ +import { types } from "../../src" + +if (process.env.NODE_ENV !== "production") { + test("it should allow only primitives", () => { + const error = expect(() => { + types.model({ + complexArg: types.literal({ a: 1 } as any) + }) + }).toThrowError("expected primitive as argument") + }) + test("it should fail if not optional and no default provided", () => { + const Factory = types.literal("hello") + expect(() => { + ;(Factory.create as any)() + }).toThrow(/is not assignable to type/) + }) + test("it should throw if a different type is given", () => { + const Factory = types.model("TestFactory", { + shouldBeOne: types.literal(1) + }) + expect(() => { + Factory.create({ shouldBeOne: 2 as any }) + }).toThrow(/is not assignable to type/) + }) +} +test("it should support null type", () => { + const M = types.model({ + nullish: types.null + }) + expect( + M.is({ + nullish: null + }) + ).toBe(true) + expect(M.is({ nullish: undefined })).toBe(false) + expect(M.is({ nullish: 17 })).toBe(false) +}) +test("it should support undefined type", () => { + const M = types.model({ + undefinedish: types.undefined + }) + expect( + M.is({ + undefinedish: undefined + }) + ).toBe(true) + expect(M.is({})).toBe(true) // MWE: disputable, should be false? + expect(M.is({ undefinedish: null })).toBe(false) + expect(M.is({ undefinedish: 17 })).toBe(false) +}) diff --git a/__tests__/core/map.test.ts b/__tests__/core/map.test.ts new file mode 100644 index 000000000..c37fb2b36 --- /dev/null +++ b/__tests__/core/map.test.ts @@ -0,0 +1,592 @@ +import { configure } from "mobx" +import { + onSnapshot, + onPatch, + applyPatch, + applySnapshot, + getSnapshot, + types, + unprotect, + isStateTreeNode, + SnapshotOut, + IJsonPatch, + IAnyModelType, + detach +} from "../../src" + +const createTestFactories = () => { + const ItemFactory = types.model({ + to: "world" + }) + const Factory = types.map(ItemFactory) + const PrimitiveMapFactory = types.model({ + boolean: types.map(types.boolean), + string: types.map(types.string), + number: types.map(types.number) + }) + return { Factory, ItemFactory, PrimitiveMapFactory } +} +// === FACTORY TESTS === +test("it should create a factory", () => { + const { Factory } = createTestFactories() + const snapshot = getSnapshot(Factory.create()) + expect(snapshot).toEqual({}) +}) +test("it should succeed if not optional and no default provided", () => { + const Factory = types.map(types.string) + expect(Factory.create().toJSON()).toEqual({}) +}) +test("it should restore the state from the snapshot", () => { + const { Factory } = createTestFactories() + const instance = Factory.create({ hello: { to: "world" } }) + expect(getSnapshot(instance)).toEqual({ hello: { to: "world" } }) + expect(("" + instance).replace(/@\d+/, "@xx")).toBe("[object ObservableMap]") // default toString +}) +// === SNAPSHOT TESTS === +test("it should emit snapshots", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let snapshots: SnapshotOut[] = [] + onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) + doc.set("hello", ItemFactory.create()) + expect(snapshots).toEqual([{ hello: { to: "world" } }]) +}) +test("it should apply snapshots", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applySnapshot(doc, { hello: { to: "universe" } }) + expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) +}) +test("it should return a snapshot", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.set("hello", ItemFactory.create()) + expect(getSnapshot(doc)).toEqual({ hello: { to: "world" } }) +}) +test("it should be the same each time", () => { + const { PrimitiveMapFactory } = createTestFactories() + const data = { + string: { a: "a", b: "" }, + boolean: { a: true, b: false }, + number: { a: 0, b: 42, c: NaN } + } + const doc = PrimitiveMapFactory.create(data) + expect(getSnapshot(doc)).toEqual(data) + applySnapshot(doc, data) + expect(getSnapshot(doc)).toEqual(data) + applySnapshot(doc, data) + expect(getSnapshot(doc)).toEqual(data) +}) +// === PATCHES TESTS === +test("it should emit add patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.set("hello", ItemFactory.create({ to: "universe" })) + expect(patches).toEqual([{ op: "add", path: "/hello", value: { to: "universe" } }]) +}) +test("it should apply an add patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, { op: "add", path: "/hello", value: { to: "universe" } }) + expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) +}) +test("it should emit update patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.set("hello", ItemFactory.create()) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.set("hello", ItemFactory.create({ to: "universe" })) + expect(patches).toEqual([{ op: "replace", path: "/hello", value: { to: "universe" } }]) +}) +test("it should apply an update patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + applyPatch(doc, { op: "replace", path: "/hello", value: { to: "universe" } }) + expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) +}) +test("it should emit remove patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.set("hello", ItemFactory.create()) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.delete("hello") + expect(patches).toEqual([{ op: "remove", path: "/hello" }]) +}) +test("it should apply a remove patch", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + doc.set("hello", ItemFactory.create()) + applyPatch(doc, { op: "remove", path: "/hello" }) + expect(getSnapshot(doc)).toEqual({}) +}) +test("it should apply patches", () => { + const { Factory, ItemFactory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, [ + { op: "add", path: "/hello", value: { to: "mars" } }, + { op: "replace", path: "/hello", value: { to: "universe" } } + ]) + expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) +}) +// === TYPE CHECKS === +test("it should check the type correctly", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + expect(Factory.is(doc)).toEqual(true) + expect(Factory.is([])).toEqual(false) + expect(Factory.is({})).toEqual(true) + expect(Factory.is({ hello: { to: "mars" } })).toEqual(true) + expect(Factory.is({ hello: { wrongKey: true } })).toEqual(true) + expect(Factory.is({ hello: { to: true } })).toEqual(false) +}) +test("it should support identifiers", () => { + configure({ + useProxies: "never" + }) + + const Store = types.model({ + todos: types.optional( + types.map( + types.model({ + id: types.identifier + }) + ), + {} + ) + }) + const store = Store.create() + unprotect(store) + store.todos.set("17", { id: "17" }) + const a = store.todos.get("17") + applySnapshot(store.todos, { "16": { id: "16" }, "17": { id: "17" } }) + expect(a === store.todos.get("17")).toBe(true) // same instance still + expect(store.todos.get("17")!.id).toBe("17") + store.todos.put({ id: "19" }) + expect(store.todos.get("19")!.id).toBe("19") + expect("" + store.todos.get("19")).toBe("AnonymousModel@/todos/19(id: 19)") + if (process.env.NODE_ENV !== "production") { + expect(() => applySnapshot(store.todos, { "17": { id: "18" } })).toThrowError( + "[mobx-state-tree] A map of objects containing an identifier should always store the object under their own identifier. Trying to store key '18', but expected: '17'" + ) + } +}) +test("#184 - types.map().get(key) should not throw if key doesnt exists", () => { + const { Factory } = createTestFactories() + const doc = Factory.create({ + hello: { + to: "world" + } + }) + expect(() => { + doc.get("notexistingkey") + }).not.toThrow() +}) +test("#192 - put should not throw when identifier is a number", () => { + const Todo = types.model("Todo", { todo_id: types.identifierNumber, title: types.string }) + const TodoStore = types + .model("TodoStore", { + todos: types.optional(types.map(Todo), {}) + }) + .actions((self) => { + function addTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { + self.todos.put(todo) + } + return { + addTodo + } + }) + const todoStore = TodoStore.create({}) + expect(() => { + todoStore.addTodo({ + todo_id: 1, + title: "Test" + }) + }).not.toThrow() + if (process.env.NODE_ENV !== "production") { + expect(() => { + todoStore.addTodo({ todo_id: "1", title: "Test" } as any) + }).toThrowError( + 'at path "/todo_id" value `"1"` is not assignable to type: `identifierNumber` (Value is not a valid identifierNumber, expected a number)' + ) + } +}) +test("#192 - map should not mess up keys when putting twice", () => { + const Todo = types.model("Todo", { todo_id: types.identifierNumber, title: types.string }) + const TodoStore = types + .model("TodoStore", { + todos: types.optional(types.map(Todo), {}) + }) + .actions((self) => { + function addTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { + self.todos.put(todo) + } + return { + addTodo + } + }) + const todoStore = TodoStore.create({}) + todoStore.addTodo({ + todo_id: 1, + title: "Test" + }) + expect(getSnapshot(todoStore.todos)).toEqual({ "1": { todo_id: 1, title: "Test" } }) + todoStore.addTodo({ + todo_id: 1, + title: "Test Edited" + }) + expect(getSnapshot(todoStore.todos)).toEqual({ "1": { todo_id: 1, title: "Test Edited" } }) +}) +test("#694 - map.put should return new node", () => { + configure({ + useProxies: "never" + }) + + const Todo = types.model("Todo", { + todo_id: types.identifier, + title: types.string + }) + const TodoStore = types + .model("TodoStore", { + todos: types.map(Todo) + }) + .actions((self) => { + function addAndReturnTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { + return self.todos.put(todo) + } + return { + addAndReturnTodo + } + }) + const todoStore = TodoStore.create({ todos: {} }) + + const addedTodo = todoStore.addAndReturnTodo( + Todo.create({ + todo_id: "1", + title: "Test 1" + }) + ) + + expect(isStateTreeNode(addedTodo)).toEqual(true) + expect(getSnapshot(addedTodo)).toEqual({ todo_id: "1", title: "Test 1" }) + + const editedTodo = todoStore.addAndReturnTodo({ + todo_id: "1", + title: "Test 1 Edited" + }) + expect(isStateTreeNode(editedTodo)).toEqual(true) + expect(getSnapshot(editedTodo)).toEqual({ todo_id: "1", title: "Test 1 Edited" }) + expect(editedTodo).toEqual(addedTodo) + + const addedTodo2 = todoStore.addAndReturnTodo({ + todo_id: "2", + title: "Test 2" + }) + expect(isStateTreeNode(addedTodo2)).toEqual(true) + expect(getSnapshot(addedTodo2)).toEqual({ todo_id: "2", title: "Test 2" }) +}) +test("it should not throw when removing a non existing item from a map", () => { + expect(() => { + const AppModel = types + .model({ + myMap: types.map(types.number) + }) + .actions((self) => { + function something() { + return self.myMap.delete("1020") + } + return { + something + } + }) + const store = AppModel.create() + expect(store.something()).toBe(false) + }).not.toThrow() +}) +test("it should get map keys from reversePatch when deleted an item from a nested map", () => { + const AppModel = types + .model({ + value: types.map(types.map(types.map(types.number))) + }) + .actions((self) => ({ + remove(k: string) { + self.value.delete(k) + } + })) + const store = AppModel.create({ value: { a: { b: { c: 10 } } } }) + onPatch(store, (patch, reversePatch) => { + expect(patch).toEqual({ op: "remove", path: "/value/a" }) + expect(reversePatch).toEqual({ op: "add", path: "/value/a", value: { b: { c: 10 } } }) + }) + store.remove("a") +}) + +test("map expects regular identifiers", () => { + const A = types.model("A", { a: types.identifier }) + const B = types.model("B", { b: types.identifier }) + + // NOTE: we can determine identifier attribute upfront, so no need to wait for error while craetion + expect(() => types.map(types.union(A, B))).toThrow( + `[mobx-state-tree] The objects in a map should all have the same identifier attribute, expected 'a', but child of type 'B' declared attribute 'b' as identifier` + ) +}) + +test("issue #876 - map.put works fine for models with preProcessSnapshot", () => { + const Note = types.model("Item", { + text: types.string + }) + const Item = types + .model("Item", { + id: types.identifier, + title: types.string, + notes: types.array(Note) + }) + .preProcessSnapshot((snapshot) => { + const result = Object.assign({}, snapshot) + if (typeof result.title !== "string") result.title = "" + return result + }) + + const Store = types + .model("Store", { + items: types.optional(types.map(Item), {}) + }) + .actions((self) => ({ + afterCreate() { + self.items.put({ + id: "1", + title: "", + notes: [{ text: "first note" }, { text: "second note" }] + }) + } + })) + + let store!: typeof Store.Type + expect(() => { + store = Store.create({}) + }).not.toThrow() + expect(getSnapshot(store)).toEqual({ + items: { + "1": { + id: "1", + notes: [{ text: "first note" }, { text: "second note" }], + title: "" + } + } + }) +}) + +test("map can resolve late identifiers", () => { + const Late = types.model({ + id: types.identifier, + children: types.map(types.late((): IAnyModelType => Late)) + }) + const snapshot = { + id: "1", + children: { + "2": { + id: "2", + children: {} + } + } + } + expect(() => Late.create(snapshot)).not.toThrow() +}) + +test("get should return value when key is a number", () => { + const Todo = types.model("Todo", { + todo_id: types.identifierNumber, + title: types.string + }) + const TodoStore = types + .model("TodoStore", { + todos: types.optional(types.map(Todo), {}) + }) + .actions((self) => { + function addTodo(aTodo: typeof Todo.Type | typeof Todo.CreationType) { + self.todos.put(aTodo) + } + return { + addTodo + } + }) + const todoStore = TodoStore.create({}) + + const todo = { + todo_id: 1, + title: "Test" + } + + todoStore.addTodo(todo) + expect(todoStore.todos.get(1 as any as string)!.title).toEqual("Test") +}) + +test("numeric keys should work", () => { + const M = types.model({ + id: types.identifier, + title: "test" + }) + const S = types.model({ + mies: types.map(M), + ref: types.maybe(types.reference(M)) + }) + + const s = S.create({ + mies: {} + }) + unprotect(s) + + s.mies.set(7, { id: "7" }) + const i7 = s.mies.get(7)! + expect(i7.title).toBe("test") + expect(s.mies.has("7")).toBeTruthy() + expect(s.mies.has(7 as any as string)).toBeTruthy() + expect(s.mies.get("7")).toBeTruthy() + expect(s.mies.get(7 as any as string)).toBeTruthy() + + s.mies.set("8", { id: "8" }) + expect(s.mies.has("8")).toBeTruthy() + expect(s.mies.has(8 as any as string)).toBeTruthy() + expect(s.mies.get("8")).toBeTruthy() + expect(s.mies.get(8 as any as string)).toBeTruthy() + + expect(Array.from(s.mies.keys())).toEqual(["7", "8"]) + + s.mies.put({ id: "7", title: "coffee" }) + expect(s.mies.size).toBe(2) + expect(s.mies.has("7")).toBeTruthy() + expect(s.mies.has(7 as any as string)).toBeTruthy() + expect(s.mies.get("7")).toBeTruthy() + expect(s.mies.get(7 as any as string)).toBeTruthy() + expect(i7.title).toBe("coffee") + + expect(s.mies.delete(8 as any as string)).toBeTruthy() + expect(s.mies.size).toBe(1) +}) + +describe("#826, adding stuff twice", () => { + const Store = types + .model({ + map: types.optional(types.map(types.boolean), {}) + }) + .actions((self) => ({ + toogleMap: (id: string) => { + self.map.set(id, !self.map.get(id)) + } + })) + + // This one pass fine 👍 + test("Toogling once shouldn't throw", () => { + const store = Store.create({}) + expect(() => { + store.toogleMap("1") + }).not.toThrow() + }) + + // This one throws with 'Not a child 1' error 👎 + test("Toogling twice shouldn't throw", () => { + const store = Store.create({}) + expect(() => { + store.toogleMap("1") + store.toogleMap("1") + }).not.toThrow() + }) +}) + +test("#751 restore from snapshot should work", () => { + const Submodel = types.model("Submodel", { + id: types.identifierNumber + }) + + const Model = types.model("Model", { + map: types.map(Submodel) + }) + + const server = Model.create({ map: {} }) + + // We add an item with a number id + unprotect(server) + server.map.set(1 as any as string, { id: 1 }) + + // We can access it using a number + expect(server.map.get(1 as any as string)!.id).toBe(1) + + // But if we get a snapshot... + const snapshot = getSnapshot(server) + // And apply it back... + const browser = Model.create(snapshot) + + // We can access it using a string + expect(server.map.get("1")!.id).toBe(1) + + // And as number + expect(server.map.get(1 as any as string)!.id).toBe(1) + + expect(server.map.size).toBe(1) +}) + +test("#1173 - detaching a map should not eliminate its children", () => { + const M = types.model({}) + const AM = types.map(M) + const Store = types.model({ items: AM }) + const s = Store.create({ items: { x: {}, y: {}, z: {} } }) + const n0 = s.items.get("x") + + unprotect(s) + + const detachedItems = detach(s.items) + expect(s.items).not.toBe(detachedItems) + expect(s.items.size).toBe(0) + expect(detachedItems.size).toBe(3) + expect(detachedItems.get("x")).toBe(n0) +}) + +test("#1131 - put with optional identifier", () => { + const Test = types.model({ + id: types.optional(types.identifier, () => Math.random().toString(36).substr(2)), + value: "hi" + }) + + const myMap = types.map(Test).create() + unprotect(myMap) + const val = myMap.put({}) + expect(val.id).toBeTruthy() + expect(val.value).toBe("hi") +}) + +/** + * This test exercises the TypeScript types fo `MSTMap`, to ensure that our typings stay consistent. In PR #2072, + * we changed from accepting `[string, any][] | IKeyValueMap | Map | undefined,` in `initialdata` + * to accepting `IObservableMapInitialValues | undefined,`. + * + * This test demonstrates backwards compatibility for the change, and will let us know if anything changes and breaks + * if we ever update those types as well, or if MobX changes the exported `IObservableMapInitialValues` type. + * + * It looks like `[string, any][]` and `Map` are actually not supported, so we just test the `IKeyValueMap` and `undefined` cases + * for now. See https://github.com/mobxjs/mobx-state-tree/pull/2072#issuecomment-1747482100 + */ +describe("#2072 - IObservableMapInitialValues types should work correctly", () => { + it("should accept IKeyValueMap", () => { + const initialData = { + "1": "Tyler", + "2": "Jamon" + } + + const mapInstance = types.map(types.string).create(initialData) + expect(mapInstance.size).toBe(2) + }) + it("should accept undefined", () => { + const mapInstance = types.map(types.string).create(undefined) + expect(mapInstance.size).toBe(0) + }) +}) diff --git a/__tests__/core/model.test.ts b/__tests__/core/model.test.ts new file mode 100644 index 000000000..3b2e151e8 --- /dev/null +++ b/__tests__/core/model.test.ts @@ -0,0 +1,426 @@ +import { applySnapshot, getSnapshot, types } from "../../src" +import { Hook } from "../../src/internal" + +test("it should call preProcessSnapshot with the correct argument", () => { + const onSnapshot = jest.fn((snapshot: any) => { + return { + val: snapshot.val + 1 + } + }) + + const Model = types + .model({ + val: types.number + }) + .preProcessSnapshot(onSnapshot) + + const model = Model.create({ val: 0 }) + applySnapshot(model, { val: 1 }) + expect(onSnapshot).lastCalledWith({ val: 1 }) +}) +describe("Model instantiation", () => { + describe("Model name", () => { + test("Providing a string as the first argument should set it as the model's name.", () => { + const Model = types.model("Name", {}) + + expect(Model.name).toBe("Name") + }) + test("Providing an empty string as the first argument should set it as the model's name.", () => { + const Model = types.model("", {}) + + expect(Model.name).toBe("") + }) + describe("Providing a non-string argument as the first argument should set the model's name as 'AnonymousModel'.", () => { + const testCases = [ + {}, + null, + undefined, + 1, + true, + [], + function () {}, + new Date(), + /a/, + new Map(), + new Set(), + Symbol(), + new Error(), + NaN, + Infinity + ] + + testCases.forEach((testCase) => { + test(`Providing ${JSON.stringify( + testCase + )} as the first argument should set the model's name as 'AnonymousModel'.`, () => { + const Model = types.model(testCase as any) + + expect(Model.name).toBe("AnonymousModel") + }) + }) + }) + }) + describe("Model properties", () => { + test("Providing a string as the first argument and an object as the second argument should use the object's properties in the model.", () => { + const Model = types.model("name", { + prop1: "prop1", + prop2: 2 + }) + + expect(Model.properties).toHaveProperty("prop1") + expect(Model.properties).toHaveProperty("prop2") + }) + test("Providing an object as the first argument should parse and use its properties.", () => { + const Model = types.model({ + prop1: "prop1", + prop2: 2 + }) + + expect(Model.properties).toHaveProperty("prop1") + expect(Model.properties).toHaveProperty("prop2") + }) + test("Providing a string as the first argument and a falsy value as the second argument should result in an empty set of properties.", () => { + const Model = types.model("name", null as any) + + expect(Model.properties).toEqual({}) + }) + }) + describe("Model identifier", () => { + test("If no identifier attribute is provided, the identifierAttribute should be undefined.", () => { + const Model = types.model("name", {}) + + expect(Model.identifierAttribute).toBeUndefined() + }) + test("If an identifier attribute is provided, the identifierAttribute should be set for the object.", () => { + const Model = types.model("name", { + id: types.identifier + }) + + expect(Model.identifierAttribute).toBe("id") + }) + test("If an identifier attribute has already been provided, an error should be thrown when attempting to provide a second one.", () => { + expect(() => { + types.model("name", { + id: types.identifier, + id2: types.identifier + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Cannot define property 'id2' as object identifier, property 'id' is already defined as identifier property"` + ) + }) + }) + describe("Edge case behavior", () => { + describe("when we provide no arguments to the function", () => { + test("the model will be named AnonymousModel", () => { + const Model = types.model() + + expect(Model.name).toBe("AnonymousModel") + }) + test("the model will have no properties", () => { + const Model = types.model() + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({}) + }) + }) + test("the model will have no properties", () => { + const Model = types.model() + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({}) + }) + if (process.env.NODE_ENV !== "production") { + test("it should not throw an error", () => { + expect(() => { + types.model() + }).not.toThrow() + }) + } + }) + describe("when we provide an invalid name value, but a valid property object", () => { + if (process.env.NODE_ENV === "production") { + test("the model will be named AnonymousModel", () => { + const Model = types.model(null as any, { + prop1: "prop1", + prop2: 2 + }) + + expect(Model.name).toBe("AnonymousModel") + }) + test("the model will have no properties", () => { + const Model = types.model(null as any, { + prop1: "prop1", + prop2: 2 + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({}) + }) + } else { + test("it should complain about invalid name", () => { + expect(() => { + types.model(null as any, { + prop1: "prop1", + prop2: 2 + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Model creation failed. First argument must be a string when two arguments are provided"` + ) + }) + } + }) + describe("when we provide three arguments to the function", () => { + test("the model gets the correct name", () => { + // @ts-ignore + const Model = types.model("name", {}, {}) + + expect(Model.name).toBe("name") + }) + test("the model gets the correct properties", () => { + const Model = types.model( + "name", + { + prop1: "prop1", + prop2: 2 + }, + // @ts-ignore + {} + ) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + prop1: "prop1", + prop2: 2 + }) + }) + }) + + describe("When a model has duplicate key in actions or views", () => { + test("it should show friendly message", () => { + const UserModel = types + .model("UserModel", { + id: types.identifier, + name: types.string + }) + .views((user) => ({ + get name() { + return user.name + } + })) + + expect(() => + UserModel.create({ + id: "chakri", + name: "Subramanya Chakravarthy" + }) + ).toThrow("[mobx-state-tree] name property is declared twice") + }) + }) +}) +describe("Model properties objects", () => { + describe("when a user names a property the same as an MST lifecycle hook", () => { + test("it throws an error", () => { + const hookValues = Object.values(Hook) + + hookValues.forEach((hook) => { + expect(() => { + types.model({ + [hook]: types.string + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Hook '${hook}' was defined as property. Hooks should be defined as part of the actions"` + ) + }) + }) + }) + describe("when a user attempts to define a property with the get keyword", () => { + test("it throws an error", () => { + expect(() => { + types.model({ + get foo() { + return "bar" + } + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Getters are not supported as properties. Please use views instead"` + ) + }) + }) + describe("when a user attempts to define a property with null as the value", () => { + test("it throws an error", () => { + expect(() => { + types.model({ + foo: null as any + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean \`types.maybe(someType)\`?"` + ) + }) + }) + describe("when a user attempts to define a property with undefined as the value", () => { + test("it throws an error", () => { + expect(() => { + types.model({ + foo: undefined as any + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean \`types.maybe(someType)\`?"` + ) + }) + }) + describe("when a user defines a property using a primitive value (not null or undefined)", () => { + describe("and the primitive value is a string", () => { + test("it converts a string to an optional string", () => { + const Model = types.model({ + foo: "bar" + }) + + const modelDescription = Model.describe() + expect(modelDescription).toBe("{ foo: string? }") + }) + test("it uses the primitive value as the default value", () => { + const Model = types.model({ + foo: "bar" + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: "bar" + }) + }) + }) + describe("and the primitive value is a number", () => { + test("it converts a number to an optional number", () => { + const Model = types.model({ + foo: 1 + }) + + const modelDescription = Model.describe() + expect(modelDescription).toBe("{ foo: number? }") + }) + test("it uses the primitive value as the default value", () => { + const Model = types.model({ + foo: 1 + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: 1 + }) + }) + }) + describe("and the primitive value is a boolean", () => { + test("it converts a boolean to an optional boolean", () => { + const Model = types.model({ + foo: true + }) + + const modelDescription = Model.describe() + expect(modelDescription).toBe("{ foo: boolean? }") + }) + test("it uses the primitive value as the default value", () => { + const Model = types.model({ + foo: true + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: true + }) + }) + }) + describe("and the primitive value is a date", () => { + test("it converts a date to an optional date", () => { + const Model = types.model({ + foo: new Date() + }) + + const modelDescription = Model.describe() + expect(modelDescription).toBe("{ foo: Date? }") + }) + test("it sets a default value with the date in unix milliseconds timestamp", () => { + const date = new Date("2023-07-24T04:26:04.701Z") + const Model = types.model({ + foo: date + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: 1690172764701 + }) + }) + }) + }) + describe("when a user defines a property using a complex type", () => { + describe('and that type is "types.map"', () => { + test("it sets the default value to an empty map", () => { + const Model = types.model({ + foo: types.map(types.string) + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: {} + }) + }) + }) + describe('and that type is "types.array"', () => { + test("it sets the default value to an empty array", () => { + const Model = types.model({ + foo: types.array(types.string) + }) + + const modelSnapshot = getSnapshot(Model.create()) + expect(modelSnapshot).toEqual({ + foo: [] + }) + }) + }) + describe("and that type is another model", () => { + test("it sets the default value to the default of that model", () => { + const Todo = types.model({ + task: types.optional(types.string, "test") + }) + + const TodoStore = types.model("TodoStore", { + todo1: types.optional(Todo, () => Todo.create()) + }) + + const modelSnapshot = getSnapshot(TodoStore.create()) + expect(modelSnapshot).toEqual({ + todo1: { + task: "test" + } + }) + }) + }) + }) + describe("when a user defines a property using a function", () => { + if (process.env.NODE_ENV !== "production") { + test("it throws an error when not in production", () => { + expect(() => { + // @ts-ignore + types.model({ + foo: () => "bar" + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Invalid type definition for property 'foo', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?"` + ) + }) + } + }) + describe("when a user defins a property using a plain JavaScript object", () => { + if (process.env.NODE_ENV !== "production") { + test("it throws an error when not in production", () => { + expect(() => { + // @ts-ignore + types.model({ + foo: {} + }) + }).toThrowErrorMatchingInlineSnapshot( + `"[mobx-state-tree] Invalid type definition for property 'foo', it looks like you passed an object. Try passing another model type or a types.frozen."` + ) + }) + } + }) +}) diff --git a/__tests__/core/name.test.ts b/__tests__/core/name.test.ts new file mode 100644 index 000000000..3f30ebd5b --- /dev/null +++ b/__tests__/core/name.test.ts @@ -0,0 +1,14 @@ +import { types } from "../../src" +import { getDebugName } from "mobx" + +test("it should have a debug name", () => { + const Model = types.model("Name") + + const model = Model.create() + const array = types.array(Model).create() + const map = types.map(Model).create() + + expect(getDebugName(model)).toBe("Name") + expect(getDebugName(array)).toBe("Name[]") + expect(getDebugName(map)).toBe("Map") +}) diff --git a/__tests__/core/node.test.ts b/__tests__/core/node.test.ts new file mode 100644 index 000000000..a3c27a5b4 --- /dev/null +++ b/__tests__/core/node.test.ts @@ -0,0 +1,455 @@ +import { + getPath, + getSnapshot, + getParent, + hasParent, + getRoot, + getIdentifier, + getPathParts, + isAlive, + clone, + getType, + getChildType, + recordActions, + recordPatches, + types, + destroy, + unprotect, + hasParentOfType, + getParentOfType, + detach, + getNodeId +} from "../../src" + +import { autorun, configure } from "mobx" + +// getParent +test("it should resolve to the parent instance", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(getParent(row)).toEqual(doc.rows) +}) +// hasParent +test("it should check for parent instance", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(hasParent(row)).toEqual(true) +}) +test("it should check for parent instance (unbound)", () => { + const Row = types.model({ + article_id: 0 + }) + const row = Row.create() + expect(hasParent(row)).toEqual(false) +}) +// getParentOfType +test("it should resolve to the given parent instance", () => { + configure({ + useProxies: "never" + }) + + const Cell = types.model({}) + const Row = types.model({ + cells: types.optional(types.array(Cell), []) + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create({ + rows: [ + { + cells: [{}] + } + ] + }) + expect(getParentOfType(doc.rows[0].cells[0], Document)).toEqual(doc) +}) +test("it should throw if there is not parent of type", () => { + const Cell = types.model({}) + const Row = types.model({ + cells: types.optional(types.array(Cell), []) + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const row = Row.create({ + cells: [{}] + }) + expect(() => getParentOfType(row.cells[0], Document)).toThrowError( + "[mobx-state-tree] Failed to find the parent of AnonymousModel@/cells/0 of a given type" + ) +}) +// hasParentOfType +test("it should check for parent instance of given type", () => { + const Cell = types.model({}) + const Row = types.model({ + cells: types.optional(types.array(Cell), []) + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create({ + rows: [ + { + cells: [{}] + } + ] + }) + expect(hasParentOfType(doc.rows[0].cells[0], Document)).toEqual(true) +}) +test("it should check for parent instance of given type (unbound)", () => { + const Cell = types.model({}) + const Row = types.model({ + cells: types.optional(types.array(Cell), []) + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const row = Row.create({ + cells: [{}] + }) + expect(hasParentOfType(row.cells[0], Document)).toEqual(false) +}) +// getRoot +test("it should resolve to the root of an object", () => { + const Row = types.model("Row", { + article_id: 0 + }) + const Document = types.model("Document", { + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(getRoot(row)).toBe(doc) +}) +// getIdentifier +test("it should resolve to the identifier of the object", () => { + const Document = types.model("Document", { + id: types.identifier + }) + const doc = Document.create({ + id: "document_1" + }) + // get identifier of object + expect(getIdentifier(doc)).toBe("document_1") +}) +// getPath +test("it should resolve the path of an object", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(getPath(row)).toEqual("/rows/0") +}) +// getPathParts +test("it should resolve the path of an object", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(getPathParts(row)).toEqual(["rows", "0"]) +}) +test("it should resolve parents", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(hasParent(row)).toBe(true) // array + expect(hasParent(row, 2)).toBe(true) // row + expect(hasParent(row, 3)).toBe(false) + expect(getParent(row) === doc.rows).toBe(true) // array + expect(getParent(row, 2) === doc).toBe(true) // row + expect(() => getParent(row, 3)).toThrowError( + "[mobx-state-tree] Failed to find the parent of AnonymousModel@/rows/0 at depth 3" + ) +}) +// clone +test("it should clone a node", () => { + configure({ + useProxies: "never" + }) + + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + const cloned = clone(doc) + expect(doc).toEqual(cloned) + expect(getSnapshot(doc)).toEqual(getSnapshot(cloned)) +}) +test("it should be possible to clone a dead object", () => { + configure({ + useProxies: "never" + }) + + const Task = types.model("Task", { + x: types.string + }) + const a = Task.create({ x: "a" }) + const store = types + .model({ + todos: types.optional(types.array(Task), []) + }) + .create({ + todos: [a] + }) + unprotect(store) + expect(store.todos.slice()).toEqual([a]) + expect(isAlive(a)).toBe(true) + store.todos.splice(0, 1) + expect(isAlive(a)).toBe(false) + const a2 = clone(a) + store.todos.splice(0, 0, a2) + expect(store.todos[0].x).toBe("a") +}) +// getModelFactory +test("it should return the model factory", () => { + const Document = types.model({ + customer_id: 0 + }) + const doc = Document.create() + expect(getType(doc)).toEqual(Document) +}) +// getChildModelFactory +test("it should return the child model factory", () => { + const Row = types.model({ + article_id: 0 + }) + const ArrayOfRow = types.optional(types.array(Row), []) + const Document = types.model({ + rows: ArrayOfRow + }) + const doc = Document.create() + expect(getChildType(doc, "rows")).toEqual(ArrayOfRow) +}) +test("a node can exists only once in a tree", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + rows: types.optional(types.array(Row), []), + foos: types.optional(types.array(Row), []) + }) + const doc = Document.create() + unprotect(doc) + const row = Row.create() + doc.rows.push(row) + expect(() => { + doc.foos.push(row) + }).toThrow( + "[mobx-state-tree] Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/foos/0', but it lives already at '/rows/0'" + ) +}) +test("make sure array filter works properly", () => { + const Row = types.model({ + done: false + }) + const Document = types + .model({ + rows: types.optional(types.array(Row), []) + }) + .actions((self) => { + function clearDone() { + self.rows.filter((row) => row.done === true).forEach(destroy) + } + return { + clearDone + } + }) + const doc = Document.create() + unprotect(doc) + const a = Row.create({ done: true }) + const b = Row.create({ done: false }) + doc.rows.push(a) + doc.rows.push(b) + doc.clearDone() + expect(getSnapshot(doc)).toEqual({ rows: [{ done: false }] }) +}) +// === RECORD PATCHES === +test("it can record and replay patches", () => { + const Row = types.model({ + article_id: 0 + }) + const Document = types.model({ + customer_id: 0, + rows: types.optional(types.array(Row), []) + }) + const source = Document.create() + unprotect(source) + const target = Document.create() + const recorder = recordPatches(source) + source.customer_id = 1 + source.rows.push(Row.create({ article_id: 1 })) + recorder.replay(target) + expect(getSnapshot(source)).toEqual(getSnapshot(target)) +}) +// === RECORD ACTIONS === +test("it can record and replay actions", () => { + const Row = types + .model({ + article_id: 0 + }) + .actions((self) => { + function setArticle(article_id: number) { + self.article_id = article_id + } + return { + setArticle + } + }) + const Document = types + .model({ + customer_id: 0, + rows: types.optional(types.array(Row), []) + }) + .actions((self) => { + function setCustomer(customer_id: number) { + self.customer_id = customer_id + } + function addRow() { + self.rows.push(Row.create()) + } + return { + setCustomer, + addRow + } + }) + const source = Document.create() + const target = Document.create() + const recorder = recordActions(source) + source.setCustomer(1) + source.addRow() + source.rows[0].setArticle(1) + recorder.replay(target) + expect(getSnapshot(source)).toEqual(getSnapshot(target)) +}) + +test("Liveliness issue #683", () => { + const User = types.model({ id: types.identifierNumber, name: types.string }) + + const Users = types + .model({ + list: types.map(User) + }) + .actions((self) => ({ + put(aUser: typeof User.CreationType | typeof User.Type) { + // if (self.has(user.id)) detach(self.get(user.id)); + self.list.put(aUser) + }, + get(id: string) { + return self.list.get(id) + }, + has(id: string) { + return self.list.has(id) + } + })) + + const users = Users.create({ + list: { + 1: { name: "Name", id: 1 } + } + }) + const user = users.get("1") + expect(user!.name).toBe("Name") + + users.put({ id: 1, name: "NameX" }) + expect(user!.name).toBe("NameX") + expect(users.get("1")!.name).toBe("NameX") +}) + +test("triggers on changing paths - 1", () => { + const Todo = types.model({ + title: types.string + }) + const App = types + .model({ + todos: types.array(Todo) + }) + .actions((self) => ({ + do(fn: () => void) { + fn() + } + })) + + const t1 = Todo.create({ title: "t1 " }) + const t2 = Todo.create({ title: "t2 " }) + + const app = App.create({ + todos: [t1] + }) + + const events: string[] = [] + const d1 = autorun(() => { + events.push("t1@" + getPath(t1)) + }) + const d2 = autorun(() => { + events.push("t2@" + getPath(t2)) + }) + + expect(events.splice(0)).toEqual(["t1@/todos/0", "t2@"]) + app.do(() => { + app.todos.unshift(t2) + }) + expect(events.splice(0)).toEqual(["t2@/todos/0", "t1@/todos/1"]) + app.do(() => { + detach(t2) + }) + expect(events.splice(0)).toEqual(["t1@/todos/0", "t2@"]) + + app.do(() => { + app.todos.splice(0) + }) + expect(events.splice(0)).toEqual(["t1@"]) +}) + +test("getNodeId works", () => { + const M = types.model({}) + const m1 = M.create() + const m2 = M.create() + const m1Id = getNodeId(m1) + const m2Id = getNodeId(m2) + expect(m1Id).toBeGreaterThan(0) + expect(m2Id).toBe(m1Id + 1) +}) diff --git a/__tests__/core/object.test.ts b/__tests__/core/object.test.ts new file mode 100644 index 000000000..05c9827c2 --- /dev/null +++ b/__tests__/core/object.test.ts @@ -0,0 +1,1196 @@ +import { + destroy, + detach, + onSnapshot, + onPatch, + onAction, + applyPatch, + applyAction, + applySnapshot, + getSnapshot, + unprotect, + types, + setLivelinessChecking, + getParent, + SnapshotOut, + IJsonPatch, + ISerializedActionCall, + isAlive, + cast, + resolveIdentifier +} from "../../src" + +import { autorun, reaction, observable, configure, getDebugName } from "mobx" + +const createTestFactories = () => { + const Factory = types + .model({ + to: "world" + }) + .actions((self) => { + function setTo(to: string) { + self.to = to + } + return { + setTo + } + }) + const ComputedFactory = types + .model({ + width: 100, + height: 200 + }) + .views((self) => ({ + get area() { + return self.width * self.height + } + })) + const ComputedFactory2 = types + .model({ + props: types.map(types.number) + }) + .views((self) => ({ + get area() { + return self.props.get("width")! * self.props.get("height")! + } + })) + .actions((self) => { + function setWidth(value: number) { + self.props.set("width", value) + } + function setHeight(value: number) { + self.props.set("height", value) + } + return { + setWidth, + setHeight + } + }) + const BoxFactory = types.model({ + width: 0, + height: 0 + }) + const ColorFactory = types.model({ + color: "#FFFFFF" + }) + return { Factory, ComputedFactory, ComputedFactory2, BoxFactory, ColorFactory } +} + +const createFactoryWithChildren = () => { + const File = types + .model("File", { + name: types.string + }) + .actions((self) => ({ + rename(value: string) { + self.name = value + } + })) + + const Folder = types + .model("Folder", { + name: types.string, + files: types.array(File) + }) + .actions((self) => ({ + rename(value: string) { + self.name = value + } + })) + return Folder +} +// === FACTORY TESTS === +test("it should create a factory", () => { + const { Factory } = createTestFactories() + const instance = Factory.create() + const snapshot = getSnapshot(instance) + expect(snapshot).toEqual({ to: "world" }) + expect(getSnapshot(Factory.create())).toEqual({ to: "world" }) // toJSON is there as shortcut for getSnapshot(), primarily for debugging convenience + expect(Factory.create().toString()).toEqual("AnonymousModel@") +}) +test("it should restore the state from the snapshot", () => { + const { Factory } = createTestFactories() + expect(getSnapshot(Factory.create({ to: "universe" }))).toEqual({ to: "universe" }) +}) +// === SNAPSHOT TESTS === +test("it should emit snapshots", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let snapshots: SnapshotOut[] = [] + onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) + doc.to = "universe" + expect(snapshots).toEqual([{ to: "universe" }]) +}) + +test("it should emit snapshots for children", () => { + const Factory = createFactoryWithChildren() + const folder = Factory.create({ + name: "Photos to sort", + files: [ + { + name: "Photo1" + }, + { + name: "Photo2" + } + ] + }) + let snapshotsP: SnapshotOut[] = [] + let snapshotsC: SnapshotOut[] = [] + onSnapshot(folder, (snapshot) => snapshotsP.push(snapshot)) + folder.rename("Vacation photos") + expect(snapshotsP[0]).toEqual({ + name: "Vacation photos", + files: [{ name: "Photo1" }, { name: "Photo2" }] + }) + + onSnapshot(folder.files[0], (snapshot) => snapshotsC.push(snapshot)) + folder.files[0].rename("01-arrival") + expect(snapshotsP[1]).toEqual({ + name: "Vacation photos", + files: [{ name: "01-arrival" }, { name: "Photo2" }] + }) + expect(snapshotsC[0]).toEqual({ name: "01-arrival" }) + + folder.files[1].rename("02-hotel") + expect(snapshotsP[2]).toEqual({ + name: "Vacation photos", + files: [{ name: "01-arrival" }, { name: "02-hotel" }] + }) + expect(snapshotsP.length).toBe(3) + expect(snapshotsC.length).toBe(1) +}) + +test("it should apply snapshots", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + applySnapshot(doc, { to: "universe" }) + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +test("it should apply and accept null value for types.maybe(complexType)", () => { + const Item = types.model("Item", { + value: types.string + }) + const Model = types.model("Model", { + item: types.maybe(Item) + }) + const myModel = Model.create() + applySnapshot(myModel, { item: { value: "something" } }) + applySnapshot(myModel, { item: undefined }) + expect(getSnapshot(myModel)).toEqual({ item: undefined }) +}) +test("it should apply and accept null value for types.maybeNull(complexType)", () => { + const Item = types.model("Item", { + value: types.string + }) + const Model = types.model("Model", { + item: types.maybeNull(Item) + }) + const myModel = Model.create() + applySnapshot(myModel, { item: { value: "something" } }) + applySnapshot(myModel, { item: null }) + expect(getSnapshot(myModel)).toEqual({ item: null }) +}) +test("it should return a snapshot", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + expect(getSnapshot(doc)).toEqual({ to: "world" }) +}) +// === PATCHES TESTS === +test("it should emit patches", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + doc.to = "universe" + expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) +}) +test("it should apply a patch", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, { op: "replace", path: "/to", value: "universe" }) + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +test("it should apply patches", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + applyPatch(doc, [ + { op: "replace", path: "/to", value: "mars" }, + { op: "replace", path: "/to", value: "universe" } + ]) + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +test("it should stop listening to patches patches", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + unprotect(doc) + let patches: IJsonPatch[] = [] + let disposer = onPatch(doc, (patch) => patches.push(patch)) + doc.to = "universe" + disposer() + doc.to = "mweststrate" + expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) +}) +// === ACTIONS TESTS === +test("it should call actions correctly", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + doc.setTo("universe") + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +test("it should emit action calls", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + let actions: ISerializedActionCall[] = [] + onAction(doc, (action) => actions.push(action)) + doc.setTo("universe") + expect(actions).toEqual([{ name: "setTo", path: "", args: ["universe"] }]) +}) +test("it should apply action call", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + applyAction(doc, { name: "setTo", path: "", args: ["universe"] }) + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +test("it should apply actions calls", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + applyAction(doc, [ + { name: "setTo", path: "", args: ["mars"] }, + { name: "setTo", path: "", args: ["universe"] } + ]) + expect(getSnapshot(doc)).toEqual({ to: "universe" }) +}) +// === COMPUTED VALUES === +test("it should have computed properties", () => { + const { ComputedFactory } = createTestFactories() + const doc = ComputedFactory.create() + unprotect(doc) + doc.width = 3 + doc.height = 2 + expect(doc.area).toEqual(6) +}) + +test("it should throw if a replaced object is read or written to", () => { + const Todo = types + .model("Todo", { + title: "test", + arr: types.array(types.string), + map: types.map(types.string), + sub: types.optional( + types + .model("Sub", { + title: "test2" + }) + .actions((self) => ({ + fn2() {} + })), + {} + ) + }) + .actions((self) => ({ + fn() { + self.sub.fn2() + } + })) + const Store = types.model("Store", { + todo: Todo + }) + const data = { + title: "alive", + arr: ["arr0"], + map: { mapkey0: "mapval0" }, + sub: { title: "title" } + } + const s = Store.create({ todo: { ...data, title: "dead" } }) + unprotect(s) + + const deadArr = s.todo.arr + s.todo.arr = cast(data.arr) + + const deadMap = s.todo.map + s.todo.map = cast(data.map) + + const deadSub = s.todo.sub + s.todo.sub = cast(data.sub) + + const deadTodo = s.todo + s.todo = Todo.create(data) + + expect(s.todo.title).toBe("alive") + + setLivelinessChecking("error") + + function getError(obj: any, path: string, subpath: string, action: string) { + return `You are trying to read or write to an object that is no longer part of a state tree. (Object type: '${getDebugName( + obj + )}', Path upon death: '${path}', Subpath: '${subpath}', Action: '${action}'). Either detach nodes first, or don't use objects after removing / replacing them in the tree.` + } + + // dead todo + expect(() => { + deadTodo.fn() + }).toThrow(getError(deadTodo, "/todo", "", "/todo.fn()")) + expect(() => { + // tslint:disable-next-line:no-unused-expression + deadTodo.title + }).toThrow(getError(deadTodo, "/todo", "title", "")) + expect(() => { + deadTodo.title = "5" + }).toThrow(getError(deadTodo, "/todo", "title", "")) + + expect(() => { + // tslint:disable-next-line:no-unused-expression + deadTodo.arr[0] + }).toThrow(getError(deadTodo, "/todo", "arr", "")) + expect(() => { + deadTodo.arr.push("arr1") + }).toThrow(getError(deadTodo, "/todo", "arr", "")) + + expect(() => { + deadTodo.map.get("mapkey0") + }).toThrow(getError(deadTodo, "/todo", "map", "")) + expect(() => { + deadTodo.map.set("mapkey1", "val") + }).toThrow(getError(deadTodo, "/todo", "map", "")) + + expect(() => { + deadTodo.sub.fn2() + }).toThrow(getError(deadTodo, "/todo", "sub", "")) + expect(() => { + // tslint:disable-next-line:no-unused-expression + deadTodo.sub.title + }).toThrow(getError(deadTodo, "/todo", "sub", "")) + expect(() => { + deadTodo.sub.title = "hi" + }).toThrow(getError(deadTodo, "/todo", "sub", "")) + + // dead array + expect(() => { + // tslint:disable-next-line:no-unused-expression + deadArr[0] + }).toThrow(getError(deadArr, "/todo/arr", "0", "")) + expect(() => { + deadArr[0] = "hi" + }).toThrow(getError(deadArr, "/todo/arr", "0", "")) + expect(() => { + deadArr.push("hi") + }).toThrow(getError(deadArr, "/todo/arr", "1", "")) + + // dead map + expect(() => { + deadMap.get("mapkey0") + }).toThrow(getError(deadMap, "/todo/map", "mapkey0", "")) + expect(() => { + deadMap.set("mapkey0", "val") + }).toThrow(getError(deadMap, "/todo/map", "mapkey0", "")) + + // dead subobj + expect(() => { + deadSub.fn2() + }).toThrow(getError(deadSub, "/todo/sub", "", "/todo/sub.fn2()")) + expect(() => { + // tslint:disable-next-line:no-unused-expression + deadSub.title + }).toThrow(getError(deadSub, "/todo/sub", "title", "")) + expect(() => { + deadSub.title = "ho" + }).toThrow(getError(deadSub, "/todo/sub", "title", "")) +}) + +test("it should warn if a replaced object is read or written to", () => { + const Todo = types + .model("Todo", { + title: "test" + }) + .actions((self) => { + function fn() {} + return { + fn + } + }) + const Store = types.model("Store", { + todo: Todo + }) + const s = Store.create({ + todo: { title: "3" } + }) + unprotect(s) + const todo = s.todo + s.todo = Todo.create({ title: "4" }) + expect(s.todo.title).toBe("4") + + // try reading old todo + setLivelinessChecking("error") + const error = + "You are trying to read or write to an object that is no longer part of a state tree" + expect(() => todo.fn()).toThrow(error) + expect(() => todo.title).toThrow(error) + unprotect(todo) + expect(() => { + todo.title = "5" + }).toThrow(error) +}) + +// === COMPOSE FACTORY === +test("it should compose factories", () => { + const { BoxFactory, ColorFactory } = createTestFactories() + const ComposedFactory = types.compose(BoxFactory, ColorFactory) + expect(getSnapshot(ComposedFactory.create())).toEqual({ width: 0, height: 0, color: "#FFFFFF" }) +}) +test("it should compose factories with computed properties", () => { + const { ComputedFactory2, ColorFactory } = createTestFactories() + const ComposedFactory = types.compose(ColorFactory, ComputedFactory2) + const store = ComposedFactory.create({ props: { width: 100, height: 200 } }) + expect(getSnapshot(store)).toEqual({ props: { width: 100, height: 200 }, color: "#FFFFFF" }) + expect(store.area).toBe(20000) + expect(typeof store.setWidth).toBe("function") + expect(typeof store.setHeight).toBe("function") +}) +test("it should compose multiple types with computed properties", () => { + const { ComputedFactory2, ColorFactory } = createTestFactories() + const ComposedFactory = types.compose(ColorFactory, ComputedFactory2) + const store = ComposedFactory.create({ props: { width: 100, height: 200 } }) + expect(getSnapshot(store)).toEqual({ props: { width: 100, height: 200 }, color: "#FFFFFF" }) + expect(store.area).toBe(20000) + expect(typeof store.setWidth).toBe("function") + expect(typeof store.setHeight).toBe("function") +}) +test("methods get overridden by compose", () => { + const A = types + .model({ + count: types.optional(types.number, 0) + }) + .actions((self) => { + function increment() { + self.count += 1 + } + return { + increment + } + }) + const B = A.actions((self) => ({ + increment() { + self.count += 10 + } + })) + const store = B.create() + expect(getSnapshot(store)).toEqual({ count: 0 }) + expect(store.count).toBe(0) + store.increment() + expect(store.count).toBe(10) +}) +test("compose should add new props", () => { + const A = types.model({ + count: types.optional(types.number, 0) + }) + const B = A.props({ + called: types.optional(types.number, 0) + }) + const store = B.create() + expect(getSnapshot(store)).toEqual({ count: 0, called: 0 }) + expect(store.count).toBe(0) +}) +test("models should expose their actions to be used in a composable way", () => { + const A = types + .model({ + count: types.optional(types.number, 0) + }) + .actions((self) => { + function increment() { + self.count += 1 + } + return { + increment + } + }) + const B = A.props({ + called: types.optional(types.number, 0) + }).actions((self) => { + const baseIncrement = self.increment + return { + increment() { + baseIncrement() + self.called += 1 + } + } + }) + const store = B.create() + expect(getSnapshot(store)).toEqual({ count: 0, called: 0 }) + expect(store.count).toBe(0) + store.increment() + expect(store.count).toBe(1) + expect(store.called).toBe(1) +}) +test("compose should be overwrite", () => { + const A = types + .model({ + name: "", + alias: "" + }) + .views((self) => ({ + get displayName() { + return self.alias || self.name + } + })) + const B = A.props({ + type: "" + }).views((self) => ({ + get displayName() { + return self.alias || self.name + self.type + } + })) + const storeA = A.create({ name: "nameA", alias: "aliasA" }) + const storeB = B.create({ name: "nameB", alias: "aliasB", type: "typeB" }) + const storeC = B.create({ name: "nameC", type: "typeC" }) + expect(storeA.displayName).toBe("aliasA") + expect(storeB.displayName).toBe("aliasB") + expect(storeC.displayName).toBe("nameCtypeC") +}) +// === TYPE CHECKS === +test("it should check the type correctly", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + expect(Factory.is(doc)).toEqual(true) + expect(Factory.is([])).toEqual(false) + expect(Factory.is({})).toEqual(true) + expect(Factory.is({ to: "mars" })).toEqual(true) + expect(Factory.is({ wrongKey: true })).toEqual(true) + expect(Factory.is({ to: 3 })).toEqual(false) +}) + +if (process.env.NODE_ENV !== "production") { + test("complex map / array values are optional by default", () => { + expect( + types + .model({ + todo: types.model({}) + }) + .is({}) + ).toBe(false) + expect(() => + types + .model({ + todo: types.model({}) + }) + .create({} as any) + ).toThrow() + expect( + types + .model({ + todo: types.array(types.string) + }) + .is({}) + ).toBe(true) // TBD: or true? + expect( + getSnapshot( + types + .model({ + todo: types.array(types.string) + }) + .create({}) + ) + ).toEqual({ todo: [] }) + expect( + types + .model({ + todo: types.map(types.string) + }) + .is({}) + ).toBe(true) + expect( + getSnapshot( + types + .model({ + todo: types.map(types.string) + }) + .create({}) + ) + ).toEqual({ todo: {} }) + }) +} +// === VIEW FUNCTIONS === +test("view functions should be tracked", () => { + const model = types + .model({ + x: 3 + }) + .views((self) => ({ + doubler() { + return self.x * 2 + } + })) + .create() + unprotect(model) + const values: number[] = [] + const d = autorun(() => { + values.push(model.doubler()) + }) + model.x = 7 + expect(values).toEqual([6, 14]) +}) +test("view functions should not be allowed to change state", () => { + const model = types + .model({ + x: 3 + }) + .views((self) => ({ + doubler() { + self.x *= 2 + } + })) + .actions((self) => { + function anotherDoubler() { + self.x *= 2 + } + return { + anotherDoubler + } + }) + .create() + expect(() => model.doubler()).toThrow() + model.anotherDoubler() + expect(model.x).toBe(6) +}) +test("it should consider primitives as proposed defaults", () => { + const now = new Date() + const Todo = types.model({ + id: 0, + name: "Hello world", + done: false, + createdAt: now + }) + const doc = Todo.create() + expect(getSnapshot(doc)).toEqual({ + id: 0, + name: "Hello world", + done: false, + createdAt: now.getTime() + }) +}) +test("it should throw if a non-primitive value is provided and no default can be created", () => { + expect(() => { + types.model({ + complex: { + a: 1, + b: 2 + } as any + }) + }).toThrow() +}) +if (process.env.NODE_ENV !== "production") { + test("it should not be possible to remove a node from a parent if it is required, see ", () => { + const A = types.model("A", { x: 3 }) + const B = types.model("B", { a: A }) + const b = B.create({ a: { x: 7 } }) + unprotect(b) + expect(() => { + detach(b.a) + }).toThrowError(/Error while converting `undefined` to `A`/) + expect(() => { + destroy(b.a) + }).toThrowError(/Error while converting `undefined` to `A`/) + }) + test("it should be possible to remove a node from a parent if it is defined as type maybe ", () => { + const A = types.model("A", { x: 3 }) + const B = types.model("B", { a: types.maybe(A) }) + const b = B.create({ a: { x: 7 } }) + unprotect(b) + expect(() => { + const a = b.a! + detach(a) + destroy(a) + }).not.toThrow() + expect(b.a).toBe(undefined) + expect(getSnapshot(b).a).toBe(undefined) + }) + test("it should be possible to remove a node from a parent if it is defined as type maybeNull ", () => { + const A = types.model("A", { x: 3 }) + const B = types.model("B", { a: types.maybeNull(A) }) + const b = B.create({ a: { x: 7 } }) + unprotect(b) + expect(() => { + const a = b.a! + detach(a) + destroy(a) + }).not.toThrow() + expect(b.a).toBe(null) + expect(getSnapshot(b).a).toBe(null) + }) +} +test("it should be possible to share states between views and actions using enhance", () => { + const A = types.model({}).extend((self) => { + const localState = observable.box(3) + return { + views: { + get x() { + return localState.get() + } + }, + actions: { + setX(value: number) { + localState.set(value) + } + } + } + }) + let x = 0 + let a = A.create() + const d = reaction( + () => a.x, + (v) => { + x = v + } + ) + a.setX(7) + expect(a.x).toBe(7) + expect(x).toBe(7) + d() +}) +test("It should throw if any other key is returned from extend", () => { + const A = types.model({}).extend(() => ({ stuff() {} } as any)) + expect(() => A.create()).toThrowError(/stuff/) +}) + +test("782, TS + compose", () => { + const User = types.model("User", { + id: types.identifier, + name: types.maybe(types.string), + avatar: types.maybe(types.string) + }) + + const user = User.create({ id: "someId" }) +}) + +test("961 - model creating should not change snapshot", () => { + const M = types.model({ foo: 1 }) + const o = {} + + const m = M.create(o) + expect(o).toEqual({}) + expect(getSnapshot(m)).toEqual({ foo: 1 }) +}) + +if (process.env.NODE_ENV === "development") + test("beautiful errors", () => { + expect(() => { + types.model("User", { x: (types.identifier as any)() }) + }).toThrow("types.identifier is not a function") + expect(() => { + types.model("User", { x: { bla: true } as any }) + }).toThrow( + "Invalid type definition for property 'x', it looks like you passed an object. Try passing another model type or a types.frozen" + ) + expect(() => { + types.model("User", { x: function () {} as any }) + }).toThrow( + "Invalid type definition for property 'x', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?" + ) + }) + +test("#967 - changing values in afterCreate/afterAttach when node is instantiated from view", () => { + const Answer = types + .model("Answer", { + title: types.string, + selected: false + }) + .actions((self) => ({ + toggle() { + self.selected = !self.selected + } + })) + const Question = types + .model("Question", { title: types.string, answers: types.array(Answer) }) + .views((self) => ({ + get brokenView() { + // this should not be allowed + // MWE: disabled, MobX 6 no longer forbids this + // expect(() => { + // self.answers[0].toggle() + // }).toThrow() + return 0 + } + })) + .actions((self) => ({ + afterCreate() { + // we should allow changes even when inside a computed property when done inside afterCreate/afterAttach + self.answers[0].toggle() + // but not further computed changes + expect(self.brokenView).toBe(0) + }, + afterAttach() { + // we should allow changes even when inside a computed property when done inside afterCreate/afterAttach + self.answers[0].toggle() + expect(self.brokenView).toBe(0) + } + })) + + const Product = types + .model("Product", { + questions: types.array(Question) + }) + .views((self) => ({ + get selectedAnswers() { + const result = [] + for (const question of self.questions) { + result.push(question.answers.find((a) => a.selected)) + } + return result + } + })) + + const product = Product.create({ + questions: [ + { title: "Q 0", answers: [{ title: "A 0.0" }, { title: "A 0.1" }] }, + { title: "Q 1", answers: [{ title: "A 1.0" }, { title: "A 1.1" }] } + ] + }) + + // tslint:disable-next-line:no-unused-expression + product.selectedAnswers +}) + +test("#993-1 - after attach should have a parent when accesing a reference directly", () => { + const L4 = types + .model("Todo", { + id: types.identifier, + finished: false + }) + .actions((self) => ({ + afterAttach() { + expect(getParent(self)).toBeTruthy() + } + })) + + const L3 = types.model({ l4: L4 }).actions((self) => ({ + afterAttach() { + expect(getParent(self)).toBeTruthy() + } + })) + + const L2 = types + .model({ + l3: L3 + }) + .actions((self) => ({ + afterAttach() { + expect(getParent(self)).toBeTruthy() + } + })) + + const L1 = types + .model({ + l2: L2, + selected: types.reference(L4) + }) + .actions((self) => ({ + afterAttach() { + throw fail("should never be called") + } + })) + + const createL1 = () => + L1.create({ + l2: { + l3: { + l4: { + id: "11124091-11c1-4dda-b2ed-7dd6323491a5" + } + } + }, + selected: "11124091-11c1-4dda-b2ed-7dd6323491a5" + }) + + // test 1, real child first + { + const l1 = createL1() + + const a = l1.l2.l3.l4 + const b = l1.selected + } + + // test 2, reference first + { + const l1 = createL1() + + const a = l1.selected + const b = l1.l2.l3.l4 + } +}) + +test("#993-2 - references should have a parent even when the parent has not been accessed before", () => { + const events: string[] = [] + + const L4 = types + .model("Todo", { + id: types.identifier, + finished: false + }) + .actions((self) => ({ + toggle() { + self.finished = !self.finished + }, + afterCreate() { + events.push("l4-ac") + }, + afterAttach() { + events.push("l4-at") + } + })) + + const L3 = types.model({ l4: L4 }).actions((self) => ({ + afterCreate() { + events.push("l3-ac") + }, + afterAttach() { + events.push("l3-at") + } + })) + + const L2 = types + .model({ + l3: L3 + }) + .actions((self) => ({ + afterCreate() { + events.push("l2-ac") + }, + afterAttach() { + events.push("l2-at") + } + })) + + const L1 = types + .model({ + l2: L2, + selected: types.reference(L4) + }) + .actions((self) => ({ + afterCreate() { + events.push("l1-ac") + }, + afterAttach() { + events.push("l1-at") + } + })) + + const createL1 = () => + L1.create({ + l2: { + l3: { + l4: { + id: "11124091-11c1-4dda-b2ed-7dd6323491a5" + } + } + }, + selected: "11124091-11c1-4dda-b2ed-7dd6323491a5" + }) + + const expectedEvents = [ + "l1-ac", + "l2-ac", + "l2-at", + "l3-ac", + "l3-at", + "l4-ac", + "l4-at", + "onSnapshot", + "-", + "onSnapshot" + ] + + // test 1, real child first + { + const l1 = createL1() + onSnapshot(l1, () => { + events.push("onSnapshot") + }) + + l1.l2.l3.l4.toggle() + events.push("-") + l1.selected.toggle() + expect(events).toEqual(expectedEvents) + } + + const expectedEvents2 = [ + "l1-ac", + "l4-ac", + "l3-ac", + "l2-ac", + "l2-at", + "l3-at", + "l4-at", + "onSnapshot", + "-", + "onSnapshot" + ] + + // test 2, reference first + // the order of hooks is different but they are all called + events.length = 0 + { + const l1 = createL1() + onSnapshot(l1, () => { + events.push("onSnapshot") + }) + + l1.selected.toggle() + events.push("-") + l1.l2.l3.l4.toggle() + expect(events).toEqual(expectedEvents2) + } + + // test 3, reference get parent should be available from the beginning and all the way to the root + { + const rootL1 = createL1() + const l4 = rootL1.selected + const l3 = getParent(l4) + expect(l3).toBeTruthy() + const l2 = getParent(l3) + expect(l2).toBeTruthy() + const l1 = getParent(l2) + expect(l1).toBeTruthy() + + expect(l1).toBe(rootL1) + expect(l2).toBe(rootL1.l2) + expect(l3).toBe(rootL1.l2.l3) + expect(l4).toBe(rootL1.l2.l3.l4) + } +}) + +test("it should emit patches when applySnapshot is used", () => { + const { Factory } = createTestFactories() + const doc = Factory.create() + let patches: IJsonPatch[] = [] + onPatch(doc, (patch) => patches.push(patch)) + applySnapshot(doc, { ...getSnapshot(doc), to: "universe" }) + expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) +}) + +test("isAlive must be reactive", () => { + const Todo = types.model({ text: types.string }) + const TodoStore = types.model({ + todos: types.array(Todo), + todo: types.maybe(Todo) + }) + + const store = TodoStore.create({ + todos: [{ text: "1" }, { text: "2" }], + todo: { text: "3" } + }) + unprotect(store) + + const t1 = store.todos[0]! + const t2 = store.todos[1]! + const t3 = store.todo! + + let calls = 0 + const r1 = reaction( + () => isAlive(t1), + (v) => { + expect(v).toBe(false) + calls++ + } + ) + const r2 = reaction( + () => isAlive(t2), + (v) => { + expect(v).toBe(false) + calls++ + } + ) + const r3 = reaction( + () => isAlive(t3), + (v) => { + expect(v).toBe(false) + calls++ + } + ) + + try { + store.todos = cast([]) + store.todo = undefined + + expect(calls).toBe(3) + } finally { + r1() + r2() + r3() + } +}) + +test("#1112 - identifier cache should be cleared for unaccessed wrapped objects", () => { + const mock1 = [ + { id: "1", name: "Kate" }, + { id: "2", name: "John" } + ] + const mock2 = [ + { id: "3", name: "Andrew" }, + { id: "2", name: "John" } + ] + + const mock1_2 = mock1.map((i, index) => ({ text: `Text${index}`, entity: i })) + const mock2_2 = mock2.map((i, index) => ({ text: `Text${index}`, entity: i })) + + const Entity = types.model({ + id: types.identifier, + name: types.string + }) + + const Wrapper = types.model({ + text: types.string, + entity: Entity + }) + + const Store = types + .model({ + list: types.optional(types.array(Wrapper), []), + selectedId: 2 + }) + .views((self) => ({ + get selectedEntity() { + return resolveIdentifier(Entity, self, self.selectedId) + } + })) + + const store = Store.create() + unprotect(store) + + store.list.replace(mock1_2) + store.list.replace(mock2_2) + + expect(store.selectedEntity!.id).toBe("2") +}) + +test("#1173 - detaching a model should not screw it", () => { + const AM = types.model({ x: 5 }) + const Store = types.model({ item: types.maybe(AM) }) + const s = Store.create({ item: { x: 6 } }) + const n0 = s.item + + unprotect(s) + + const detachedItem = detach(s.item!) + expect(s.item).not.toBe(detachedItem) + expect(s.item).toBe(undefined) + expect(detachedItem.x).toBe(6) + expect(detachedItem).toBe(n0) +}) + +test("#1702 - should not throw with useProxies: 'ifavailable'", () => { + configure({ + useProxies: "ifavailable" + }) + + const M = types.model({ x: 5 }).views((self) => ({ + get y() { + return self.x + } + })) + + expect(() => { + M.create({}) + }).not.toThrow() +}) diff --git a/__tests__/core/optimizations.test.ts b/__tests__/core/optimizations.test.ts new file mode 100644 index 000000000..ad9bfdb6d --- /dev/null +++ b/__tests__/core/optimizations.test.ts @@ -0,0 +1,38 @@ +import { getSnapshot, applySnapshot, unprotect, types } from "../../src" + +test("it should avoid processing patch if is exactly the current one in applySnapshot", () => { + const Model = types.model({ + a: types.number, + b: types.string + }) + const store = Model.create({ a: 1, b: "hello" }) + const snapshot = getSnapshot(store) + applySnapshot(store, snapshot) + expect(getSnapshot(store)).toBe(snapshot) // no new snapshot emitted +}) +test("it should avoid processing patch if is exactly the current one in reconcile", () => { + const Model = types.model({ + a: types.number, + b: types.string + }) + const RootModel = types.model({ + a: Model + }) + const store = RootModel.create({ a: { a: 1, b: "hello" } }) + unprotect(store) + // NOTE: snapshots are not equal after property access anymore, + // so we test initial and actual ones separately + const snapshot = getSnapshot(store) + expect(getSnapshot(store)).toEqual(snapshot) + + store.a = snapshot.a + // check whether reconciliation works on initial values + expect(getSnapshot(store)).toEqual(snapshot) + + // access property to initialize observable instance + expect(getSnapshot(store.a)).toEqual(snapshot.a) + + // check whether initializing instance does not cause snapshot invalidation + const actualSnapshot = getSnapshot(store) + expect(actualSnapshot.a).toBe(snapshot.a) +}) diff --git a/__tests__/core/optional-extension.test.ts b/__tests__/core/optional-extension.test.ts new file mode 100644 index 000000000..3a894ef13 --- /dev/null +++ b/__tests__/core/optional-extension.test.ts @@ -0,0 +1,326 @@ +import { getSnapshot, types, unprotect } from "../../src" + +describe("null as default", () => { + describe("basic tests", () => { + const M = types.model({ + x: types.optional(types.number, 1, [null]), + y: types.optional(types.number, () => 2, [null]) + }) + + test("with optional values, then assigned values", () => { + const m = M.create({ + x: null, + y: null + }) + unprotect(m) + + expect(m.x).toBe(1) + expect(m.y).toBe(2) + + expect(getSnapshot(m)).toEqual({ + x: 1, + y: 2 + }) + + m.x = 10 + m.y = 20 + expect(m.x).toBe(10) + expect(m.y).toBe(20) + + expect(getSnapshot(m)).toEqual({ + x: 10, + y: 20 + }) + }) + + test("with given values, then assigned optional values", () => { + const m = M.create({ + x: 10, + y: 20 + }) + unprotect(m) + + expect(m.x).toBe(10) + expect(m.y).toBe(20) + + expect(getSnapshot(m)).toEqual({ + x: 10, + y: 20 + }) + + m.x = null as any + m.y = null as any + expect(m.x).toBe(1) + expect(m.y).toBe(2) + + expect(getSnapshot(m)).toEqual({ + x: 1, + y: 2 + }) + }) + }) + + test("when the underlying type accepts undefined it should be ok", () => { + const M = types.model({ + a: types.optional(types.union(types.undefined, types.number), undefined, [null]), + b: types.optional(types.union(types.undefined, types.number), 5, [null]) + }) + + { + const m = M.create({ + a: null, + b: null + }) + expect(m.a).toBe(undefined) + expect(m.b).toBe(5) + expect(getSnapshot(m)).toEqual({ + a: undefined, + b: 5 + }) + } + + { + const m = M.create({ + a: 10, + b: 20 + }) + expect(m.a).toBe(10) + expect(m.b).toBe(20) + expect(getSnapshot(m)).toEqual({ + a: 10, + b: 20 + }) + } + + { + const m = M.create({ + a: undefined, + b: undefined + }) + expect(m.a).toBe(undefined) + expect(m.b).toBe(undefined) + expect(getSnapshot(m)).toEqual({ + a: undefined, + b: undefined + }) + } + }) + + test("when the underlying type does not accept undefined, then undefined should throw", () => { + const M = types.model({ + a: types.optional(types.number, 5, [null]), + b: types.optional(types.number, 6, [null]) + }) + + { + const m = M.create({ + a: null, + b: null + }) + expect(m.a).toBe(5) + expect(m.b).toBe(6) + } + + if (process.env.NODE_ENV !== "production") { + expect(() => { + M.create({ + a: null, + b: undefined as any // undefined is not valid + }) + }).toThrowError("value `undefined` is not assignable to type: `number`") + + expect(() => { + M.create({ + a: null + // b: null missing, but should be there + } as any) + }).toThrowError("value `undefined` is not assignable to type: `number`") + } + }) +}) + +describe("'empty' or false as default", () => { + describe("basic tests", () => { + const M = types.model({ + x: types.optional(types.number, 1, ["empty", false]), + y: types.optional(types.number, () => 2, ["empty", false]) + }) + + test("with optional values, then assigned values", () => { + const m = M.create({ + x: "empty", + y: false + }) + unprotect(m) + + expect(m.x).toBe(1) + expect(m.y).toBe(2) + + expect(getSnapshot(m)).toEqual({ + x: 1, + y: 2 + }) + + m.x = 10 + m.y = 20 + expect(m.x).toBe(10) + expect(m.y).toBe(20) + + expect(getSnapshot(m)).toEqual({ + x: 10, + y: 20 + }) + }) + + test("with given values, then assigned 'empty'", () => { + const m = M.create({ + x: 10, + y: 20 + }) + unprotect(m) + + expect(m.x).toBe(10) + expect(m.y).toBe(20) + + expect(getSnapshot(m)).toEqual({ + x: 10, + y: 20 + }) + + m.x = "empty" as any + m.y = false as any + expect(m.x).toBe(1) + expect(m.y).toBe(2) + + expect(getSnapshot(m)).toEqual({ + x: 1, + y: 2 + }) + }) + }) + + test("when the underlying type accepts undefined it should be ok", () => { + const M = types.model({ + a: types.optional(types.union(types.undefined, types.number), undefined, ["empty", false]), + b: types.optional(types.union(types.undefined, types.number), 5, ["empty", false]) + }) + + { + const m = M.create({ + a: "empty", + b: false + }) + expect(m.a).toBe(undefined) + expect(m.b).toBe(5) + expect(getSnapshot(m)).toEqual({ + a: undefined, + b: 5 + }) + } + + { + const m = M.create({ + a: 10, + b: 20 + }) + expect(m.a).toBe(10) + expect(m.b).toBe(20) + expect(getSnapshot(m)).toEqual({ + a: 10, + b: 20 + }) + } + + { + const m = M.create({ + a: undefined, + b: undefined + }) + expect(m.a).toBe(undefined) + expect(m.b).toBe(undefined) + expect(getSnapshot(m)).toEqual({ + a: undefined, + b: undefined + }) + } + }) + + test("when the underlying type does not accept undefined, then undefined should throw", () => { + const M = types.model({ + a: types.optional(types.number, 5, ["empty", false]), + b: types.optional(types.number, 6, ["empty", false]) + }) + + { + const m = M.create({ + a: "empty", + b: false + }) + expect(m.a).toBe(5) + expect(m.b).toBe(6) + } + + if (process.env.NODE_ENV !== "production") { + expect(() => { + M.create({ + a: undefined as any, + b: undefined as any + }) + }).toThrowError("value `undefined` is not assignable to type: `number`") + } + }) +}) + +test("cached snapshots should be ok when using default values", () => { + const M = types.model({ x: 5, y: 6 }) + const Store = types.model({ + deep: types.model({ + a: types.optional(types.undefined, undefined), + b: types.optional(types.undefined, undefined, ["empty"]), + c: types.optional(types.number, 5), + d: types.optional(types.number, 5, ["empty"]), + + a2: types.optional(types.undefined, () => undefined), + b2: types.optional(types.undefined, () => undefined, ["empty"]), + c2: types.optional(types.number, () => 5), + d2: types.optional(types.number, () => 5, ["empty"]), + + a3: types.optional(M, { y: 20 }), + b3: types.optional(M, { y: 20 }, ["empty"]), + c3: types.optional(M, () => M.create({ y: 20 })), + d3: types.optional(M, () => M.create({ y: 20 }), ["empty"]), + e3: types.optional(M, () => ({ y: 20 })), + f3: types.optional(M, () => ({ y: 20 }), ["empty"]) + }) + }) + + const s = Store.create({ + deep: { + b: "empty", + d: "empty", + b2: "empty", + d2: "empty", + b3: "empty", + d3: "empty", + f3: "empty" + } + }) + expect(getSnapshot(s)).toEqual({ + deep: { + a: undefined, + b: undefined, + c: 5, + d: 5, + a2: undefined, + b2: undefined, + c2: 5, + d2: 5, + a3: { x: 5, y: 20 }, + b3: { x: 5, y: 20 }, + c3: { x: 5, y: 20 }, + d3: { x: 5, y: 20 }, + e3: { x: 5, y: 20 }, + f3: { x: 5, y: 20 } + } + }) +}) diff --git a/__tests__/core/optional.test.ts b/__tests__/core/optional.test.ts new file mode 100644 index 000000000..3e21af6d8 --- /dev/null +++ b/__tests__/core/optional.test.ts @@ -0,0 +1,148 @@ +import { getSnapshot, types, unprotect, applySnapshot, cast } from "../../src" + +test("it should provide a default value, if no snapshot is provided", () => { + const Row = types.model({ + name: "", + quantity: 0 + }) + const Factory = types.model({ + rows: types.optional(types.array(Row), [{ name: "test" }]) + }) + const doc = Factory.create() + expect(getSnapshot(doc)).toEqual({ rows: [{ name: "test", quantity: 0 }] }) +}) + +test("it should use the snapshot if provided", () => { + const Row = types.model({ + name: "", + quantity: 0 + }) + const Factory = types.model({ + rows: types.optional(types.array(Row), [{ name: "test" }]) + }) + const doc = Factory.create({ rows: [{ name: "snapshot", quantity: 0 }] }) + expect(getSnapshot(doc)).toEqual({ rows: [{ name: "snapshot", quantity: 0 }] }) +}) + +if (process.env.NODE_ENV !== "production") { + test("it should throw if default value is invalid snapshot", () => { + const Row = types.model({ + name: types.string, + quantity: types.number + }) + const error = expect(() => { + types.model({ + rows: types.optional(types.array(Row), [{}] as any) + }) + }).toThrow() + }) + + test("it should throw bouncing errors from its sub-type", () => { + const Row = types.model({ + name: types.string, + quantity: types.number + }) + const RowList = types.optional(types.array(Row), []) + const error = expect(() => { + RowList.create([ + { name: "a", quantity: 1 }, + { name: "b", quantity: "x" } + ] as any) + }).toThrow() + }) +} + +test("it should accept a function to provide dynamic values", () => { + let defaultValue = 1 + const Factory = types.model({ + a: types.optional(types.number, () => defaultValue) + }) + expect(getSnapshot(Factory.create())).toEqual({ a: 1 }) + defaultValue = 2 + expect(getSnapshot(Factory.create())).toEqual({ a: 2 }) + defaultValue = "hello world!" as any + if (process.env.NODE_ENV !== "production") { + expect(() => Factory.create()).toThrowError( + `[mobx-state-tree] Error while converting \`"hello world!"\` to \`number\`:\n\n value \`"hello world!"\` is not assignable to type: \`number\` (Value is not a number).` + ) + } +}) + +test("Values should reset to default if omitted in snapshot", () => { + const Store = types.model({ + todo: types.model({ + id: types.identifier, + done: false, + title: "test", + thing: types.frozen({}) + }) + }) + const store = Store.create({ todo: { id: "2" } }) + unprotect(store) + store.todo.done = true + expect(store.todo.done).toBe(true) + store.todo = cast({ title: "stuff", id: "2" }) + expect(store.todo.title).toBe("stuff") + expect(store.todo.done).toBe(false) +}) + +test("optional frozen should fallback to default value if snapshot is undefined", () => { + const Store = types.model({ thing: types.frozen({}) }) + const store = Store.create({ + thing: null + }) + + expect(store.thing).toBeNull() + applySnapshot(store, {}) + expect(store.thing).toBeDefined() + expect(store.thing).toEqual({}) +}) + +test("an instance is not a valid default value, snapshot or function that creates instance must be used", () => { + const Row = types.model("Row", { + name: "", + quantity: 0 + }) + + // passing a node directly, without a generator function + expect(() => { + types.model({ rows: types.optional(types.array(Row), types.array(Row).create()) }) + }).toThrow( + "default value cannot be an instance, pass a snapshot or a function that creates an instance/snapshot instead" + ) + + // an alike node but created from a different yet equivalent type + const e = expect(() => { + const Factory = types.model({ + rows: types.optional(types.array(Row), () => types.array(Row).create()) + }) + // we need to create the node for it to throw, since generator functions are typechecked when nodes are created + // tslint:disable-next-line:no-unused-expression + Factory.create() + }) + if (process.env.NODE_ENV === "production") { + e.not.toThrow() + } else { + e.toThrow("Error while converting <> to `Row[]`") + } + + { + // a node created on a generator function of the exact same type + const RowArray = types.array(Row) + const Factory = types.model("Factory", { + rows: types.optional(RowArray, () => RowArray.create()) + }) + const doc = Factory.create() + expect(getSnapshot(doc)).toEqual({ rows: [] }) + } +}) + +test("undefined can work as a missing value", () => { + const M = types.model({ x: types.union(types.undefined, types.number) }) + const m1 = M.create({ x: 5 }) + expect(m1.x).toBe(5) + const m2 = M.create({ x: undefined }) + expect(m2.x).toBe(undefined) + const m3 = M.create({}) // is ok as well (even in TS) + expect(m3.x).toBe(undefined) +}) diff --git a/__tests__/core/parent-properties.test.ts b/__tests__/core/parent-properties.test.ts new file mode 100644 index 000000000..592a4cdc4 --- /dev/null +++ b/__tests__/core/parent-properties.test.ts @@ -0,0 +1,127 @@ +import { types, getEnv, getParent, getPath, cast, Instance } from "../../src" + +const ChildModel = types + .model("Child", { + parentPropertyIsNullAfterCreate: false, + parentEnvIsNullAfterCreate: false, + parentPropertyIsNullAfterAttach: false + }) + .views((self) => { + return { + get parent(): IParentModelInstance { + return getParent(self) + } + } + }) + .actions((self) => ({ + afterCreate() { + self.parentPropertyIsNullAfterCreate = typeof self.parent.fetch === "undefined" + self.parentEnvIsNullAfterCreate = typeof getEnv(self.parent).fetch === "undefined" + }, + afterAttach() { + self.parentPropertyIsNullAfterAttach = typeof self.parent.fetch === "undefined" + } + })) + +const ParentModel = types + .model("Parent", { + child: types.optional(ChildModel, {}) + }) + .views((self) => ({ + get fetch() { + return getEnv(self).fetch + } + })) + +interface IParentModelInstance extends Instance {} + +// NOTE: parents are now always created before children; +// moreover, we do not actually have actions hash during object-node creation +test("Parent property have value during child's afterCreate() event", () => { + const mockFetcher = () => Promise.resolve(true) + const parent = ParentModel.create({}, { fetch: mockFetcher }) + // Because the child is created before the parent creation is finished, this one will yield `true` (the .fetch view is still undefined) + expect(parent.child.parentPropertyIsNullAfterCreate).toBe(false) + // ... but, the env is available + expect(parent.child.parentEnvIsNullAfterCreate).toBe(false) +}) +test("Parent property has value during child's afterAttach() event", () => { + const mockFetcher = () => Promise.resolve(true) + const parent = ParentModel.create({}, { fetch: mockFetcher }) + expect(parent.child.parentPropertyIsNullAfterAttach).toBe(false) +}) + +test("#917", () => { + const SubTodo = types + .model("SubTodo", { + id: types.optional(types.number, () => Math.random()), + title: types.string, + finished: false + }) + .views((self) => ({ + get path() { + return getPath(self) + } + })) + .actions((self) => ({ + toggle() { + self.finished = !self.finished + } + })) + + const Todo = types + .model("Todo", { + id: types.optional(types.number, () => Math.random()), + title: types.string, + finished: false, + subTodos: types.array(SubTodo) + }) + .views((self) => ({ + get path() { + return getPath(self) + } + })) + .actions((self) => ({ + toggle() { + self.finished = !self.finished + } + })) + + const TodoStore = types + .model("TodoStore", { + todos: types.array(Todo) + }) + .views((self) => ({ + get unfinishedTodoCount() { + return self.todos.filter((todo) => !todo.finished).length + } + })) + .actions((self) => ({ + addTodo(title: string) { + self.todos.push({ + title, + subTodos: [ + { + title + } + ] + }) + } + })) + + const store2 = TodoStore.create({ + todos: [ + Todo.create({ + title: "get Coffee", + subTodos: [ + SubTodo.create({ + title: "test" + }) + ] + }) + ] + }) + + expect(store2.todos[0].path).toBe("/todos/0") + expect(store2.todos[0].subTodos[0].path).toBe("/todos/0/subTodos/0") +}) diff --git a/__tests__/core/pointer.test.ts b/__tests__/core/pointer.test.ts new file mode 100644 index 000000000..de22f8fae --- /dev/null +++ b/__tests__/core/pointer.test.ts @@ -0,0 +1,85 @@ +import { types, unprotect, IAnyModelType, castToReferenceSnapshot } from "../../src" + +function Pointer(Model: IT) { + return types.model("PointerOf" + Model.name, { + value: types.maybe(types.reference(Model)) + }) +} +const Todo = types.model("Todo", { + id: types.identifier, + name: types.string +}) +test("it should allow array of pointer objects", () => { + const TodoPointer = Pointer(Todo) + const AppStore = types.model("AppStore", { + todos: types.array(Todo), + selected: types.optional(types.array(TodoPointer), []) + }) + const store = AppStore.create({ + todos: [ + { id: "1", name: "Hello" }, + { id: "2", name: "World" } + ], + selected: [] + }) + unprotect(store) + const ref = TodoPointer.create({ value: castToReferenceSnapshot(store.todos[0]) }) // Fails because store.todos does not belongs to the same tree + store.selected.push(ref) + expect(store.selected[0].value).toBe(store.todos[0]) +}) +test("it should allow array of pointer objects - 2", () => { + const TodoPointer = Pointer(Todo) + const AppStore = types.model({ + todos: types.array(Todo), + selected: types.optional(types.array(TodoPointer), []) + }) + const store = AppStore.create({ + todos: [ + { id: "1", name: "Hello" }, + { id: "2", name: "World" } + ], + selected: [] + }) + unprotect(store) + const ref = TodoPointer.create() + store.selected.push(ref) + ref.value = store.todos[0] + expect(store.selected[0].value).toBe(store.todos[0]) +}) +test("it should allow array of pointer objects - 3", () => { + const TodoPointer = Pointer(Todo) + const AppStore = types.model({ + todos: types.array(Todo), + selected: types.optional(types.array(TodoPointer), []) + }) + const store = AppStore.create({ + todos: [ + { id: "1", name: "Hello" }, + { id: "2", name: "World" } + ], + selected: [] + }) + unprotect(store) + const ref = TodoPointer.create({ value: castToReferenceSnapshot(store.todos[0]) }) + store.selected.push(ref) + expect(store.selected[0].value).toBe(store.todos[0]) +}) +test("it should allow array of pointer objects - 4", () => { + const TodoPointer = Pointer(Todo) + const AppStore = types.model({ + todos: types.array(Todo), + selected: types.optional(types.array(TodoPointer), []) + }) + const store = AppStore.create({ + todos: [ + { id: "1", name: "Hello" }, + { id: "2", name: "World" } + ], + selected: [] + }) + unprotect(store) + const ref = TodoPointer.create() // Fails because ref is required + store.selected.push(ref) + ref.value = store.todos[0] + expect(ref.value).toBe(store.todos[0]) +}) diff --git a/__tests__/core/primitives.test.ts b/__tests__/core/primitives.test.ts new file mode 100644 index 000000000..d104212a6 --- /dev/null +++ b/__tests__/core/primitives.test.ts @@ -0,0 +1,107 @@ +import { isFinite, isFloat, isInteger } from "../../src/utils" +import { types, applySnapshot, getSnapshot } from "../../src" + +test("Date instance can be reused", () => { + const Model = types.model({ + a: types.model({ + b: types.string + }), + c: types.Date // types.string -> types.Date + }) + const Store = types + .model({ + one: Model, + index: types.array(Model) + }) + .actions((self) => { + function set(one: typeof Model.Type) { + self.one = one + } + function push(model: typeof Model.Type) { + self.index.push(model) + } + return { + set, + push + } + }) + const object = { a: { b: "string" }, c: new Date() } // string -> date (number) + const instance = Store.create({ + one: object, + index: [object] + }) + instance.set(object) + expect(() => instance.push(object)).not.toThrow() + expect(instance.one.c).toBe(object.c) + expect(instance.index[0].c).toBe(object.c) +}) +test("Date can be rehydrated using unix timestamp", () => { + const time = new Date() + const newTime = 6813823163 + const Factory = types.model({ + date: types.optional(types.Date, () => time) + }) + const store = Factory.create() + expect(store.date.getTime()).toBe(time.getTime()) + applySnapshot(store, { date: newTime }) + expect(store.date.getTime()).toBe(newTime) + expect(getSnapshot(store).date).toBe(newTime) +}) + +test("check isInteger", () => { + expect(isInteger(5)).toBe(true) + expect(isInteger(-5)).toBe(true) + expect(isInteger(5.2)).toBe(false) +}) + +test("Default inference for integers is 'number'", () => { + const A = types.model({ + x: 3 + }) + expect( + A.is({ + x: 2.5 + }) + ).toBe(true) +}) + +test("check isFloat", () => { + expect(isFloat(3.14)).toBe(true) + expect(isFloat(-2.5)).toBe(true) + expect(isFloat(Infinity)).toBe(true) + expect(isFloat(10)).toBe(false) + expect(isFloat(0)).toBe(false) + expect(isFloat("3.14")).toBe(false) + expect(isFloat(null)).toBe(false) + expect(isFloat(undefined)).toBe(false) + expect(isFloat(NaN)).toBe(false) +}) + +test("check isFinite", () => { + expect(isFinite(3.14)).toBe(true) + expect(isFinite(-2.5)).toBe(true) + expect(isFinite(10)).toBe(true) + expect(isFinite(0)).toBe(true) + expect(isFinite("3.14")).toBe(false) + expect(isFinite(null)).toBe(false) + expect(isFinite(undefined)).toBe(false) + expect(isFinite(NaN)).toBe(false) + expect(isFinite(Infinity)).toBe(false) +}) + +if (process.env.NODE_ENV !== "production") { + test("Passing non integer to types.integer", () => { + const Size = types.model({ + width: types.integer, + height: 20 + }) + + expect(() => { + const size = Size.create({ width: 10 }) + }).not.toThrow() + + expect(() => { + const size = Size.create({ width: 10.5 }) + }).toThrow() + }) +} diff --git a/__tests__/core/protect.test.ts b/__tests__/core/protect.test.ts new file mode 100644 index 000000000..c3017e727 --- /dev/null +++ b/__tests__/core/protect.test.ts @@ -0,0 +1,124 @@ +import { protect, unprotect, applySnapshot, types, isProtected, getParent, cast } from "../../src" + +const Todo = types + .model("Todo", { + title: "" + }) + .actions((self) => { + function setTitle(newTitle: string) { + self.title = newTitle + } + return { + setTitle + } + }) +const Store = types.model("Store", { + todos: types.array(Todo) +}) +function createTestStore() { + return Store.create({ + todos: [{ title: "Get coffee" }, { title: "Get biscuit" }] + }) +} +test("it should be possible to protect an object", () => { + const store = createTestStore() + unprotect(store) + store.todos[1].title = "A" + protect(store) + expect(() => { + store.todos[0].title = "B" + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." + ) + expect(store.todos[1].title).toBe("A") + expect(store.todos[0].title).toBe("Get coffee") + store.todos[0].setTitle("B") + expect(store.todos[0].title).toBe("B") +}) +test("protect should protect against any update", () => { + const store = createTestStore() + expect( + // apply Snapshot / patch are currently allowed, even outside protected mode + () => { + applySnapshot(store, { todos: [{ title: "Get tea" }] }) + } + ).not.toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@', the object is protected and can only be modified by using an action." + ) + expect(() => { + store.todos.push({ title: "test" }) + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo[]@/todos', the object is protected and can only be modified by using an action." + ) + expect(() => { + store.todos[0].title = "test" + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." + ) +}) +test("protect should also protect children", () => { + const store = createTestStore() + expect(() => { + store.todos[0].title = "B" + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." + ) + store.todos[0].setTitle("B") + expect(store.todos[0].title).toBe("B") +}) +test("unprotected mode should be lost when attaching children", () => { + const store = Store.create({ todos: [] }) + const t1 = Todo.create({ title: "hello" }) + unprotect(t1) + expect(isProtected(t1)).toBe(false) + expect(isProtected(store)).toBe(true) + t1.title = "world" // ok + unprotect(store) + store.todos.push(t1) + protect(store) + expect(isProtected(t1)).toBe(true) + expect(isProtected(store)).toBe(true) + expect(() => { + t1.title = "B" + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." + ) + store.todos[0].setTitle("C") + expect(store.todos[0].title).toBe("C") +}) +test("protected mode should be inherited when attaching children", () => { + const store = Store.create({ todos: [] }) + unprotect(store) + const t1 = Todo.create({ title: "hello" }) + expect(isProtected(t1)).toBe(true) + expect(isProtected(store)).toBe(false) + expect(() => { + t1.title = "B" + }).toThrowError( + "[mobx-state-tree] Cannot modify 'Todo@', the object is protected and can only be modified by using an action." + ) + store.todos.push(t1) + t1.title = "world" // ok, now unprotected + expect(isProtected(t1)).toBe(false) + expect(isProtected(store)).toBe(false) + expect(store.todos[0].title).toBe("world") +}) +test("action cannot modify parent", () => { + const Child = types + .model("Child", { + x: 2 + }) + .actions((self) => ({ + setParentX() { + getParent(self).x += 1 + } + })) + const Parent = types.model("Parent", { + x: 3, + child: Child + }) + const p = Parent.create({ child: {} }) + expect(() => p.child.setParentX()).toThrowError( + "[mobx-state-tree] Cannot modify 'Parent@', the object is protected and can only be modified by using an action." + ) +}) diff --git a/__tests__/core/recordPatches.test.ts b/__tests__/core/recordPatches.test.ts new file mode 100644 index 000000000..9af1c6527 --- /dev/null +++ b/__tests__/core/recordPatches.test.ts @@ -0,0 +1,350 @@ +import { + getSnapshot, + unprotect, + recordPatches, + types, + IType, + IJsonPatch, + Instance, + cast, + IAnyModelType, + IMSTMap +} from "../../src" + +function testPatches( + type: IType, + snapshot: C, + fn: any, + expectedPatches: IJsonPatch[], + expectedInversePatches: IJsonPatch[] +) { + const instance = type.create(snapshot) + const baseSnapshot = getSnapshot(instance) + const recorder = recordPatches(instance) + unprotect(instance) + fn(instance) + recorder.stop() + expect(recorder.patches).toEqual(expectedPatches) + expect(recorder.inversePatches).toEqual(expectedInversePatches) + const clone = type.create(snapshot) + recorder.replay(clone) + expect(getSnapshot(clone)).toEqual(getSnapshot(instance)) + recorder.undo() + expect(getSnapshot(instance)).toEqual(baseSnapshot) +} +const Node = types.model("Node", { + id: types.identifierNumber, + text: "Hi", + children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) +}) + +test("it should apply simple patch", () => { + testPatches( + Node, + { id: 1 }, + (n: Instance) => { + n.text = "test" + }, + [ + { + op: "replace", + path: "/text", + value: "test" + } + ], + [ + { + op: "replace", + path: "/text", + value: "Hi" + } + ] + ) +}) + +test("it should apply deep patches to arrays", () => { + testPatches( + Node, + { id: 1, children: [{ id: 2 }] }, + (n: Instance) => { + const children = n.children as unknown as Instance[] + children[0].text = "test" // update + children[0] = cast({ id: 2, text: "world" }) // this reconciles; just an update + children[0] = cast({ id: 4, text: "coffee" }) // new object + children[1] = cast({ id: 3, text: "world" }) // addition + children.splice(0, 1) // removal + }, + [ + { + op: "replace", + path: "/children/0/text", + value: "test" + }, + { + op: "replace", + path: "/children/0/text", + value: "world" + }, + { + op: "replace", + path: "/children/0", + value: { + id: 4, + text: "coffee", + children: [] + } + }, + { + op: "add", + path: "/children/1", + value: { + id: 3, + text: "world", + children: [] + } + }, + { + op: "remove", + path: "/children/0" + } + ], + [ + { + op: "replace", + path: "/children/0/text", + value: "Hi" + }, + { + op: "replace", + path: "/children/0/text", + value: "test" + }, + { + op: "replace", + path: "/children/0", + value: { + children: [], + id: 2, + text: "world" + } + }, + { + op: "remove", + path: "/children/1" + }, + { + op: "add", + path: "/children/0", + value: { + children: [], + id: 4, + text: "coffee" + } + } + ] + ) +}) + +test("it should apply deep patches to maps", () => { + const NodeMap = types.model("NodeMap", { + id: types.identifierNumber, + text: "Hi", + children: types.optional(types.map(types.late((): IAnyModelType => NodeMap)), {}) + }) + testPatches( + NodeMap, + { id: 1, children: { 2: { id: 2 } } }, + (n: Instance) => { + const children = n.children as IMSTMap + children.get("2")!.text = "test" // update + children.put({ id: 2, text: "world" }) // this reconciles; just an update + children.set("4", NodeMap.create({ id: 4, text: "coffee", children: { 23: { id: 23 } } })) // new object + children.put({ id: 3, text: "world", children: { 7: { id: 7 } } }) // addition + children.delete("2") // removal + }, + [ + { + op: "replace", + path: "/children/2/text", + value: "test" + }, + { + op: "replace", + path: "/children/2/text", + value: "world" + }, + { + op: "add", + path: "/children/4", + value: { + children: { + 23: { + children: {}, + id: 23, + text: "Hi" + } + }, + id: 4, + text: "coffee" + } + }, + { + op: "add", + path: "/children/3", + value: { + children: { + 7: { + children: {}, + id: 7, + text: "Hi" + } + }, + id: 3, + text: "world" + } + }, + { + op: "remove", + path: "/children/2" + } + ], + [ + { + op: "replace", + path: "/children/2/text", + value: "Hi" + }, + { + op: "replace", + path: "/children/2/text", + value: "test" + }, + { + op: "remove", + path: "/children/4" + }, + { + op: "remove", + path: "/children/3" + }, + { + op: "add", + path: "/children/2", + value: { + children: {}, + id: 2, + text: "world" + } + } + ] + ) +}) + +test("it should apply deep patches to objects", () => { + const NodeObject = types.model("NodeObject", { + id: types.identifierNumber, + text: "Hi", + child: types.maybe(types.late((): IAnyModelType => NodeObject)) + }) + testPatches( + NodeObject, + { id: 1, child: { id: 2 } }, + (n: Instance) => { + n.child!.text = "test" // update + n.child = cast({ id: 2, text: "world" }) // this reconciles; just an update + n.child = NodeObject.create({ id: 2, text: "coffee", child: { id: 23 } }) + n.child = cast({ id: 3, text: "world", child: { id: 7 } }) // addition + n.child = undefined // removal + }, + [ + { + op: "replace", + path: "/child/text", + value: "test" + }, + { + op: "replace", + path: "/child/text", + value: "world" + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 23, + text: "Hi" + }, + id: 2, + text: "coffee" + } + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 7, + text: "Hi" + }, + id: 3, + text: "world" + } + }, + { + op: "replace", + path: "/child", + value: undefined + } + ], + [ + { + op: "replace", + path: "/child/text", + value: "Hi" + }, + { + op: "replace", + path: "/child/text", + value: "test" + }, + { + op: "replace", + path: "/child", + value: { + child: undefined, + id: 2, + text: "world" + } + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 23, + text: "Hi" + }, + id: 2, + text: "coffee" + } + }, + { + op: "replace", + path: "/child", + value: { + child: { + child: undefined, + id: 7, + text: "Hi" + }, + id: 3, + text: "world" + } + } + ] + ) +}) diff --git a/__tests__/core/reference-custom.test.ts b/__tests__/core/reference-custom.test.ts new file mode 100644 index 000000000..836ea70e9 --- /dev/null +++ b/__tests__/core/reference-custom.test.ts @@ -0,0 +1,250 @@ +import { reaction, when, values } from "mobx" +import { + types, + recordPatches, + getSnapshot, + applySnapshot, + applyPatch, + unprotect, + getRoot, + onSnapshot, + flow, + Instance, + resolveIdentifier +} from "../../src" + +test("it should support custom references - basics", () => { + const User = types.model({ + id: types.identifier, + name: types.string + }) + const UserByNameReference = types.maybeNull( + types.reference(User, { + // given an identifier, find the user + get(identifier, parent): any { + return (parent as Instance)!.users.find((u) => u.name === identifier) || null + }, + // given a user, produce the identifier that should be stored + set(value) { + return value.name + } + }) + ) + const Store = types.model({ + users: types.array(User), + selection: UserByNameReference + }) + const s = Store.create({ + users: [ + { id: "1", name: "Michel" }, + { id: "2", name: "Mattia" } + ], + selection: "Mattia" + }) + unprotect(s) + expect(s.selection!.name).toBe("Mattia") + expect(s.selection === s.users[1]).toBe(true) + expect(getSnapshot(s).selection).toBe("Mattia") + s.selection = s.users[0] + expect(s.selection!.name).toBe("Michel") + expect(s.selection === s.users[0]).toBe(true) + expect(getSnapshot(s).selection).toBe("Michel") + s.selection = null + expect(getSnapshot(s).selection).toBe(null) + applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Mattia" })) + expect(s.selection).toBe(s.users[1]) + applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Unknown" })) + expect(s.selection).toBe(null) +}) + +test("it should support custom references - adv", () => { + const User = types.model({ + id: types.identifier, + name: types.string + }) + const NameReference = types.reference(User, { + get(identifier, parent): any { + if (identifier === null) return null + const users = values(getRoot>(parent!).users) + return users.filter((u) => u.name === identifier)[0] || null + }, + set(value) { + return value ? value.name : "" + } + }) + const Store = types.model({ + users: types.map(User), + selection: NameReference + }) + const s = Store.create({ + users: { + "1": { id: "1", name: "Michel" }, + "2": { id: "2", name: "Mattia" } + }, + selection: "Mattia" + }) + unprotect(s) + expect(s.selection.name).toBe("Mattia") + expect(s.selection === s.users.get("2")).toBe(true) + expect(getSnapshot(s).selection).toBe("Mattia") + const p = recordPatches(s) + const r: any[] = [] + onSnapshot(s, r.push.bind(r)) + const ids: (string | null)[] = [] + reaction( + () => s.selection, + (selection) => { + ids.push(selection ? selection.id : null) + } + ) + s.selection = s.users.get("1")! + expect(s.selection.name).toBe("Michel") + expect(s.selection === s.users.get("1")).toBe(true) + expect(getSnapshot(s).selection).toBe("Michel") + applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Mattia" })) + expect(s.selection).toBe(s.users.get("2")) + applyPatch(s, { op: "replace", path: "/selection", value: "Michel" }) + expect(s.selection).toBe(s.users.get("1")) + s.users.delete("1") + expect(s.selection).toBe(null) + s.users.put({ id: "3", name: "Michel" }) + expect(s.selection.id).toBe("3") + expect(ids).toMatchSnapshot() + expect(r).toMatchSnapshot() + expect(p.patches).toMatchSnapshot() + expect(p.inversePatches).toMatchSnapshot() +}) + +test("it should support dynamic loading", (done) => { + const events: string[] = [] + const User = types.model({ + name: types.string, + age: 0 + }) + const UserByNameReference = types.maybe( + types.reference(User, { + get(identifier: string, parent): any { + return (parent as Instance).getOrLoadUser(identifier) + }, + set(value) { + return value.name + } + }) + ) + const Store = types + .model({ + users: types.array(User), + selection: UserByNameReference + }) + .actions((self) => ({ + loadUser: flow(function* loadUser(name: string) { + events.push("loading " + name) + self.users.push({ name }) + yield new Promise((resolve) => { + setTimeout(resolve, 200) + }) + events.push("loaded " + name) + const user = (self.users.find((u) => u.name === name)!.age = name.length * 3) // wonderful! + }) + })) + .views((self) => ({ + // Important: a view so that the reference will automatically react to the reference being changed! + getOrLoadUser(name: string) { + const user = self.users.find((u) => u.name === name) || null + if (!user) { + /* + TODO: this is ugly, but workaround the idea that views should be side effect free. + We need a more elegant solution.. + */ + setImmediate(() => self.loadUser(name)) + } + return user + } + })) + const s = Store.create({ + users: [], + selection: "Mattia" + }) + unprotect(s) + expect(events).toEqual([]) + expect(s.users.length).toBe(0) + expect(s.selection).toBe(null) + when( + () => s.users.length === 1 && s.users[0].age === 18 && s.users[0].name === "Mattia", + () => { + expect(s.selection).toBe(s.users[0]) + expect(events).toEqual(["loading Mattia", "loaded Mattia"]) + done() + } + ) +}) + +test("custom reference / safe custom reference to another store works", () => { + const Todo = types.model({ id: types.identifier }) + const TodoStore = types.model({ todos: types.array(Todo) }) + const OtherStore = types.model({ + todoRef: types.maybe( + types.reference(Todo, { + get(id) { + const node = resolveIdentifier(Todo, todos, id) + if (!node) { + throw new Error("Invalid ref") + } + return node + }, + set(value) { + return value.id + } + }) + ), + safeRef: types.safeReference(Todo, { + get(id) { + const node = resolveIdentifier(Todo, todos, id) + if (!node) { + throw new Error("Invalid ref") + } + return node + }, + set(value) { + return value.id + } + }) + }) + const todos = TodoStore.create({ + todos: [{ id: "1" }, { id: "2" }, { id: "3" }] + }) + unprotect(todos) + + // from a snapshot + const otherStore = OtherStore.create({ + todoRef: "1", + safeRef: "1" + }) + unprotect(otherStore) + expect(otherStore.todoRef!.id).toBe("1") + expect(otherStore.safeRef!.id).toBe("1") + + // assigning an id + otherStore.todoRef = "2" as any + otherStore.safeRef = "2" as any + expect(otherStore.todoRef!.id).toBe("2") + expect(otherStore.safeRef!.id).toBe("2") + + // assigning a node directly + otherStore.todoRef = todos.todos[2] + otherStore.safeRef = todos.todos[2] + expect(otherStore.todoRef!.id).toBe("3") + expect(otherStore.safeRef!.id).toBe("3") + + // getting the snapshot + expect(getSnapshot(otherStore)).toEqual({ + todoRef: "3", + safeRef: "3" + }) + + // the removed node should throw on standard refs access + // and be set to undefined on safe ones + todos.todos.splice(2, 1) + expect(() => otherStore.todoRef).toThrow("Invalid ref") + expect(otherStore.safeRef).toBe(undefined) +}) diff --git a/__tests__/core/reference-onInvalidated.test.ts b/__tests__/core/reference-onInvalidated.test.ts new file mode 100644 index 000000000..be549d90b --- /dev/null +++ b/__tests__/core/reference-onInvalidated.test.ts @@ -0,0 +1,492 @@ +import { + types, + OnReferenceInvalidated, + Instance, + ReferenceIdentifier, + IAnyStateTreeNode, + unprotect, + OnReferenceInvalidatedEvent, + getSnapshot, + applySnapshot, + clone, + destroy +} from "../../src" + +const Todo = types.model({ id: types.identifier }) + +const createSnapshot = (partialSnapshot: any) => ({ + todos: [{ id: "1" }, { id: "2" }, { id: "3" }, { id: "4" }], + ...partialSnapshot +}) + +const createStore = ( + partialSnapshot: any, + onInvalidated?: OnReferenceInvalidated>, + customRef = false +) => { + const refOptions = { + onInvalidated, + get(identifier: ReferenceIdentifier, parent: IAnyStateTreeNode | null) { + return (parent as Instance).todos.find((t) => t.id === identifier) + }, + set(value: Instance): ReferenceIdentifier { + return value.id + } + } + + if (!customRef) { + // @ts-ignore + delete refOptions.get + // @ts-ignore + delete refOptions.set + } + + const Store = types.model({ + todos: types.array(Todo), + onInv: types.maybe(types.reference(Todo, refOptions as any)), + single: types.safeReference(Todo), + deep: types.optional( + types.model({ + single: types.safeReference(Todo) + }), + {} + ), + arr: types.array(types.safeReference(Todo)), + map: types.map(types.safeReference(Todo)) + }) + + const s = Store.create(createSnapshot(partialSnapshot)) + unprotect(s) + return s +} + +for (const customRef of [false, true]) { + describe(`onInvalidated - customRef: ${customRef}`, () => { + test("from snapshot without accessing the referenced node", () => { + let ev: OnReferenceInvalidatedEvent> | undefined + let oldRefId!: string + let calls = 0 + const onInv: OnReferenceInvalidated> = (ev1) => { + calls++ + oldRefId = ev1.invalidTarget!.id + expect(ev1.invalidId).toBe(oldRefId) + ev = ev1 + ev1.removeRef() + } + const store = createStore({ onInv: "1" }, onInv) + + expect(calls).toBe(0) + store.todos.splice(0, 1) + expect(calls).toBe(1) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("1") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + + store.onInv = store.todos[0] + expect(calls).toBe(1) + store.todos.splice(0, 1) + expect(calls).toBe(2) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("2") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + }) + + test("applying snapshot without accesing the referenced node", () => { + let ev: OnReferenceInvalidatedEvent> | undefined + let oldRefId!: string + let calls = 0 + const onInv: OnReferenceInvalidated> = (ev1) => { + calls++ + oldRefId = ev1.invalidTarget!.id + expect(ev1.invalidId).toBe(oldRefId) + ev = ev1 + ev1.removeRef() + } + const store = createStore({}, onInv) + expect(calls).toBe(0) + applySnapshot(store, createSnapshot({ onInv: "1" })) + expect(calls).toBe(0) + store.todos.splice(0, 1) + expect(calls).toBe(1) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("1") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + + store.onInv = store.todos[0] + expect(calls).toBe(1) + store.todos.splice(0, 1) + expect(calls).toBe(2) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("2") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + }) + + test("runtime change", () => { + let ev: OnReferenceInvalidatedEvent> | undefined + let oldRefId!: string + let calls = 0 + const onInv: OnReferenceInvalidated> = (ev1) => { + calls++ + oldRefId = ev1.invalidTarget!.id + expect(ev1.invalidId).toBe(oldRefId) + ev = ev1 + ev1.removeRef() + } + const store = createStore({}, onInv) + + expect(calls).toBe(0) + store.onInv = store.todos[1] + expect(calls).toBe(0) + store.onInv = store.todos[0] + expect(calls).toBe(0) + store.todos.remove(store.todos[0]) + expect(calls).toBe(1) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("1") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + + store.onInv = store.todos[0] + expect(calls).toBe(1) + store.todos.remove(store.todos[0]) + expect(calls).toBe(2) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("2") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + }) + + test("replacing ref", () => { + let ev: OnReferenceInvalidatedEvent> | undefined + let oldRefId!: string + let calls = 0 + const onInv: OnReferenceInvalidated> = (ev1) => { + calls++ + oldRefId = ev1.invalidTarget!.id + expect(ev1.invalidId).toBe(oldRefId) + ev = ev1 + ev1.replaceRef(store.todos[1]) + } + const store = createStore({}, onInv) + + expect(calls).toBe(0) + store.onInv = store.todos[0] + expect(calls).toBe(0) + store.todos.remove(store.todos[0]) + expect(calls).toBe(1) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("1") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv!.id).toBe("2") + expect(getSnapshot(store).onInv).toBe("2") + }) + + test("cloning works", () => { + let ev: OnReferenceInvalidatedEvent> | undefined + let oldRefId!: string + let calls = 0 + const onInv: OnReferenceInvalidated> = (ev1) => { + calls++ + oldRefId = ev1.invalidTarget!.id + expect(ev1.invalidId).toBe(oldRefId) + ev = ev1 + ev1.removeRef() + } + const store1 = createStore({}, onInv) + + expect(calls).toBe(0) + store1.onInv = store1.todos[0] + expect(calls).toBe(0) + + const store = clone(store1) + unprotect(store) + expect(calls).toBe(0) + store.onInv = store.todos[0] + expect(calls).toBe(0) + store.todos.remove(store.todos[0]) + expect(calls).toBe(1) + expect(ev!.parent).toBe(store) + expect(oldRefId).toBe("1") + expect(ev!.removeRef).toBeTruthy() + expect(ev!.replaceRef).toBeTruthy() + expect(store.onInv).toBe(undefined) + expect(getSnapshot(store).onInv).toBeUndefined() + // make sure other ref stil points to the right one + expect(store1.onInv).toBe(store1.todos[0]) + }) + }) +} + +describe("safeReference", () => { + test("model property", () => { + const store = createStore({}) + expect(store.single).toBeUndefined() + store.single = store.todos[0] + expect(store.single).toBe(store.todos[0]) + store.todos.remove(store.todos[0]) + expect(store.single).toBeUndefined() + }) + + test("deep model property", () => { + const store = createStore({}) + expect(store.deep.single).toBeUndefined() + store.deep.single = store.todos[0] + expect(store.deep.single).toBe(store.todos[0]) + store.todos.remove(store.todos[0]) + expect(store.deep.single).toBeUndefined() + }) + + test("array child", () => { + const store = createStore({}) + expect(store.arr.length).toBe(0) + + store.arr.push(store.todos[0]) + store.arr.push(store.todos[2]) + expect(store.arr.length).toBe(2) + expect(store.arr[0]!.id).toBe("1") + expect(store.arr[1]!.id).toBe("3") + + store.todos.splice(0, 1) + expect(store.arr.length).toBe(1) + expect(store.arr[0]!.id).toBe("3") + }) + + test("map child", () => { + const store = createStore({}) + expect(store.map.size).toBe(0) + + store.map.set("a", store.todos[0]) + store.map.set("c", store.todos[2]) + expect(store.map.size).toBe(2) + expect(store.map.get("a")!.id).toBe("1") + expect(store.map.get("c")!.id).toBe("3") + + store.todos.splice(0, 1) + expect(store.map.size).toBe(1) + expect(store.map.get("c")!.id).toBe("3") + }) + + test("invalid references in a snapshot should be removed", () => { + const store = createStore({ single: "100", arr: ["100", "1"], map: { a: "100", b: "1" } }) + expect(store.single).toBeUndefined() + expect(store.arr.length).toBe(1) + expect(store.arr[0]!.id).toBe("1") + expect(store.map.size).toBe(1) + expect(store.map.get("b")!.id).toBe("1") + + // check reassignation still works + store.single = store.todos[0] + expect(store.single).toBe(store.todos[0]) + store.todos.remove(store.todos[0]) + expect(store.single).toBeUndefined() + }) + + test("setting it to an invalid id and then accessing it should still result in an error", () => { + const store = createStore({}) + store.single = "100" as any + expect(() => { + const s = store.single + }).toThrow("Failed to resolve reference") + }) +}) + +test("#1115 - safe reference doesn't become invalidated when the reference has never been acessed", () => { + const MyRefModel = types.model("MyRefModel", { + id: types.identifier + }) + + const SafeRef = types.model("SafeRef", { + ref: types.safeReference(MyRefModel) + }) + + const RootModel = types + .model("RootModel", { + mapOfRef: types.map(MyRefModel), + arrayOfSafeRef: types.array(SafeRef) + }) + .actions((self) => ({ + deleteSqr(id: string) { + self.mapOfRef.delete(id) + } + })) + + const rootModel = RootModel.create({ + mapOfRef: { + sqr1: { + id: "sqr1" + }, + sqr2: { + id: "sqr2" + } + }, + arrayOfSafeRef: [ + { + ref: "sqr2" + }, + { + ref: "sqr1" + }, + { + ref: "sqr2" + } + ] + }) + + expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ + { + ref: "sqr2" + }, + { + ref: "sqr1" + }, + { + ref: "sqr2" + } + ]) + + rootModel.deleteSqr("sqr1") + expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ + { + ref: "sqr2" + }, + { + ref: undefined + }, + { + ref: "sqr2" + } + ]) + + rootModel.deleteSqr("sqr2") + expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ + { + ref: undefined + }, + { + ref: undefined + }, + { + ref: undefined + } + ]) +}) + +describe("safeReference with acceptsUndefined: false", () => { + const MyRefModel = types.model("MyRefModel", { + id: types.identifier + }) + + const SafeRef = types.safeReference(MyRefModel, { acceptsUndefined: false }) + + it("removes invalidates items from map/array", () => { + const Store = types.model({ + todos: types.array(MyRefModel), + arr: types.array(SafeRef), + map: types.map(SafeRef) + }) + + const store = Store.create({ + todos: [{ id: "1" }, { id: "2" }], + arr: ["1", "2"], + map: { + a1: "1", + a2: "2" + } + }) + unprotect(store) + + // just to check TS is happy with this + const arr: Instance[] = store.arr + + store.todos.splice(0, 1) + expect(store.arr.length).toBe(1) + expect(store.map.size).toBe(1) + }) + + if (process.env.NODE_ENV !== "production") { + it("throws when a model property is invalidated", () => { + const Store = types.model({ + todos: types.array(MyRefModel), + single: SafeRef + }) + + const store = Store.create({ + todos: [{ id: "1" }, { id: "2" }], + single: "1" + }) + unprotect(store) + + expect(() => { + store.todos.splice(0, 1) + }).toThrow("value `undefined` is not assignable to type") + }) + + it("does not accept undefined in the array", () => { + const Store = types.model({ + todos: types.array(MyRefModel), + arr: types.array(SafeRef) + }) + + expect(() => + Store.create({ + todos: [{ id: "1" }, { id: "2" }], + arr: ["1", undefined as any] + }) + ).toThrow("value `undefined` is not assignable to type") + }) + + it("does not accept undefined in the map", () => { + const Store = types.model({ + todos: types.array(MyRefModel), + map: types.map(SafeRef) + }) + + expect(() => + Store.create({ + todos: [{ id: "1" }, { id: "2" }], + map: { + a1: "1", + a2: undefined as any + } + }) + ).toThrow("value `undefined` is not assignable to type") + }) + } +}) + +test("#1275 - removing an object from a map should result in the snapshot of references being modified", () => { + const Item = types.model({ + id: types.identifier + }) + + const Root = types.model({ + items: types.map(Item), + refs: types.array(types.safeReference(Item)) + }) + + const thing = Root.create({ + items: { aa: { id: "a" }, bb: { id: "b" }, cc: { id: "c" } }, + refs: ["a", "b", "c"] + }) + unprotect(thing) + + destroy(thing.items.get("bb")!) + expect(getSnapshot(thing.refs)).toEqual(["a", "c"]) +}) diff --git a/__tests__/core/reference.test.ts b/__tests__/core/reference.test.ts new file mode 100644 index 000000000..53de7b621 --- /dev/null +++ b/__tests__/core/reference.test.ts @@ -0,0 +1,1113 @@ +import { reaction, autorun, isObservable, configure } from "mobx" +import { + types, + getSnapshot, + applySnapshot, + onPatch, + applyPatch, + unprotect, + detach, + resolveIdentifier, + getRoot, + cast, + SnapshotOut, + IAnyModelType, + Instance, + SnapshotOrInstance, + isAlive, + destroy, + castToReferenceSnapshot, + tryReference, + isValidReference, + isStateTreeNode, + addDisposer +} from "../../src" + +test("it should support prefixed paths in maps", () => { + const User = types.model({ + id: types.identifier, + name: types.string + }) + const UserStore = types.model({ + user: types.reference(User), + users: types.map(User) + }) + const store = UserStore.create({ + user: "17", + users: { + "17": { id: "17", name: "Michel" }, + "18": { id: "18", name: "Veria" } + } + }) + unprotect(store) + expect(store.users.get("17")!.name).toBe("Michel") + expect(store.users.get("18")!.name).toBe("Veria") + expect(store.user.name).toBe("Michel") + store.user = store.users.get("18")! + expect(store.user.name).toBe("Veria") + store.users.get("18")!.name = "Noa" + expect(store.user.name).toBe("Noa") + expect(getSnapshot(store)).toEqual({ + user: "18", + users: { "17": { id: "17", name: "Michel" }, "18": { id: "18", name: "Noa" } } + } as SnapshotOut) +}) + +test("it should support prefixed paths in arrays", () => { + const User = types.model({ + id: types.identifier, + name: types.string + }) + const UserStore = types.model({ + user: types.reference(User), + users: types.array(User) + }) + const store = UserStore.create({ + user: "17", + users: [ + { id: "17", name: "Michel" }, + { id: "18", name: "Veria" } + ] + }) + unprotect(store) + expect(store.users[0].name).toBe("Michel") + expect(store.users[1].name).toBe("Veria") + expect(store.user.name).toBe("Michel") + store.user = store.users[1] + expect(store.user.name).toBe("Veria") + store.users[1].name = "Noa" + expect(store.user.name).toBe("Noa") + expect(getSnapshot(store)).toEqual({ + user: "18", + users: [ + { id: "17", name: "Michel" }, + { id: "18", name: "Noa" } + ] + } as SnapshotOut) +}) + +if (process.env.NODE_ENV !== "production") { + test("identifiers are required", () => { + const Todo = types.model({ + id: types.identifier + }) + expect(Todo.is({})).toBe(false) + expect(Todo.is({ id: "x" })).toBe(true) + expect(() => (Todo.create as any)()).toThrowError( + " `undefined` is not assignable to type: `identifier` (Value is not a valid identifier, expected a string)" + ) + }) + + test("identifiers cannot be modified", () => { + const Todo = types.model({ + id: types.identifier + }) + const todo = Todo.create({ id: "x" }) + unprotect(todo) + expect(() => (todo.id = "stuff")).toThrowError( + "[mobx-state-tree] Tried to change identifier from 'x' to 'stuff'. Changing identifiers is not allowed." + ) + expect(() => applySnapshot(todo, { id: "stuff" })).toThrowError( + "[mobx-state-tree] Tried to change identifier from 'x' to 'stuff'. Changing identifiers is not allowed." + ) + }) +} + +test("it should resolve refs during creation, when using path", () => { + const values: number[] = [] + const Book = types.model({ + id: types.identifier, + price: types.number + }) + const BookEntry = types + .model({ + book: types.reference(Book) + }) + .views((self) => ({ + get price() { + return self.book.price * 2 + } + })) + const Store = types.model({ + books: types.array(Book), + entries: types.optional(types.array(BookEntry), []) + }) + const s = Store.create({ + books: [{ id: "3", price: 2 }] + }) + unprotect(s) + reaction( + () => s.entries.reduce((a, e) => a + e.price, 0), + (v) => values.push(v) + ) + s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) + expect(s.entries[0].price).toBe(4) + expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) + const entry = BookEntry.create({ book: castToReferenceSnapshot(s.books[0]) }) // N.B. ref is initially not resolvable! + s.entries.push(entry) + expect(s.entries[1].price).toBe(4) + expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(8) + expect(values).toEqual([4, 8]) +}) + +test("it should resolve refs over late types", () => { + const Book = types.model({ + id: types.identifier, + price: types.number + }) + const BookEntry = types + .model({ + book: types.reference(types.late(() => Book)) + }) + .views((self) => ({ + get price() { + return self.book.price * 2 + } + })) + const Store = types.model({ + books: types.array(Book), + entries: types.array(BookEntry) + }) + const s = Store.create({ + books: [{ id: "3", price: 2 }] + }) + unprotect(s) + s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) + expect(s.entries[0].price).toBe(4) + expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) +}) + +test("it should resolve refs during creation, when using generic reference", () => { + const values: number[] = [] + const Book = types.model({ + id: types.identifier, + price: types.number + }) + const BookEntry = types + .model({ + book: types.reference(Book) + }) + .views((self) => ({ + get price() { + return self.book.price * 2 + } + })) + const Store = types.model({ + books: types.array(Book), + entries: types.optional(types.array(BookEntry), []) + }) + const s = Store.create({ + books: [{ id: "3", price: 2 }] + }) + unprotect(s) + reaction( + () => s.entries.reduce((a, e) => a + e.price, 0), + (v) => values.push(v) + ) + s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) + expect(s.entries[0].price).toBe(4) + expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) + const entry = BookEntry.create({ book: castToReferenceSnapshot(s.books[0]) }) // can refer to book, even when not part of tree yet + expect(getSnapshot(entry)).toEqual({ book: "3" }) + s.entries.push(entry) + expect(values).toEqual([4, 8]) +}) + +test("identifiers should support subtypes of types.string and types.number", () => { + const M = types.model({ + id: types.refinement(types.identifierNumber, (n) => n > 5) + }) + expect(M.is({})).toBe(false) + expect(M.is({ id: "test" })).toBe(false) + expect(M.is({ id: "6" })).toBe(false) + expect(M.is({ id: "4" })).toBe(false) + expect(M.is({ id: 6 })).toBe(true) + expect(M.is({ id: 4 })).toBe(false) + + const S = types.model({ + mies: types.map(M), + ref: types.reference(M) + }) + const s = S.create({ mies: { "7": { id: 7 } }, ref: "7" }) + expect(s.mies.get("7")).toBeTruthy() + expect(s.ref).toBe(s.mies.get("7")) +}) + +test("string identifiers should not accept numbers", () => { + const F = types.model({ + id: types.identifier + }) + expect(F.is({ id: "4" })).toBe(true) + expect(F.is({ id: 4 })).toBe(false) + const F2 = types.model({ + id: types.identifier + }) + expect(F2.is({ id: "4" })).toBe(true) + expect(F2.is({ id: 4 })).toBe(false) +}) + +test("122 - identifiers should support numbers as well", () => { + const F = types.model({ + id: types.identifierNumber + }) + expect( + F.create({ + id: 3 + }).id + ).toBe(3) + + expect(F.is({ id: 4 })).toBe(true) + expect(F.is({ id: "4" })).toBe(false) + expect(F.is({ id: "bla" })).toBe(false) +}) + +test("self reference with a late type", () => { + const Book = types.model("Book", { + id: types.identifier, + genre: types.string, + reference: types.reference(types.late((): IAnyModelType => Book)) + }) + const Store = types + .model("Store", { + books: types.array(Book) + }) + .actions((self) => { + function addBook(book: SnapshotOrInstance) { + self.books.push(book) + } + return { + addBook + } + }) + const s = Store.create({ + books: [{ id: "1", genre: "thriller", reference: "" }] + }) + const book2 = Book.create({ + id: "2", + genre: "romance", + reference: castToReferenceSnapshot(s.books[0]) + }) + s.addBook(book2) + expect((s.books[1].reference as Instance).genre).toBe("thriller") +}) + +test("when applying a snapshot, reference should resolve correctly if value added after", () => { + const Box = types.model({ + id: types.identifierNumber, + name: types.string + }) + const Factory = types.model({ + selected: types.reference(Box), + boxes: types.array(Box) + }) + expect(() => + Factory.create({ + selected: 1, + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ] + }) + ).not.toThrow() +}) + +test("it should fail when reference snapshot is ambiguous", () => { + const Box = types.model("Box", { + id: types.identifierNumber, + name: types.string + }) + const Arrow = types.model("Arrow", { + id: types.identifierNumber, + name: types.string + }) + const BoxOrArrow = types.union(Box, Arrow) + const Factory = types.model({ + selected: types.reference(BoxOrArrow), + boxes: types.array(Box), + arrows: types.array(Arrow) + }) + const store = Factory.create({ + selected: 2, + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ], + arrows: [{ id: 2, name: "arrow" }] + }) + expect(() => { + // tslint:disable-next-line:no-unused-expression + store.selected // store.boxes[1] // throws because it can't know if you mean a box or an arrow! + }).toThrowError( + "[mobx-state-tree] Cannot resolve a reference to type '(Box | Arrow)' with id: '2' unambigously, there are multiple candidates: /boxes/1, /arrows/0" + ) + unprotect(store) + // first update the reference, than create a new matching item! Ref becomes ambigous now... + store.selected = 1 as any // valid assignment + expect(store.selected).toBe(store.boxes[0]) // unambigous identifier + let err!: Error + autorun(() => store.selected, { + onError(e) { + err = e + } + }) + expect(store.selected).toBe(store.boxes[0]) // unambigous identifier + store.arrows.push({ id: 1, name: "oops" }) + expect(err.message).toBe( + "[mobx-state-tree] Cannot resolve a reference to type '(Box | Arrow)' with id: '1' unambigously, there are multiple candidates: /boxes/0, /arrows/1" + ) +}) + +test("it should support array of references", () => { + const Box = types.model({ + id: types.identifierNumber, + name: types.string + }) + const Factory = types.model({ + selected: types.array(types.reference(Box)), + boxes: types.array(Box) + }) + const store = Factory.create({ + selected: [], + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ] + }) + unprotect(store) + expect(() => { + store.selected.push(store.boxes[0]) + }).not.toThrow() + expect(getSnapshot(store.selected)).toEqual([1]) + expect(() => { + store.selected.push(store.boxes[1]) + }).not.toThrow() + expect(getSnapshot(store.selected)).toEqual([1, 2]) +}) + +test("it should restore array of references from snapshot", () => { + const Box = types.model({ + id: types.identifierNumber, + name: types.string + }) + const Factory = types.model({ + selected: types.array(types.reference(Box)), + boxes: types.array(Box) + }) + const store = Factory.create({ + selected: [1, 2], + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ] + }) + unprotect(store) + expect(store.selected[0] === store.boxes[0]).toEqual(true) + expect(store.selected[1] === store.boxes[1]).toEqual(true) +}) + +test("it should support map of references", () => { + const Box = types.model({ + id: types.identifierNumber, + name: types.string + }) + const Factory = types.model({ + selected: types.map(types.reference(Box)), + boxes: types.array(Box) + }) + const store = Factory.create({ + selected: {}, + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ] + }) + unprotect(store) + expect(() => { + store.selected.set("from", store.boxes[0]) + }).not.toThrow() + expect(getSnapshot(store.selected)).toEqual({ from: 1 }) + expect(() => { + store.selected.set("to", store.boxes[1]) + }).not.toThrow() + expect(getSnapshot(store.selected)).toEqual({ from: 1, to: 2 }) +}) + +test("it should restore map of references from snapshot", () => { + const Box = types.model({ + id: types.identifierNumber, + name: types.string + }) + const Factory = types.model({ + selected: types.map(types.reference(Box)), + boxes: types.array(Box) + }) + const store = Factory.create({ + selected: { from: 1, to: 2 }, + boxes: [ + { id: 1, name: "hello" }, + { id: 2, name: "world" } + ] + }) + unprotect(store) + expect(store.selected.get("from") === store.boxes[0]).toEqual(true) + expect(store.selected.get("to") === store.boxes[1]).toEqual(true) +}) + +test("it should support relative lookups", () => { + const Node = types.model({ + id: types.identifierNumber, + children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) + }) + const root = Node.create({ + id: 1, + children: [ + { + id: 2, + children: [ + { + id: 4 + } + ] + }, + { + id: 3 + } + ] + }) + unprotect(root) + expect(getSnapshot(root)).toEqual({ + id: 1, + children: [ + { id: 2, children: [{ id: 4, children: [] }] }, + { id: 3, children: [] } + ] + }) + expect(resolveIdentifier(Node, root, 1)).toBe(root) + expect(resolveIdentifier(Node, root, 4)).toBe(root.children[0].children[0]) + expect(resolveIdentifier(Node, root.children[0].children[0], 3)).toBe(root.children[1]) + const n2 = detach(root.children[0]) + unprotect(n2) + expect(resolveIdentifier(Node, n2, 2)).toBe(n2) + expect(resolveIdentifier(Node, root, 2)).toBe(undefined) + expect(resolveIdentifier(Node, root, 4)).toBe(undefined) + expect(resolveIdentifier(Node, n2, 3)).toBe(undefined) + expect(resolveIdentifier(Node, n2, 4)).toBe(n2.children[0]) + expect(resolveIdentifier(Node, n2.children[0], 2)).toBe(n2) + const n5 = Node.create({ id: 5 }) + expect(resolveIdentifier(Node, n5, 4)).toBe(undefined) + n2.children.push(n5) + expect(resolveIdentifier(Node, n5, 4)).toBe(n2.children[0]) + expect(resolveIdentifier(Node, n2.children[0], 5)).toBe(n5) +}) + +test("References are non-nullable by default", () => { + const Todo = types.model({ + id: types.identifierNumber + }) + const Store = types.model({ + todo: types.maybe(Todo), + ref: types.reference(Todo), + maybeRef: types.maybe(types.reference(Todo)) + }) + expect(Store.is({})).toBe(false) + expect(Store.is({ ref: 3 })).toBe(true) + expect(Store.is({ ref: null })).toBe(false) + expect(Store.is({ ref: undefined })).toBe(false) + expect(Store.is({ ref: 3, maybeRef: 3 })).toBe(true) + expect(Store.is({ ref: 3, maybeRef: undefined })).toBe(true) + let store = Store.create({ + todo: { id: 3 }, + ref: 3 + }) + expect(store.ref).toBe(store.todo) + expect(store.maybeRef).toBe(undefined) + store = Store.create({ + todo: { id: 3 }, + ref: 4 + }) + unprotect(store) + if (process.env.NODE_ENV !== "production") { + expect(store.maybeRef).toBe(undefined) + expect(() => store.ref).toThrow( + "[mobx-state-tree] Failed to resolve reference '4' to type 'AnonymousModel' (from node: /ref)" + ) + store.maybeRef = 3 as any // valid assignment + expect(store.maybeRef).toBe(store.todo) + store.maybeRef = 4 as any // valid assignment + expect(() => store.maybeRef).toThrow( + "[mobx-state-tree] Failed to resolve reference '4' to type 'AnonymousModel' (from node: /maybeRef)" + ) + store.maybeRef = undefined + expect(store.maybeRef).toBe(undefined) + expect(() => ((store as any).ref = undefined)).toThrow(/Error while converting/) + } +}) + +test("References are described properly", () => { + const Todo = types.model({ + id: types.identifierNumber + }) + const Store = types.model({ + todo: types.maybe(Todo), + ref: types.reference(Todo), + maybeRef: types.maybe(types.reference(Todo)) + }) + expect(Store.describe()).toBe( + "{ todo: ({ id: identifierNumber } | undefined?); ref: reference(AnonymousModel); maybeRef: (reference(AnonymousModel) | undefined?) }" + ) +}) + +test("References in recursive structures", () => { + const Folder = types.model("Folder", { + id: types.identifierNumber, + name: types.string, + files: types.array(types.string) + }) + const Tree = types + .model("Tree", { + // sadly, this becomes any, and further untypeable... + children: types.array(types.late((): IAnyModelType => Tree)), + data: types.maybeNull(types.reference(Folder)) + }) + .actions((self) => { + function addFolder(data: SnapshotOrInstance) { + const folder3 = Folder.create(data) + getRoot(self).putFolderHelper(folder3) + self.children.push(Tree.create({ data: castToReferenceSnapshot(folder3), children: [] })) + } + return { addFolder } + }) + + const Storage = types + .model("Storage", { + objects: types.map(Folder), + tree: Tree + }) + .actions((self) => ({ + putFolderHelper(aFolder: SnapshotOrInstance) { + self.objects.put(aFolder) + } + })) + const store = Storage.create({ objects: {}, tree: { children: [], data: null } }) + const folder = { id: 1, name: "Folder 1", files: ["a.jpg", "b.jpg"] } + store.tree.addFolder(folder) + expect(getSnapshot(store)).toEqual({ + objects: { + "1": { + files: ["a.jpg", "b.jpg"], + id: 1, + name: "Folder 1" + } + }, + tree: { + children: [ + { + children: [], + data: 1 + } + ], + data: null + } + }) + expect(store.objects.get("1")).toBe(store.tree.children[0].data) + const folder2 = { id: 2, name: "Folder 2", files: ["c.jpg", "d.jpg"] } + store.tree.children[0].addFolder(folder2) + expect(getSnapshot(store)).toEqual({ + objects: { + "1": { + files: ["a.jpg", "b.jpg"], + id: 1, + name: "Folder 1" + }, + "2": { + files: ["c.jpg", "d.jpg"], + id: 2, + name: "Folder 2" + } + }, + tree: { + children: [ + { + children: [ + { + children: [], + data: 2 + } + ], + data: 1 + } + ], + data: null + } + }) + expect(store.objects.get("1")).toBe(store.tree.children[0].data) + expect(store.objects.get("2")).toBe(store.tree.children[0].children[0].data) +}) + +test("it should applyPatch references in array", () => { + const Item = types.model("Item", { + id: types.identifier, + name: types.string + }) + const Folder = types + .model("Folder", { + id: types.identifier, + objects: types.map(Item), + hovers: types.array(types.reference(Item)) + }) + .actions((self) => { + function addObject(anItem: typeof Item.Type) { + self.objects.put(anItem) + } + function addHover(anItem: typeof Item.Type) { + self.hovers.push(anItem) + } + function removeHover(anItem: typeof Item.Type) { + self.hovers.remove(anItem) + } + return { + addObject, + addHover, + removeHover + } + }) + const folder = Folder.create({ id: "folder 1", objects: {}, hovers: [] }) + folder.addObject({ id: "item 1", name: "item name 1" }) + const item = folder.objects.get("item 1")! + const snapshot = getSnapshot(folder) + const newStore = Folder.create(snapshot) + onPatch(folder, (data) => { + applyPatch(newStore, data) + }) + folder.addHover(item) + expect(getSnapshot(newStore)).toEqual({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: ["item 1"] + }) + folder.removeHover(item) + expect(getSnapshot(newStore)).toEqual({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: [] + }) +}) + +test("it should applySnapshot references in array", () => { + const Item = types.model("Item", { + id: types.identifier, + name: types.string + }) + const Folder = types.model("Folder", { + id: types.identifier, + objects: types.map(Item), + hovers: types.array(types.reference(Item)) + }) + const folder = Folder.create({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: ["item 1"] + }) + const snapshot = JSON.parse(JSON.stringify(getSnapshot(folder))) + expect(snapshot).toEqual({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: ["item 1"] + }) + snapshot.hovers = [] + applySnapshot(folder, snapshot) + expect(getSnapshot(folder)).toEqual({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: [] + }) + snapshot.hovers = ["item 1"] + applySnapshot(folder, snapshot) + expect(getSnapshot(folder)).toEqual({ + id: "folder 1", + objects: { + "item 1": { + id: "item 1", + name: "item name 1" + } + }, + hovers: ["item 1"] + }) +}) + +test("array of references should work fine", () => { + const B = types.model("Block", { id: types.identifier }) + const S = types + .model("Store", { + blocks: types.array(B), + blockRefs: types.array(types.reference(B)) + }) + .actions((self) => { + return { + order() { + const res = self.blockRefs.slice() + self.blockRefs.replace([res[1], res[0]]) + } + } + }) + const a = S.create({ blocks: [{ id: "1" }, { id: "2" }], blockRefs: ["1", "2"] }) + a.order() + expect(a.blocks[0].id).toBe("1") + expect(a.blockRefs[0].id).toBe("2") +}) + +test("should serialize references correctly", () => { + const M = types.model({ + id: types.identifierNumber + }) + const S = types.model({ + mies: types.map(M), + ref: types.maybe(types.reference(M)) + }) + + const s = S.create({ + mies: { + 7: { + id: 7 + } + } + }) + unprotect(s) + + expect(Array.from(s.mies.keys())).toEqual(["7"]) + expect(s.mies.get("7")!.id).toBe(7) + expect(s.mies.get(7 as any)).toBe(s.mies.get("7")) // maps automatically normalizes the key + + s.mies.put({ + id: 8 + }) + expect(Array.from(s.mies.keys())).toEqual(["7", "8"]) + + s.ref = 8 as any + expect(s.ref!.id).toBe(8) // resolved from number + expect(getSnapshot(s).ref).toBe(8) // ref serialized as number + + s.ref = "7" as any // resolved from string + expect(s.ref!.id).toBe(7) // resolved from string + expect(getSnapshot(s).ref).toBe("7") // ref serialized as string (number would be ok as well) + + s.ref = s.mies.get("8")! + expect(s.ref.id).toBe(8) // resolved from instance + expect(getSnapshot(s).ref).toBe(8) // ref serialized as number + + s.ref = "9" as any // unresolvable + expect(getSnapshot(s).ref).toBe("9") // snapshot preserved as it was unresolvable + + s.mies.set(9 as any, { + id: 9 + }) + expect(Array.from(s.mies.keys())).toEqual(["7", "8", "9"]) + expect(s.mies.get("9")!.id).toBe(9) + expect(getSnapshot(s).ref).toBe("9") // ref serialized as string (number would be ok as well) +}) + +test("#1052 - Reference returns destroyed model after subtree replacing", () => { + const Todo = types.model("Todo", { + id: types.identifierNumber, + title: types.string + }) + + const Todos = types.model("Todos", { + items: types.array(Todo) + }) + + const Store = types + .model("Store", { + todos: Todos, + last: types.maybe(types.reference(Todo)), + lastWithId: types.maybe(types.reference(Todo)), + counter: -1 + }) + .actions((self) => ({ + load() { + self.counter++ + self.todos = Todos.create({ + items: [ + { id: 1, title: "Get Coffee " + self.counter }, + { id: 2, title: "Write simpler code " + self.counter } + ] + }) + }, + select(todo: Instance) { + self.last = todo + self.lastWithId = todo.id as any + } + })) + + const store = Store.create({ todos: {} }) + store.load() + + expect(store.last).toBe(undefined) + expect(store.lastWithId).toBe(undefined) + + const reactionFn = jest.fn() + const reactionDisposer = reaction(() => store.last, reactionFn) + const reactionFn2 = jest.fn() + const reactionDisposer2 = reaction(() => store.lastWithId, reactionFn2) + + try { + store.select(store.todos.items[0]) + + expect(isAlive(store.last!)).toBe(true) + expect(isObservable(store.last)).toBe(true) + expect(reactionFn).toHaveBeenCalledTimes(1) + expect(store.last!.title).toBe("Get Coffee 0") + + expect(isAlive(store.lastWithId!)).toBe(true) + expect(isObservable(store.lastWithId)).toBe(true) + expect(reactionFn2).toHaveBeenCalledTimes(1) + expect(store.lastWithId!.title).toBe("Get Coffee 0") + + store.load() + + expect(isAlive(store.last!)).toBe(true) + expect(isObservable(store.last)).toBe(true) + expect(reactionFn).toHaveBeenCalledTimes(2) + expect(store.last!.title).toBe("Get Coffee 1") + + expect(isAlive(store.lastWithId!)).toBe(true) + expect(isObservable(store.lastWithId)).toBe(true) + expect(reactionFn2).toHaveBeenCalledTimes(2) + expect(store.lastWithId!.title).toBe("Get Coffee 1") + } finally { + reactionDisposer() + reactionDisposer2() + } +}) + +test("#1080 - does not crash trying to resolve a reference to a destroyed+recreated model", () => { + configure({ + useProxies: "never" + }) + + const Branch = types.model("Branch", { + id: types.identifierNumber, + name: types.string + }) + + const User = types.model("User", { + id: types.identifierNumber, + email: types.maybeNull(types.string), + branches: types.maybeNull(types.array(Branch)) + }) + + const BranchStore = types + .model("BranchStore", { + activeBranch: types.maybeNull(types.reference(Branch)) + }) + .actions((self) => ({ + setActiveBranch(branchId: any) { + self.activeBranch = branchId + } + })) + + const RootStore = types + .model("RootStore", { + user: types.maybeNull(User), + branchStore: types.maybeNull(BranchStore) + }) + .actions((self) => ({ + setUser(snapshot: typeof userSnapshot) { + self.user = cast(snapshot) + }, + setBranchStore(snapshot: typeof branchStoreSnapshot) { + self.branchStore = cast(snapshot) + }, + destroyUser() { + destroy(self.user!) + }, + destroyBranchStore() { + destroy(self.branchStore!) + } + })) + + const userSnapshot = { + id: 1, + email: "test@test.com", + branches: [ + { + id: 1, + name: "Branch 1" + }, + { + id: 2, + name: "Branch 2" + } + ] + } + + const branchStoreSnapshot = {} + const rootStore = RootStore.create({ user: userSnapshot, branchStore: branchStoreSnapshot }) + + rootStore.branchStore!.setActiveBranch(1) + expect(rootStore.branchStore!.activeBranch).toEqual({ + id: 1, + name: "Branch 1" + }) + + rootStore.destroyUser() + rootStore.destroyBranchStore() + + rootStore.setUser(userSnapshot) + rootStore.setBranchStore(branchStoreSnapshot) + + rootStore.branchStore!.setActiveBranch(2) + expect(rootStore.branchStore!.activeBranch).toEqual({ + id: 2, + name: "Branch 2" + }) +}) + +test("tryReference / isValidReference", () => { + const Todo = types.model({ id: types.identifier }) + + const TodoStore = types + .model({ + todos: types.array(Todo), + ref1: types.maybe(types.reference(Todo)), + ref2: types.maybeNull(types.reference(Todo)), + ref3: types.maybe(types.reference(Todo)) + }) + .actions((self) => ({ + clearRef3() { + self.ref3 = undefined + }, + afterCreate() { + addDisposer( + self, + reaction( + () => isValidReference(() => self.ref3), + (valid) => { + if (!valid) { + this.clearRef3() + } + }, + { fireImmediately: true } + ) + ) + } + })) + + const store = TodoStore.create({ + todos: [{ id: "1" }, { id: "2" }, { id: "3" }] + }) + + expect(tryReference(() => store.ref1)).toBeUndefined() + expect(tryReference(() => store.ref2)).toBeUndefined() + expect(isValidReference(() => store.ref1)).toBe(false) + expect(isValidReference(() => store.ref2)).toBe(false) + + unprotect(store) + store.ref1 = store.todos[0] + store.ref2 = store.todos[1] + store.ref3 = store.todos[2] + + expect(isStateTreeNode(store.ref1)).toBe(true) + expect(isStateTreeNode(store.ref2)).toBe(true) + + expect(tryReference(() => store.ref1)).toBeDefined() + expect(tryReference(() => store.ref2)).toBeDefined() + expect(isValidReference(() => store.ref1)).toBe(true) + expect(isValidReference(() => store.ref2)).toBe(true) + + store.todos = cast([]) + + expect(tryReference(() => store.ref1)).toBeUndefined() + expect(tryReference(() => store.ref2)).toBeUndefined() + expect(isValidReference(() => store.ref1)).toBe(false) + expect(isValidReference(() => store.ref2)).toBe(false) + + // the reaction should have triggered and set this to undefined + expect(store.ref3).toBe(undefined) + + expect(() => tryReference(() => 5 as any)).toThrowError( + "The reference to be checked is not one of node, null or undefined" + ) + expect(() => isValidReference(() => 5 as any)).toThrowError( + "The reference to be checked is not one of node, null or undefined" + ) +}) + +test("#1162 - reference to union", () => { + const M1 = types.model({ id: types.identifier, type: types.string, sum: types.string }) + const M2 = types.model({ + id: types.identifier, + type: types.string, + data: types.string + }) + const AnyModel = types.union( + { + dispatcher(snapshot) { + switch (snapshot.type) { + case "type1": + return M1 + case "type2": + return M2 + default: + throw new Error() + } + } + }, + M1, + M2 + ) + + const Store = types.model({ + arr: types.array(AnyModel), + selected: types.reference(AnyModel) + }) + + const s = Store.create({ + selected: "num1", + arr: [ + { id: "num1", type: "type1", sum: "1" }, + { id: "num2", type: "type1", sum: "2" }, + { id: "num3", type: "type2", data: "3" } + ] + }) + unprotect(s) + + expect(s.selected.id).toBe("num1") + expect(s.selected.type).toBe("type1") + expect((s.selected as Instance).sum).toBe("1") + + s.selected = "num2" as any + expect(s.selected.id).toBe("num2") + expect(s.selected.type).toBe("type1") + expect((s.selected as Instance).sum).toBe("2") + + s.selected = "num3" as any + expect(s.selected.id).toBe("num3") + expect(s.selected.type).toBe("type2") + expect((s.selected as Instance).data).toBe("3") +}) diff --git a/__tests__/core/refinement.test.ts b/__tests__/core/refinement.test.ts new file mode 100644 index 000000000..659eb2aac --- /dev/null +++ b/__tests__/core/refinement.test.ts @@ -0,0 +1,53 @@ +import { getSnapshot, types } from "../../src" + +test("it should allow if type and predicate is correct", () => { + const Factory = types.model({ + number: types.refinement( + "positive number", + types.optional(types.number, 0), + (s) => typeof s === "number" && s >= 0 + ) + }) + const doc = Factory.create({ number: 42 }) + expect(getSnapshot(doc)).toEqual({ number: 42 }) +}) +if (process.env.NODE_ENV !== "production") { + test("it should throw if a correct type with failing predicate is given", () => { + const Factory = types.model({ + number: types.refinement( + "positive number", + types.optional(types.number, 0), + (s) => typeof s === "number" && s >= 0 + ) + }) + expect(() => { + Factory.create({ number: "givenStringInstead" } as any) + }).toThrowError( + `[mobx-state-tree] Error while converting \`{\"number\":\"givenStringInstead\"}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`\"givenStringInstead\"\` is not assignable to type: \`positive number\` (Value is not a number).` + ) + expect(() => { + Factory.create({ number: -4 }) + }).toThrowError( + `[mobx-state-tree] Error while converting \`{\"number\":-4}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`-4\` is not assignable to type: \`positive number\` (Value does not respect the refinement predicate).` + ) + }) + test("it should throw custom error message with failing predicate is given", () => { + const Factory = types.model({ + number: types.refinement( + types.optional(types.number, 0), + (s) => typeof s === "number" && s >= 0, + (s) => "A positive number was expected" + ) + }) + expect(() => { + Factory.create({ number: "givenStringInstead" } as any) + }).toThrowError( + `[mobx-state-tree] Error while converting \`{\"number\":\"givenStringInstead\"}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`\"givenStringInstead\"\` is not assignable to type: \`number\` (Value is not a number).` + ) + expect(() => { + Factory.create({ number: -4 }) + }).toThrowError( + `[mobx-state-tree] Error while converting \`{\"number\":-4}\` to \`AnonymousModel\`:\n\n at path "/number" value \`-4\` is not assignable to type: \`number\` (A positive number was expected).` + ) + }) +} diff --git a/__tests__/core/reflection.test.ts b/__tests__/core/reflection.test.ts new file mode 100644 index 000000000..71c9e0cbe --- /dev/null +++ b/__tests__/core/reflection.test.ts @@ -0,0 +1,244 @@ +import { + types, + getMembers, + getPropertyMembers, + IAnyStateTreeNode, + getType, + IAnyModelType, + IModelReflectionData, + IModelReflectionPropertiesData, + flow +} from "../../src" + +const User = types.model("User", { + id: types.identifier, + name: types.string +}) + +const Model = types + .model({ + isPerson: false, + users: types.optional(types.map(User), {}), + dogs: types.array(User), + user: types.maybe(types.late(() => User)) + }) + .volatile((self) => ({ + volatileProperty: { propName: "halo" } + })) + .actions((self) => { + function actionName() { + return 1 + } + return { + actionName, + generatorAction: flow(function* generatorAction() { + const promise = new Promise((resolve) => { + resolve(true) + }) + yield promise + }) + } + }) + .views((self) => ({ + get viewName() { + return 1 + } + })) + +function expectPropertyMembersToMatchMembers( + propertyMembers: IModelReflectionPropertiesData, + members: IModelReflectionData +) { + expect(propertyMembers).toEqual({ + name: members.name, + properties: members.properties + }) +} + +test("reflection - model", () => { + const node = Model.create() + const reflection = getMembers(node) + expect(reflection.name).toBe("AnonymousModel") + expect(reflection.actions.includes("actionName")).toBe(true) + expect(reflection.flowActions.includes("generatorAction")).toBe(true) + expect(reflection.views.includes("viewName")).toBe(true) + expect(reflection.volatile.includes("volatileProperty")).toBe(true) + expect(!!reflection.properties.users).toBe(true) + expect(!!reflection.properties.isPerson).toBe(true) + + const typeReflection = getPropertyMembers(Model) + expectPropertyMembersToMatchMembers(typeReflection, reflection) + const reflection2 = getPropertyMembers(node) + expectPropertyMembersToMatchMembers(reflection2, reflection) +}) +test("reflection - map", () => { + const node = Model.create({ + users: { "1": { id: "1", name: "Test" } } + }) + const node2 = node.users.get("1")! + const reflection = getMembers(node2) + expect(reflection.name).toBe("User") + expect(!!reflection.properties.id).toBe(true) + expect(!!reflection.properties.name).toBe(true) + + const typeReflection = getPropertyMembers(getType(node2) as IAnyModelType) + expectPropertyMembersToMatchMembers(typeReflection, reflection) + const reflection2 = getPropertyMembers(node2) + expectPropertyMembersToMatchMembers(reflection2, reflection) +}) +test("reflection - array", () => { + const node = Model.create({ + dogs: [{ id: "1", name: "Test" }] + }) + const node2 = node.dogs[0] + const reflection = getMembers(node2) + expect(!!reflection.properties.id).toBe(true) + expect(!!reflection.properties.name).toBe(true) + + const typeReflection = getPropertyMembers(getType(node2) as IAnyModelType) + expectPropertyMembersToMatchMembers(typeReflection, reflection) + const reflection2 = getPropertyMembers(node2) + expectPropertyMembersToMatchMembers(reflection2, reflection) +}) +test("reflection - late", () => { + const node = Model.create({ + user: { id: "5", name: "Test" } + }) + const empty: IAnyStateTreeNode = {} + const reflection = getMembers(node.user || empty) + const keys = Object.keys(reflection.properties || {}) + expect(keys.includes("name")).toBe(true) + expect(reflection.properties.name.describe()).toBe("string") +}) +if (process.env.NODE_ENV !== "production") { + test("reflection - throw on non model node for getMembers", () => { + const node = Model.create({ + users: { "1": { id: "1", name: "Test" } } + }) + expect(() => (node.users ? getMembers(node.users) : {})).toThrowError() + }) + + test("reflection - throw on non model type/node for getMembers", () => { + expect(() => getPropertyMembers(types.array(types.number) as any)).toThrowError() + + const node = Model.create({ + users: { "1": { id: "1", name: "Test" } } + }) + expect(() => getPropertyMembers(node.users)).toThrowError() + }) +} +test("reflection - can retrieve property names", () => { + const node = Model.create() + const reflection = getMembers(node) + const keys = Object.keys(reflection.properties) + expect(keys.includes("users")).toBe(true) + expect(keys.includes("isPerson")).toBe(true) +}) +test("reflection - property contains type", () => { + const TestModel = types.model({ + string: types.string, + optional: false + }) + const node = TestModel.create({ + string: "hello" + }) + const reflection = getMembers(node) + expect(reflection.properties.string).toBe(types.string) + expect(reflection.properties.optional).toMatchObject(types.optional(types.boolean, false)) +}) +test("reflection - members chained", () => { + const ChainedModel = types + .model({ + isPerson: false + }) + .actions((self) => { + return { + actionName() { + return 1 + } + } + }) + .actions((self) => { + return { + anotherAction() { + return 1 + } + } + }) + .views((self) => ({ + get viewName() { + return 1 + } + })) + .views((self) => ({ + anotherView(prop: string) { + return 1 + } + })) + const node = ChainedModel.create() + const reflection = getMembers(node) + const keys = Object.keys(reflection.properties || {}) + expect(keys.includes("isPerson")).toBe(true) + expect(reflection.actions.includes("actionName")).toBe(true) + expect(reflection.actions.includes("anotherAction")).toBe(true) + expect(reflection.views.includes("viewName")).toBe(true) + expect(reflection.views.includes("anotherView")).toBe(true) +}) +test("reflection - conditionals respected", () => { + let swap = true + const ConditionalModel = types + .model({ + isPerson: false + }) + .actions((self) => ({ + actionName0() { + return 1 + } + })) + .actions((self): { actionName1(): number } | { actionName2(): number } => { + if (swap) { + return { + actionName1() { + return 1 + } + } + } else { + return { + actionName2() { + return 1 + } + } + } + }) + .views((self) => { + if (swap) { + return { + get view1() { + return 1 + } + } + } else { + return { + get view2() { + return 1 + } + } + } + }) + // swap true + const node = ConditionalModel.create() + const reflection = getMembers(node) + expect(reflection.actions.includes("actionName0")).toBe(true) + expect(reflection.actions.includes("actionName1")).toBe(true) + expect(reflection.actions.includes("actionName2")).toBe(false) + expect(reflection.views.includes("view1")).toBe(true) + expect(reflection.views.includes("view2")).toBe(false) + swap = false + const node2 = ConditionalModel.create() + const reflection2 = getMembers(node2) + expect(reflection.actions.includes("actionName0")).toBe(true) + expect(reflection2.actions.includes("actionName1")).toBe(false) + expect(reflection2.actions.includes("actionName2")).toBe(true) + expect(reflection2.views.includes("view1")).toBe(false) + expect(reflection2.views.includes("view2")).toBe(true) +}) diff --git a/__tests__/core/snapshotProcessor.test.ts b/__tests__/core/snapshotProcessor.test.ts new file mode 100644 index 000000000..c0dab1d0d --- /dev/null +++ b/__tests__/core/snapshotProcessor.test.ts @@ -0,0 +1,805 @@ +import { + types, + getSnapshot, + unprotect, + cast, + detach, + clone, + SnapshotIn, + getNodeId +} from "../../src" + +describe("snapshotProcessor", () => { + describe("over a model type", () => { + const M = types.model({ + x: types.string + }) + + test("no processors", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, {}) + }) + const model = Model.create({ m: { x: "hi" } }) + unprotect(model) + expect(model.m.x).toBe("hi") + expect(getSnapshot(model).m.x).toBe("hi") + // reconciliation + model.m = { x: "ho" } + expect(model.m.x).toBe("ho") + expect(getSnapshot(model).m.x).toBe("ho") + }) + + test("pre processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: { x: number }) { + return { + ...sn, + x: String(sn.x) + } + } + }) + }) + const model = Model.create({ m: { x: 5 } }) + unprotect(model) + expect(model.m.x).toBe("5") + expect(getSnapshot(model).m.x).toBe("5") + // reconciliation + model.m = cast({ x: 6 }) + expect(model.m.x).toBe("6") + expect(getSnapshot(model).m.x).toBe("6") + }) + + test("post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + postProcessor(sn): { x: number } { + return { + ...sn, + x: Number(sn.x) + } + } + }) + }) + const model = Model.create({ + m: { x: "5" } + }) + unprotect(model) + expect(model.m.x).toBe("5") + expect(getSnapshot(model).m.x).toBe(5) + // reconciliation + model.m = cast({ x: "6" }) + expect(model.m.x).toBe("6") + expect(getSnapshot(model).m.x).toBe(6) + }) + + test("pre and post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: { x: number }) { + return { + ...sn, + x: String(sn.x) + } + }, + postProcessor(sn): { x: number } { + return { + ...sn, + x: Number(sn.x) + } + } + }) + }) + const model = Model.create({ + m: { x: 5 } + }) + unprotect(model) + expect(model.m.x).toBe("5") + expect(getSnapshot(model).m.x).toBe(5) + // reconciliation + model.m = cast({ x: 6 }) + expect(model.m.x).toBe("6") + expect(getSnapshot(model).m.x).toBe(6) + // cloning + expect(getSnapshot(clone(model.m)).x).toBe(6) + }) + }) + + describe("over a literal type", () => { + const M = types.string + + test("no processors", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, {}) + }) + const model = Model.create({ m: "hi" }) + unprotect(model) + expect(model.m).toBe("hi") + expect(getSnapshot(model).m).toBe("hi") + // reconciliation + model.m = "ho" + expect(model.m).toBe("ho") + expect(getSnapshot(model).m).toBe("ho") + }) + + test("pre processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: number) { + return String(sn) + } + }) + }) + const model = Model.create({ m: 5 }) + unprotect(model) + expect(model.m).toBe("5") + expect(getSnapshot(model).m).toBe("5") + // reconciliation + model.m = 6 as any + expect(model.m).toBe("6") + expect(getSnapshot(model).m).toBe("6") + }) + + test("post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + postProcessor(sn): number { + return Number(sn) + } + }) + }) + const model = Model.create({ + m: "5" + }) + unprotect(model) + expect(model.m).toBe("5") + expect(getSnapshot(model).m).toBe(5) + // reconciliation + model.m = "6" + expect(model.m).toBe("6") + expect(getSnapshot(model).m).toBe(6) + }) + + test("pre and post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: number) { + return String(sn) + }, + postProcessor(sn): number { + return Number(sn) + } + }) + }) + const model = Model.create({ + m: 5 + }) + unprotect(model) + expect(model.m).toBe("5") + expect(getSnapshot(model).m).toBe(5) + // reconciliation + model.m = "6" + expect(model.m).toBe("6") + expect(getSnapshot(model).m).toBe(6) + // cloning + expect(getSnapshot(clone(model)).m).toBe(6) + }) + }) + + describe("over an array type", () => { + const M = types.array(types.string) + + test("no processors", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, {}) + }) + const model = Model.create({ m: ["hi"] }) + unprotect(model) + expect(model.m[0]).toBe("hi") + expect(getSnapshot(model).m[0]).toBe("hi") + // reconciliation + model.m = cast(["ho"]) + expect(model.m[0]).toBe("ho") + expect(getSnapshot(model).m[0]).toBe("ho") + }) + + test("pre processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: number[]) { + return sn.map((n) => String(n)) + } + }) + }) + const model = Model.create({ m: [5] }) + unprotect(model) + expect(model.m[0]).toBe("5") + expect(getSnapshot(model).m[0]).toBe("5") + // reconciliation + model.m = cast([6]) + expect(model.m[0]).toBe("6") + expect(getSnapshot(model).m[0]).toBe("6") + }) + + test("post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + postProcessor(sn): number[] { + return sn.map((n) => Number(n)) + } + }) + }) + const model = Model.create({ + m: ["5"] + }) + unprotect(model) + expect(model.m[0]).toBe("5") + expect(getSnapshot(model).m[0]).toBe(5) + // reconciliation + model.m = cast(["6"]) + expect(model.m[0]).toBe("6") + expect(getSnapshot(model).m[0]).toBe(6) + }) + + test("pre and post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: number[]) { + return sn.map((n) => String(n)) + }, + postProcessor(sn): number[] { + return sn.map((n) => Number(n)) + } + }) + }) + const model = Model.create({ + m: [5] + }) + unprotect(model) + expect(model.m[0]).toBe("5") + expect(getSnapshot(model).m[0]).toBe(5) + // reconciliation + model.m = cast([6]) + expect(model.m[0]).toBe("6") + expect(getSnapshot(model).m[0]).toBe(6) + // cloning + expect(getSnapshot(clone(model.m))[0]).toBe(6) + }) + }) + + describe("over a map type", () => { + const M = types.map(types.string) + + test("no processors", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, {}) + }) + const model = Model.create({ m: { x: "hi" } }) + unprotect(model) + expect(model.m.get("x")).toBe("hi") + expect(getSnapshot(model).m.x).toBe("hi") + // reconciliation + model.m.set("x", "ho") + expect(model.m.get("x")).toBe("ho") + expect(getSnapshot(model).m.x).toBe("ho") + }) + + test("pre processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: { x: number }) { + return { + ...sn, + x: String(sn.x) + } + } + }) + }) + const model = Model.create({ m: { x: 5 } }) + unprotect(model) + expect(model.m.get("x")).toBe("5") + expect(getSnapshot(model).m.x).toBe("5") + // reconciliation + model.m = cast({ x: 6 }) + expect(model.m.get("x")).toBe("6") + expect(getSnapshot(model).m.x).toBe("6") + }) + + test("post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + postProcessor(sn): { x: number } { + return { + ...sn, + x: Number(sn.x) + } + } + }) + }) + const model = Model.create({ + m: { x: "5" } + }) + unprotect(model) + expect(model.m.get("x")).toBe("5") + expect(getSnapshot(model).m.x).toBe(5) + // reconciliation + model.m = cast({ x: "6" }) + expect(model.m.get("x")).toBe("6") + expect(getSnapshot(model).m.x).toBe(6) + }) + + test("pre and post processor", () => { + const Model = types.model({ + m: types.snapshotProcessor(M, { + preProcessor(sn: { x: number }) { + return { + ...sn, + x: String(sn.x) + } + }, + postProcessor(sn): { x: number } { + return { + ...sn, + x: Number(sn.x) + } + } + }) + }) + const model = Model.create({ + m: { x: 5 } + }) + unprotect(model) + expect(model.m.get("x")).toBe("5") + expect(getSnapshot(model).m.x).toBe(5) + // reconciliation + model.m = cast({ x: 6 }) + expect(model.m.get("x")).toBe("6") + expect(getSnapshot(model).m.x).toBe(6) + // cloning + expect(getSnapshot(clone(model.m)).x).toBe(6) + }) + }) + + test("chained transforms", () => { + const TL = types.snapshotProcessor(types.string, { + preProcessor(sn: string) { + return sn.trimLeft() + }, + postProcessor(sn): string { + return "_" + sn + } + }) + const TB = types.snapshotProcessor(TL, { + preProcessor(sn: string) { + return sn.trimRight() + }, + postProcessor(sn): string { + return sn + "_" + } + }) + const M = types.model({ + name: TB + }) + + const t = TB.create(" hello ") + expect(t).toBe("hello") + + const m = M.create({ + name: " hello " + }) + expect(m.name).toBe("hello") + expect(getSnapshot(m).name).toBe("_hello_") + }) + + describe("moving nodes around with a pre-processor", () => { + const Task = types.model("Task", { x: types.number }) + const Store = types.model({ + a: types.array( + types.snapshotProcessor( + Task, + { + preProcessor(sn: { x: string }) { + return { + x: Number(sn.x) + } + } + }, + "PTask" + ) + ), + b: types.array(Task) + }) + + test("moving from a to b", () => { + const s = Store.create({ + a: [{ x: "1" }] + }) + unprotect(s) + const n = s.a[0] + detach(n) + expect(s.a.length).toBe(0) + expect(getSnapshot(n)).toEqual({ x: 1 }) + + s.b.push(n) + expect(s.b.length).toBe(1) + expect(getSnapshot(s.b)).toEqual([{ x: 1 }]) + }) + + test("moving from b to a", () => { + const s = Store.create({ + b: [{ x: 1 }] + }) + unprotect(s) + const n = s.b[0] + detach(n) + expect(s.b.length).toBe(0) + expect(getSnapshot(n)).toEqual({ x: 1 }) + + s.a.push(n) + expect(s.a.length).toBe(1) + expect(getSnapshot(s.a)).toEqual([{ x: 1 }]) + }) + }) + + describe("moving nodes around with a post-processor", () => { + const Task = types.model({ x: types.number }) + const Store = types.model({ + a: types.array( + types.snapshotProcessor(Task, { + postProcessor(sn): { x: string } { + return { + x: String(sn.x) + } + } + }) + ), + b: types.array(Task) + }) + + test("moving from a to b", () => { + const s = Store.create({ + a: [{ x: 1 }] + }) + unprotect(s) + const n = s.a[0] + detach(n) + expect(s.a.length).toBe(0) + expect(getSnapshot(n)).toEqual({ x: "1" }) + + s.b.push(n) + expect(s.b.length).toBe(1) + expect(getSnapshot(s.b)).toEqual([{ x: "1" }]) + }) + + test("moving from b to a", () => { + const s = Store.create({ + b: [{ x: 1 }] + }) + unprotect(s) + const n = s.b[0] + detach(n) + expect(s.b.length).toBe(0) + expect(getSnapshot(n)).toEqual({ x: 1 }) + + s.a.push(n) + expect(s.a.length).toBe(1) + expect(getSnapshot(s.a)).toEqual([{ x: "1" }]) + }) + }) + + describe("assigning instances works", () => { + const Todo = types.model("Todo", { + id: types.identifier + }) + + const TodoWithProcessor = types.snapshotProcessor(Todo, { + preProcessor(snapshot: { id: string }) { + return snapshot + } + }) + + const Store = types + .model("TodoStore", { + todos: types.map(TodoWithProcessor), + instance: types.optional(TodoWithProcessor, { id: "new" }) + }) + .actions((self) => ({ + addTodo(todo: { id: string }) { + self.todos.put(todo) + }, + setInstance(next: { id: string }) { + self.instance = next + } + })) + + test("using instances in maps work", () => { + const store = Store.create() + const todo = TodoWithProcessor.create({ id: "map" }) + + store.addTodo(todo) + + expect(store.todos.size).toBe(1) + expect(getSnapshot(store.todos)).toEqual({ map: { id: "map" } }) + }) + + test("using instances as values works", () => { + const store = Store.create() + const todo = TodoWithProcessor.create({ id: "map" }) + + store.setInstance(todo) + + expect(store.instance).toBe(todo) + }) + + test("using the non processed type in place of the processed one works", () => { + const store = Store.create() + const todo = Todo.create({ id: "map" }) + + store.setInstance(todo) + + expect(store.instance).toBe(todo) + }) + + test("using the processed type in place of the non processed one works", () => { + const store = types + .model("Store", { instance: Todo }) + .actions((self) => ({ + setInstance(next: { id: string }) { + self.instance = next + } + })) + .create({ instance: { id: "new" } }) + + const todo = TodoWithProcessor.create({ id: "map" }) + + store.setInstance(todo) + + expect(store.instance).toBe(todo) + }) + }) + + test("cached initial snapshots are ok", () => { + const M2 = types.snapshotProcessor(types.model({ x: types.number }), { + preProcessor(sn: { x: number }) { + return { ...sn, x: 0 } + } + }) + const M1 = types.model({ m2: M2 }) + const M = types.model({ m1: M1 }) + + const m = M.create({ m1: { m2: { x: 10 } } }) + expect(getSnapshot(m)).toEqual({ + m1: { m2: { x: 0 } } + }) + }) + + test("works with IType.is", () => { + const Model = types.model({ x: types.number }) + const model = Model.create({ x: 1 }) + expect(Model.is(model)).toBe(true) + expect(Model.is({ x: 1 })).toBe(true) + + const ProcessedModel = types.snapshotProcessor(Model, { + preProcessor(sn: { y: number }) { + const copy = { ...sn, x: sn.y } + // @ts-ignore + delete copy.y + return copy + }, + postProcessor(sn: { x: number }) { + const copy = { ...sn, y: sn.x } + // @ts-ignore + delete copy.x + return copy + } + }) + + const processedModel = ProcessedModel.create({ y: 1 }) + expect(ProcessedModel.is(processedModel)).toBe(true) + expect(ProcessedModel.is({ y: 1 })).toBe(true) + expect(ProcessedModel.is(Model)).toBe(false) + }) + + describe("1776 - reconciliation in an array", () => { + test("model with transformed property is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier, + x: types.number + }), + { + preProcessor(sn: { id: string; y: number }) { + if ("x" in sn) { + // Ensure snapshot don't run through preprocessor twice + throw new Error("sn has already been preprocessed") + } + return { id: sn.id, x: sn.y } + } + } + ) + const Store = types.model({ items: types.array(SP) }).actions((self) => ({ + setItems(items: SnapshotIn[]) { + self.items = cast(items) + } + })) + const store = Store.create({ items: [{ id: "1", y: 0 }] }) + const oldNodeId = getNodeId(store.items[0]) + store.setItems([{ id: "1", y: 1 }]) + expect(getNodeId(store.items[0])).toBe(oldNodeId) + }) + + test("model with transformed identifier attribute is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier + }), + { + preProcessor(sn: { foo: string }) { + return { id: sn.foo } + } + } + ) + const Store = types.model({ items: types.array(SP) }).actions((self) => ({ + setItems(items: SnapshotIn[]) { + self.items = cast(items) + } + })) + const store = Store.create({ items: [{ foo: "1" }] }) + const oldNodeId = getNodeId(store.items[0]) + store.setItems([{ foo: "1" }]) + expect(getNodeId(store.items[0])).toBe(oldNodeId) + }) + }) + + describe("single node reconcilication", () => { + test("model with transformed property is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier, + x: types.number + }), + { + preProcessor(sn: { id: string; y: number }) { + if ("x" in sn) { + // Ensure snapshot don't run through preprocessor twice + throw new Error("sn has already been preprocessed") + } + return { id: sn.id, x: sn.y } + } + } + ) + const Store = types.model({ item: SP }).actions((self) => ({ + setItem(item: SnapshotIn) { + self.item = cast(item) + } + })) + const store = Store.create({ item: { id: "1", y: 0 } }) + const oldNodeId = getNodeId(store.item) + store.setItem({ id: "1", y: 1 }) + expect(getNodeId(store.item)).toBe(oldNodeId) + expect(store.item.x).toBe(1) + }) + + test("model with transformed identifier property is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier + }), + { + preProcessor(sn: { foo: string }) { + return { id: sn.foo } + } + } + ) + const Store = types.model({ item: SP }).actions((self) => ({ + setItem(item: SnapshotIn) { + self.item = cast(item) + } + })) + const store = Store.create({ item: { foo: "1" } }) + const oldNodeId = getNodeId(store.item) + store.setItem({ foo: "1" }) + expect(getNodeId(store.item)).toBe(oldNodeId) + expect(store.item.id).toBe("1") + }) + + test("1791 - model wrapped with maybe is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier, + x: types.number + }), + { + preProcessor(sn: { id: string; y: number }) { + return { id: sn.id, x: sn.y } + } + } + ) + const Store = types.model({ item: types.maybe(SP) }).actions((self) => ({ + setItem(item: SnapshotIn) { + self.item = cast(item) + } + })) + const store = Store.create({ item: { id: "1", y: 0 } }) + const oldNodeId = getNodeId(store.item!) + store.setItem({ id: "1", y: 1 }) + expect(getNodeId(store.item!)).toBe(oldNodeId) + expect(store.item?.x).toBe(1) + }) + + test("model wrapped with optional is reconciled", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier, + x: types.number + }), + { + preProcessor(sn: { id: string; y: number }) { + return { id: sn.id, x: sn.y } + } + } + ) + const Store = types + .model({ item: types.optional(SP, { id: "1", y: 0 }) }) + .actions((self) => ({ + setItem(item?: SnapshotIn) { + self.item = cast(item) + } + })) + const store = Store.create() + const oldNodeId = getNodeId(store.item!) + expect(store.item?.x).toBe(0) + store.setItem({ id: "1", y: 1 }) + expect(getNodeId(store.item!)).toBe(oldNodeId) + expect(store.item?.x).toBe(1) + store.setItem(undefined) + expect(getNodeId(store.item!)).toBe(oldNodeId) + expect(store.item?.x).toBe(0) + }) + }) + + test("1777 - preProcessor wrapped in maybe accepts undefined", () => { + const SP = types.snapshotProcessor( + types.model({ + id: types.identifier, + x: types.number + }), + { + preProcessor(sn: { id: string; y: number }) { + return { id: sn.id, x: sn.y } + } + } + ) + const Store = types.model({ item: types.maybe(SP) }).actions((self) => ({ + setItem(item?: SnapshotIn) { + self.item = cast(item) + } + })) + const store = Store.create() + expect(store.item).toBeUndefined() + store.setItem({ id: "1", y: 1 }) + expect(store.item?.x).toBe(1) + store.setItem(undefined) + expect(store.item).toBeUndefined() + }) + + test("1849 - Wrapped unions don't cause infinite recursion", () => { + const Store = types + .model({ + prop: types.optional( + types.snapshotProcessor(types.union(types.literal("a"), types.literal("b")), {}), + "a" + ) + }) + .actions((self) => ({ + setProp(prop: typeof self.prop) { + self.prop = prop + } + })) + + const store = Store.create() + expect(store.prop).toBe("a") + expect(() => store.setProp("b")).not.toThrow() + expect(store.prop).toBe("b") + }) +}) diff --git a/__tests__/core/this.test.ts b/__tests__/core/this.test.ts new file mode 100644 index 000000000..98f504b64 --- /dev/null +++ b/__tests__/core/this.test.ts @@ -0,0 +1,94 @@ +import { types } from "../../src" +import { isObservableProp, isComputedProp } from "mobx" + +// MWE: disabled test, `this` isn't supposed to work, and afaik nowhere advertised +test.skip("this support", () => { + const M = types + .model({ x: 5 }) + .views((self) => ({ + get x2() { + return self.x * 2 + }, + get x4() { + return this.x2 * 2 + }, + boundTo() { + return this + }, + innerBoundTo() { + return () => this + }, + isThisObservable() { + return ( + isObservableProp(this, "x2") && + isObservableProp(this, "x4") && + isObservableProp(this, "localState") && + isComputedProp(this, "x2") + ) + } + })) + .volatile((self) => ({ + localState: 3, + getLocalState() { + return this.localState + }, + getLocalState2() { + return this.getLocalState() * 2 + } + })) + + .actions((self) => { + return { + xBy(by: number) { + return self.x * by + }, + setX(x: number) { + self.x = x + }, + setThisX(x: number) { + ;(this as any).x = x // this should not affect self.x + }, + setXBy(x: number) { + this.setX(this.xBy(x)) + }, + setLocalState(x: number) { + self.localState = x + } + } + }) + + const mi = M.create() + + expect(mi.isThisObservable()).toBe(true) + + expect(mi.boundTo()).toBe(mi) + expect(mi.innerBoundTo()()).toBe(mi) + + expect(mi.x).toBe(5) + + mi.setX(6) + expect(mi.x).toBe(6) + + mi.setXBy(2) + expect(mi.x).toBe(12) + expect(mi.x2).toBe(12 * 2) + expect(mi.x4).toBe(12 * 4) + expect(mi.xBy(2)).toBe(24) + + expect(mi.localState).toBe(3) + expect(mi.getLocalState()).toBe(3) + expect(mi.getLocalState2()).toBe(3 * 2) + + mi.setLocalState(6) + expect(mi.localState).toBe(6) + expect(mi.getLocalState()).toBe(6) + expect(mi.getLocalState2()).toBe(6 * 2) + + mi.setLocalState(7) + expect(mi.localState).toBe(7) + + // make sure attempts to modify this (as long as it is not an action) doesn't affect self + const oldX = mi.x + mi.setThisX(oldX + 1) + expect(mi.x).toBe(oldX) +}) diff --git a/__tests__/core/type-system.test.ts b/__tests__/core/type-system.test.ts new file mode 100644 index 000000000..6ce1f4463 --- /dev/null +++ b/__tests__/core/type-system.test.ts @@ -0,0 +1,1152 @@ +import { assert, _ } from "spec.ts" + +import { + types, + getSnapshot, + unprotect, + getRoot, + getParent, + SnapshotOrInstance, + cast, + SnapshotIn, + Instance, + castToSnapshot, + IType, + isStateTreeNode, + isFrozenType, + TypeOfValue, + IAnyType, + ModelPrimitive, + ModelPropertiesDeclaration, + SnapshotOut +} from "../../src" +import { $nonEmptyObject } from "../../src/internal" + +const createTestFactories = () => { + const Box = types.model({ + width: 0, + height: 0 + }) + const Square = types.model({ + width: 0, + height: 0 + }) + const Cube = types.model({ + width: 0, + height: 0, + depth: 0 + }) + return { Box, Square, Cube } +} +test("it should recognize a valid snapshot", () => { + const { Box } = createTestFactories() + expect(Box.is({ width: 1, height: 2 })).toEqual(true) + expect(Box.is({ width: 1, height: 2, depth: 3 })).toEqual(true) +}) +test("it should recognize an invalid snapshot", () => { + const { Box } = createTestFactories() + expect(Box.is({ width: "1", height: "2" })).toEqual(false) +}) +test("it should check valid nodes as well", () => { + const { Box } = createTestFactories() + const doc = Box.create() + expect(Box.is(doc)).toEqual(true) +}) +test("it should check invalid nodes as well", () => { + const { Box } = createTestFactories() + const doc = Box.create() + expect( + types + .model({ + anotherAttr: types.number + }) + .is(doc) + ).toEqual(false) +}) +test("it should do typescript type inference correctly", () => { + const A = types + .model({ + x: types.number, + y: types.maybeNull(types.string) + }) + .views((self) => ({ + get z(): string { + return "hi" + } + })) + .actions((self) => { + function method() { + const x: string = self.z + self.x + self.y + anotherMethod(x) + } + function anotherMethod(x: string) {} + return { + method, + anotherMethod + } + }) + // factory is invokable + const a = A.create({ x: 2, y: "7" }) + unprotect(a) + // property can be used as proper type + const z: number = a.x + // property can be assigned to crrectly + a.x = 7 + // wrong type cannot be assigned + // MANUAL TEST: not ok: a.x = "stuff" + // sub factories work + const B = types.model({ + sub: types.maybe(A) + }) + const b = B.create() + unprotect(b) + // sub fields can be reassigned + b.sub = A.create({ + // MANUAL TEST not ok: z: 4, + x: 3 + }) + // sub fields have proper type + b.sub.x = 4 + const d: string | null = b.sub.y + a.y = null + const zz: string = a.z + // Manual test not assignable: + // a.z = "test" + b.sub.method() + expect(true).toBe(true) // supress no asserts warning + // snapshots are of the proper type + const snapshot = getSnapshot(a) + const sx: number = snapshot.x + const sy: string | null = snapshot.y + expect(sx).toBe(7) + expect(sy).toBe(null) +}) +test("#66 - it should accept superfluous fields", () => { + const Item = types.model({ + id: types.number, + name: types.string + }) + expect(Item.is({})).toBe(false) + expect(Item.is({ id: 3 })).toBe(false) + expect(Item.is({ id: 3, name: "" })).toBe(true) + expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) + const a = Item.create({ id: 3, name: "", description: "bla" } as any) + expect((a as any).description).toBe(undefined) +}) +test("#66 - it should not require defaulted fields", () => { + const Item = types.model({ + id: types.number, + name: types.optional(types.string, "boo") + }) + expect(Item.is({})).toBe(false) + expect(Item.is({ id: 3 })).toBe(true) + expect(Item.is({ id: 3, name: "" })).toBe(true) + expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) + const a = Item.create({ id: 3, description: "bla" } as any) + expect((a as any).description).toBe(undefined) + expect(a.name).toBe("boo") +}) +test("#66 - it should be possible to omit defaulted fields", () => { + const Item = types.model({ + id: types.number, + name: "boo" + }) + expect(Item.is({})).toBe(false) + expect(Item.is({ id: 3 })).toBe(true) + expect(Item.is({ id: 3, name: "" })).toBe(true) + expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) + const a = Item.create({ id: 3, description: "bla" } as any) + expect((a as any).description).toBe(undefined) + expect(a.name).toBe("boo") +}) +test("#66 - it should pick the correct type of defaulted fields", () => { + const Item = types.model({ + id: types.number, + name: "boo" + }) + const a = Item.create({ id: 3 }) + unprotect(a) + expect(a.name).toBe("boo") + if (process.env.NODE_ENV !== "production") { + expect(() => ((a as any).name = 3)).toThrowError( + `[mobx-state-tree] Error while converting \`3\` to \`string\`:\n\n value \`3\` is not assignable to type: \`string\` (Value is not a string).` + ) + } +}) +test("cannot create factories with null values", () => { + expect(() => + types.model({ + x: null + } as any) + ).toThrow() +}) +test("can create factories with maybe primitives", () => { + const F = types.model({ + x: types.maybeNull(types.string) + }) + expect(F.is(undefined)).toBe(false) + expect(F.is({})).toBe(true) + expect(F.is({ x: null })).toBe(true) + expect(F.is({ x: "test" })).toBe(true) + expect(F.is({ x: 3 })).toBe(false) + expect(F.create().x).toBe(null) + expect(F.create({ x: undefined }).x).toBe(null) + expect(F.create({ x: "" }).x).toBe("") + expect(F.create({ x: "3" }).x).toBe("3") +}) +test("it is possible to refer to a type", () => { + const Todo = types + .model({ + title: types.string + }) + .actions((self) => { + function setTitle(v: string) {} + return { + setTitle + } + }) + function x(): typeof Todo.Type { + return Todo.create({ title: "test" }) + } + const z = x() + unprotect(z) + z.setTitle("bla") + z.title = "bla" + // z.title = 3 // Test manual: should give compile error + expect(true).toBe(true) // supress no asserts warning +}) +test(".Type should not be callable", () => { + const Todo = types + .model({ + title: types.string + }) + .actions((self) => { + function setTitle(v: string) {} + return { + setTitle + } + }) + expect(() => Todo.Type).toThrow() +}) +test(".SnapshotType should not be callable", () => { + const Todo = types + .model({ + title: types.string + }) + .actions((self) => { + function setTitle(v: string) {} + return { + setTitle + } + }) + expect(() => Todo.SnapshotType).toThrow() +}) +test("types instances with compatible snapshots should not be interchangeable", () => { + const A = types.model("A", {}).actions((self) => { + function doA() {} + return { + doA + } + }) + const B = types.model("B", {}).actions((self) => { + function doB() {} + return { + doB + } + }) + const C = types.model("C", { + x: types.maybe(A) + }) + expect(A.is({})).toBe(true) + expect(A.is(B.create())).toBe(false) // if thies yielded true, then `B.create().doA()` should work! + expect(A.is(getSnapshot(B.create()))).toBe(true) + const c = C.create() + unprotect(c) + expect(() => { + c.x = undefined + }).not.toThrow() + expect(() => { + c.x = cast({}) + }).not.toThrow() + expect(() => { + c.x = A.create() + }).not.toThrow() + expect(() => { + ;(c as any).x = B.create() + }).toThrow() +}) +test("it handles complex types correctly", () => { + const Todo = types + .model({ + title: types.string + }) + .actions((self) => { + function setTitle(v: string) {} + return { + setTitle + } + }) + const Store = types + .model({ + todos: types.map(Todo) + }) + .views((self) => { + function getActualAmount() { + return self.todos.size + } + return { + get amount() { + return getActualAmount() + }, + getAmount(): number { + return self.todos.size + getActualAmount() + } + } + }) + .actions((self) => { + function setAmount() { + const x: number = self.todos.size + self.amount + self.getAmount() + } + return { + setAmount + } + }) + expect(true).toBe(true) // supress no asserts warning +}) +if (process.env.NODE_ENV !== "production") { + test("it should provide detailed reasons why the value is not appicable", () => { + const Todo = types + .model({ + title: types.string + }) + .actions((self) => { + function setTitle(v: string) {} + return { + setTitle + } + }) + const Store = types + .model({ + todos: types.map(Todo) + }) + .views((self) => ({ + get amount() { + return self.todos.size + }, + getAmount(): number { + return self.todos.size + self.todos.size + } + })) + .actions((self) => { + function setAmount() { + const x: number = self.todos.size + self.amount + self.getAmount() + } + return { + setAmount + } + }) + expect(() => + Store.create({ + todos: { "1": { title: true, setTitle: "hello" } }, + amount: 1, + getAmount: "hello" + } as any) + ).toThrowError( + // MWE: TODO: Ideally (like in MST =< 0.9): + // at path "/todos/1/setTitle" value \`"hello"\` is not assignable (Action properties should not be provided in the snapshot). + // at path "/amount" value \`1\` is not assignable (Computed properties should not be provided in the snapshot). + // at path "/getAmount" value \`"hello"\` is not assignable (View properties should not be provided in the snapshot).` + `[mobx-state-tree] Error while converting \`{"todos":{"1":{"title":true,"setTitle":"hello"}},"amount":1,"getAmount":"hello"}\` to \`AnonymousModel\`: + + at path "/todos/1/title" value \`true\` is not assignable to type: \`string\` (Value is not a string).` + ) + }) +} +test("it should type compose correctly", () => { + const Car = types + .model({ + wheels: 3 + }) + .actions((self) => { + let connection = null as any as Promise + function drive() {} + function afterCreate() { + connection = Promise.resolve(true) + } + return { + drive, + afterCreate + } + }) + const Logger = types + .model({ + logNode: "test" + }) + .actions((self) => { + function log(msg: string) {} + return { + log + } + }) + const LoggableCar = types.compose(Car, Logger) + const x = LoggableCar.create({ wheels: 3, logNode: "test" /* compile error: x: 7 */ }) + // x.test() // compile error + x.drive() + x.log("z") +}) +test("it should extend {pre,post}ProcessSnapshot on compose", () => { + const CompositionTracker = types + .model({ + composedOf: types.array(types.string), + composedWith: types.array(types.string) + }) + .preProcessSnapshot((snapshot) => ({ + ...snapshot, + composedOf: (snapshot.composedOf || []).concat("CompositionTracker") + })) + .postProcessSnapshot((snapshot) => ({ + ...snapshot, + composedWith: (snapshot.composedWith || []).concat("WagonTracker") + })) + const Car = types + .model({}) + .preProcessSnapshot((snapshot) => ({ + ...snapshot, + composedOf: ((snapshot as any).composedOf || []).concat("Car") + })) + .postProcessSnapshot((snapshot) => ({ + ...snapshot, + composedWith: ((snapshot as any).composedWith || []).concat("Wagon") + })) + const Logger = types + .model({}) + .preProcessSnapshot((snapshot) => ({ + ...snapshot, + composedOf: ((snapshot as any).composedOf || []).concat("CarLogger") + })) + .postProcessSnapshot((snapshot) => ({ + ...snapshot, + composedWith: ((snapshot as any).composedWith || []).concat("WagonLogger") + })) + + const LoggableCar = types.compose(CompositionTracker, Car, Logger).props({ + composedOf: types.array(types.string), + composedWith: types.array(types.string) + }) + const x = LoggableCar.create({}) + expect(x.composedOf).toContain("CompositionTracker") + expect(x.composedOf).toContain("Car") + expect(x.composedOf).toContain("CarLogger") + expect(x.composedOf).toEqual(["CompositionTracker", "Car", "CarLogger"]) + expect(getSnapshot(x).composedWith).toContain("WagonTracker") + expect(getSnapshot(x).composedWith).toContain("Wagon") + expect(getSnapshot(x).composedWith).toContain("WagonLogger") + expect(getSnapshot(x).composedWith).toEqual(["WagonTracker", "Wagon", "WagonLogger"]) +}) +test("it should extend types correctly", () => { + const Car = types + .model({ + wheels: 3 + }) + .actions((self) => { + function drive() {} + return { + drive + } + }) + const Logger = types + .model("Logger") + .props({ + logNode: "test" + }) + .actions((self) => { + let connection: Promise + return { + log(msg: string) {}, + afterCreate() { + connection = Promise.resolve(true) + } + } + }) + const LoggableCar = types.compose("LoggableCar", Car, Logger) + const x = LoggableCar.create({ wheels: 3, logNode: "test" /* compile error: x: 7 */ }) + // x.test() // compile error + x.drive() + x.log("z") +}) +test("self referring views", () => { + const Car = types.model({ x: 3 }).views((self) => { + const views = { + get tripple() { + return self.x + views.double + }, + get double() { + return self.x * 2 + } + } + return views + }) + expect(Car.create().tripple).toBe(9) +}) + +test("#922", () => { + expect(() => { + const Stateable = types.model("Statable", { + state: types.optional( + types.enumeration("state", ["initalized", "pending", "done", "error"]), + "initalized" + ) + }) + + const Client = types.model("Client", { + id: types.identifierNumber, + name: types.string + }) + + const UserClientList = types.compose( + "UserClientList", + Stateable, + types.model({ + items: types.array(Client), + month: types.optional(types.Date, () => { + return new Date() + }) + }) + ) + + const NonExtendedUserClientList = types.model("NonExtendedUserClientList", { + items: types.array(Client), + month: types.optional(types.Date, () => { + return new Date() + }), + state: types.optional( + types.enumeration("state", ["initalized", "pending", "done", "error"]), + "initalized" + ) + }) + + const User = types.model("User", { + name: types.string, + clients: types.optional(UserClientList, () => UserClientList.create({})) + }) + + const NonExtendedUser = types.model("User", { + name: types.string, + clients: types.optional(NonExtendedUserClientList, () => NonExtendedUserClientList.create({})) + }) + + const you = NonExtendedUser.create({ + name: "you" + }) + + const me = User.create({ + name: "me" + }) + }).not.toThrow() +}) + +test("#922 - 2", () => { + expect(() => { + types.optional(types.enumeration("state", ["init", "pending", "done", "error"]), "init") + }).not.toThrow() +}) + +test("#932", () => { + interface MyInterface { + test: string + } + + const MyModel = types.model("MyModel", { + myField: types.array(types.frozen()) + }) + + const x = MyModel.create({ myField: [{ test: "stuff" }] }) + const a: string = x.myField[0].test +}) + +test("932 - 2", () => { + type MyType = string + const ModelA = types.model("ModelA", { + myField: types.maybe(types.frozen()) + }) + const x = ModelA.create({}) + const y = x.myField // y is string | undefined + + const ModelA2 = types.model("ModelA", { + myField: types.frozen() + }) + const x2 = ModelA2.create({ + myField: "test" // mandatory + }) + const y2: string = x2.myField // string only +}) + +test("#923", () => { + const Foo = types.model("Foo", { + name: types.optional(types.string, "") + }) + + const Bar = types.model("Bar", { + foos: types.optional(types.array(Foo), []) + }) + + types.optional(types.map(Bar), {}) // Should have no compile error! +}) + +test("snapshot type of reference must be string | number", () => { + const M = types.model({ id: types.identifier, a: "bar" }) + const R = types.reference(M) + + const S = types.model({ realM: M, refM: R }) + const s = S.create({ + realM: { id: "5" }, + refM: "5" + }) + const sn: string | number = getSnapshot(s.refM) +}) + +test("#951", () => { + const C = types.model({ a: 123 }) + + // model as root + const ModelWithC = types.model({ c: C }) + const modelInstance = ModelWithC.create({ c: C.create() }) + + // getRoot + const modelRoot1 = getRoot(modelInstance.c) + const modelCR1: Instance = modelRoot1.c + const modelRoot2 = getRoot>(modelInstance.c) + const modelCR2: Instance = modelRoot2.c + + // getParent + const modelParent1 = getParent(modelInstance.c) + const modelCP1: Instance = modelParent1 + const modelParent2 = getParent>(modelInstance.c) + const modelCP2: Instance = modelParent2 + + // array as root + const ArrayOfC = types.array(C) + const arrayInstance = ArrayOfC.create([C.create()]) + + // getRoot + const arrayRoot1 = getRoot(arrayInstance[0]) + const arrayCR1: Instance = arrayRoot1[0] + + // getParent + const arrayParent1 = getParent(arrayInstance[0]) + const arrayCP1: Instance = arrayParent1 + + // map as root + const MapOfC = types.map(C) + const mapInstance = MapOfC.create({ a: C.create() }) + + // getRoot + const mapRoot1 = getRoot(mapInstance.get("a")!) + const mapC1: Instance = mapRoot1.get("a")! + + // getParent + const mapParent1 = getRoot(mapInstance.get("a")!) + const mapCP1: Instance = mapParent1 +}) + +test("cast and SnapshotOrInstance", () => { + const NumberArray = types.array(types.number) + const NumberMap = types.map(types.number) + const A = types + .model({ n: 123, n2: types.number, arr: NumberArray, map: NumberMap }) + .actions((self) => ({ + // for primitives (although not needed) + setN(nn: SnapshotOrInstance) { + self.n = cast(nn) + }, + setN2(nn: SnapshotOrInstance) { + self.n = cast(nn) + }, + setN3(nn: SnapshotOrInstance) { + self.n = cast(nn) + }, + setN4(nn: number) { + self.n = cast(nn) + }, + setN5() { + self.n = cast(5) + }, + + // for arrays + setArr(nn: SnapshotOrInstance) { + self.arr = cast(nn) + }, + setArr2(nn: SnapshotOrInstance) { + self.arr = cast(nn) + }, + setArr3(nn: SnapshotIn) { + self.arr = cast(nn) + }, + setArr31(nn: number[]) { + self.arr = cast(nn) + }, + setArr4() { + // it works even without specifying the target type, magic! + self.arr = cast([2, 3, 4]) + self.arr = cast(NumberArray.create([2, 3, 4])) + }, + + // for maps + setMap(nn: SnapshotOrInstance) { + self.map = cast(nn) + }, + setMap2(nn: SnapshotOrInstance) { + self.map = cast(nn) + }, + setMap3(nn: SnapshotIn) { + self.map = cast(nn) + }, + setMap31(nn: { [k: string]: number }) { + self.map = cast(nn) + }, + setMap4() { + // it works even without specifying the target type, magic! + self.map = cast({ a: 2, b: 3 }) + self.map = cast(NumberMap.create({ a: 2, b: 3 })) + } + })) + + const C = types + .model({ a: A, maybeA: types.maybe(A), maybeNullA: types.maybeNull(A) }) + .actions((self) => ({ + // for submodels, using typeof self.var + setA(na: SnapshotOrInstance) { + self.a = cast(na) + // we just want to check it compiles + if (0 !== 0) { + self.maybeA = cast(na) + self.maybeNullA = cast(na) + } + }, + // for submodels, using the type directly + setA2(na: SnapshotOrInstance) { + self.a = cast(na) + // we just want to check it compiles + if (0 !== 0) { + self.maybeA = cast(na) + self.maybeNullA = cast(na) + } + }, + setA3(na: SnapshotIn) { + self.a = cast(na) + // we just want to check it compiles + if (0 !== 0) { + self.maybeA = cast(na) + self.maybeNullA = cast(na) + } + }, + setA4(na: Instance) { + self.a = cast(na) + // we just want to check it compiles + if (0 !== 0) { + self.maybeA = cast(na) + self.maybeNullA = cast(na) + } + }, + setA5() { + // it works even without specifying the target type, magic! + self.a = cast({ n2: 5 }) + self.a = cast(A.create({ n2: 5 })) + // we just want to check it compiles + if (0 !== 0) { + self.maybeA = cast({ n2: 5 }) + self.maybeA = cast(A.create({ n2: 5 })) + self.maybeNullA = cast({ n2: 5 }) + self.maybeNullA = cast(A.create({ n2: 5 })) + } + } + })) + + const c = C.create({ a: { n2: 5 } }) + unprotect(c) + // all below works + c.setA({ n2: 5 }) + c.setA(A.create({ n2: 5 })) + c.setA2({ n2: 5 }) + c.setA2(A.create({ n2: 5 })) + c.setA3({ n2: 5 }) + // c.setA3(A.create({ n2: 5 })) // this one doesn't work (as expected, it wants the creation type) + // c.setA4({n2: 5}) // this one doesn't work (as expected, it wants the instance type) + c.setA4(A.create({ n2: 5 })) + c.setA5() + + c.a.setN(1) + c.a.setN2(1) + c.a.setN3(1) + c.a.setN4(1) + c.a.setN5() + + c.a.setArr([]) + c.a.setArr(NumberArray.create([])) + c.a.setArr2([]) + c.a.setArr2(NumberArray.create([])) + c.a.setArr3([]) + c.a.setArr3(NumberArray.create([])) + c.a.setArr4() + + c.a.setMap({ a: 2, b: 3 }) + c.a.setMap(NumberMap.create({ a: 2, b: 3 })) + c.a.setMap2({ a: 2, b: 3 }) + c.a.setMap2(NumberMap.create({ a: 2, b: 3 })) + c.a.setMap3({ a: 2, b: 3 }) + // c.a.setMap3(NumberMap.create({ a: 2, b: 3 })) // doesn't work (as expected, wants a plain object) + c.a.setMap4() + + const arr = types.array(A).create() + unprotect(arr) + arr[0] = cast({ n2: 5 }) + + const map = types.map(A).create() + unprotect(map) + map.set("a", cast({ n2: 5 })) // not really needed in this case, but whatever :) + + // this does not compile, yay! + /* + cast([]) + cast({ a: 5 }) + cast(NumberArray.create([])) + cast(A.create({ n2: 5 })) + cast({ a: 2, b: 5 }) + cast(NumberMap.create({ a: 2, b: 3 })) + */ +}) + +test("#994", () => { + const Cinema = types.model("Cinema", { + id: types.identifier, + name: types.maybe(types.string) + }) + + const ref = types.reference(Cinema) // should compile ok on TS3 +}) + +test("castToSnapshot", () => { + const firstModel = types.model({ brew1: types.map(types.number) }) + const secondModel = types.model({ brew2: types.map(firstModel) }).actions((self) => ({ do() {} })) + const appMod = types.model({ aaa: secondModel }) + + const storeSnapshot: SnapshotIn = { + brew2: { outside: { brew1: { inner: 222 } } } + } + const storeInstance = secondModel.create(storeSnapshot) + const storeSnapshotOrInstance1: SnapshotOrInstance = + secondModel.create(storeSnapshot) + const storeSnapshotOrInstance2: SnapshotOrInstance = storeSnapshot + + appMod.create({ aaa: castToSnapshot(storeInstance) }) + appMod.create({ aaa: castToSnapshot(storeSnapshot) }) + appMod.create({ aaa: castToSnapshot(storeSnapshotOrInstance1) }) + appMod.create({ aaa: castToSnapshot(storeSnapshotOrInstance2) }) + // appMod.create({ aaa: castToSnapshot(5) }) // should not compile +}) + +// disabled due to TS3.4 nesting issue +test.skip("create correctly chooses if the snapshot is needed or not - #920", () => { + const X = types.model({ + test: types.string + }) + const T = types.model({ + test: types.refinement(X, (s) => s.test.length > 5) + }) + // T.create() // manual test: expects compilation error + // T.create({}) // manual test: expects compilation error + T.create({ + test: { test: "hellothere" } + }) + + const T2 = types.model({ + test: types.maybe(X) + }) + T2.create() // ok + T2.create({}) // ok + + const A = types.model({ + test: "bla" + }) + A.create() // ok + A.create({}) // ok + + const B = types.array(types.string) + B.create() // ok + B.create(["hi"]) // ok + + const C = types.map(types.string) + C.create() // ok + C.create({ hi: "hi" }) // ok + + const D = types.number + // D.create() // manual test: expects compilation error + D.create(5) // ok + + const E = types.optional(types.number, 5) + E.create() // ok + E.create(6) // ok + + const F = types.frozen() + // F.create() // manual test: compilation error + F.create(6) // ok + + const FF = types.frozen() + FF.create() // ok + FF.create(undefined) // ok + + const G = types.frozen(5) + G.create() // ok + G.create(6) // ok + + const H = types.frozen(5) + H.create() // ok + H.create(6) // ok + + const I = types.optional(types.frozen(), 6) + I.create() + I.create(7) +}) + +test("#1117", () => { + const Failsafe = ( + t: IType, + handleProblem: (value: C, validationError: ReturnType["validate"]>) => void = ( + value, + error + ) => { + console.error("Skipping value: typecheck error on", value) + console.error(error) + } + ) => + types.custom({ + name: `Failsafe<${t.name}>`, + fromSnapshot(snapshot: C) { + try { + return t.create(snapshot) // this should compile + } catch (e) { + handleProblem(snapshot, e as any) + return null + } + }, + toSnapshot(x) { + if (isStateTreeNode(x)) return getSnapshot(x) + return x as any as C + }, + isTargetType(v): v is T | null { + if (isFrozenType(t)) { + return t.is(v) + } + return false + }, + getValidationMessage() { + return "" + } + }) +}) + +test("MST array type should be assignable to plain array type", () => { + { + const Todo = types + .model({ + done: false, + name: types.string + }) + .actions((self) => ({ + toggleDone() { + self.done = !self.done + } + })) + const TodoArray = types.array(Todo) + + const todoArray = TodoArray.create([{ done: true, name: "todo1" }, { name: "todo2" }]) + unprotect(todoArray) + const otherTodoArray: Array> = todoArray + otherTodoArray.push(cast({ done: false, name: "todo2" })) + } + + { + const T = types.model({ + a: types.optional(types.array(types.number), []) + }) + + const arr: Array = T.create().a + } + + { + const T = types.model({ + a: types.optional(types.array(types.number), [], [5]) + }) + + const arr: Array = T.create({ + a: 5 + }).a + } +}) + +test("can get snapshot from submodel (submodel is IStateNodeTree", () => { + const T = types.model({ + a: types.model({ x: 5 }) + }) + const t = T.create({ a: {} }) + const sn = getSnapshot(t.a).x +}) + +test("can extract type from complex objects", () => { + const T = types.maybe( + types.model({ + a: types.model({ + x: 5 + }) + }) + ) + const t = T.create({ + a: {} + })! + + type OriginalType = TypeOfValue + const T2: OriginalType = T +}) + +test("#1268", () => { + const Book = types.model({ + id: types.identifier + }) + + const BooksStore = types.model({ + books: types.array(types.reference(Book)) + }) + + const RootStore = types.model({ + booksStore: BooksStore + }) + + const booksStore = BooksStore.create({ books: [] }) + + const rootStore = RootStore.create({ booksStore: castToSnapshot(booksStore) }) +}) + +test("#1307 optional can be omitted in .create", () => { + const Model1 = types.model({ name: types.optional(types.string, "") }) + const model1 = Model1.create({}) + assert(model1.name, _ as string) + + const Model2 = types.model({ name: "" }) + const model2 = Model2.create({}) + assert(model2.name, _ as string) +}) + +test("#1307 custom types failing", () => { + const createCustomType = ({ + CustomType + }: { + CustomType: ICustomType + }) => { + return types + .model("Example", { + someProp: types.boolean, + someType: CustomType + }) + .views((self) => ({ + get isSomePropTrue(): boolean { + return self.someProp + } + })) + } +}) + +test("#1343", () => { + function createTypeA(t: T) { + return types.model("TypeA", t).views((self) => ({ + get someView() { + return null + } + })) + } + + function createTypeB(t: T) { + return types + .model("TypeB", { + a: createTypeA(t) + }) + .views((self) => ({ + get someViewFromA() { + return self.a.someView + } + })) + } +}) + +test("#1330", () => { + const ChildStore = types + .model("ChildStore", { + foo: types.string, + bar: types.boolean + }) + .views((self) => ({ + get root(): IRootStore { + return getRoot(self) + } + })) + .actions((self) => ({ + test() { + const { childStore } = self.root + // childStore and childStore.foo is properly inferred in TS 3.4 but not in 3.5 + console.log(childStore.foo) + } + })) + + interface IRootStore extends Instance {} + + const RootStore = types.model("RootStore", { + childStore: ChildStore, + test: "" + }) + + assert( + RootStore.create({ + childStore: { + foo: "a", + bar: true + } + }).childStore.root.test, + _ as string + ) +}) + +test("maybe / optional type inference verification", () => { + const T = types.model({ + a: types.string, + b: "test", + c: types.maybe(types.string), + d: types.maybeNull(types.string), + e: types.optional(types.string, "test") + }) + + interface ITC extends SnapshotIn {} + interface ITS extends SnapshotOut {} + + assert( + _ as ITC, + _ as { + [$nonEmptyObject]?: any + a: string + b?: string + c?: string | undefined + d?: string | null + e?: string + } + ) + + assert( + _ as ITS, + _ as { + [$nonEmptyObject]?: any + a: string + b: string + c: string | undefined + d: string | null + e: string + } + ) +}) diff --git a/__tests__/core/union.test.ts b/__tests__/core/union.test.ts new file mode 100644 index 000000000..9b2fcfdc0 --- /dev/null +++ b/__tests__/core/union.test.ts @@ -0,0 +1,306 @@ +import { configure } from "mobx" +import { + types, + hasParent, + tryResolve, + getSnapshot, + applySnapshot, + getType, + setLivelinessChecking, + SnapshotIn, + Instance +} from "../../src" + +const createTestFactories = () => { + const Box = types.model("Box", { + width: types.number, + height: types.number + }) + const Square = types.model("Square", { + width: types.number + }) + const Cube = types.model("Cube", { + width: types.number, + height: types.number, + depth: types.number + }) + const Plane = types.union(Square, Box) + const Heighed = types.union(Box, Cube) + const DispatchPlane = types.union( + { dispatcher: (snapshot) => (snapshot && "height" in snapshot ? Box : Square) }, + Box, + Square + ) + const Block = types.model("Block", { + list: types.array(Heighed) + }) + return { Box, Square, Cube, Plane, DispatchPlane, Heighed, Block } +} +const createLiteralTestFactories = () => { + const Man = types.model("Man", { type: types.literal("M") }) + const Woman = types.model("Woman", { type: types.literal("W") }) + const All = types.model("All", { type: types.string }) + const ManWomanOrAll = types.union(Man, Woman, All) + return { Man, Woman, All, ManWomanOrAll } +} +if (process.env.NODE_ENV !== "production") { + test("it should complain about multiple applicable types no dispatch method", () => { + const { Box, Square } = createTestFactories() + const PlaneNotEager = types.union({ eager: false }, Square, Box) + expect(() => { + PlaneNotEager.create({ width: 2, height: 2 }) + }).toThrow(/Error while converting/) + }) +} +test("it should have parent whenever creating or applying from a complex data structure to a model which has Union typed children", () => { + const { Block, Heighed } = createTestFactories() + const block = Block.create({ + list: [{ width: 2, height: 2 }] + }) + const child = tryResolve(block, "./list/0") + expect(hasParent(child)).toBe(true) +}) +if (process.env.NODE_ENV !== "production") { + test("it should complain about no applicable types", () => { + const { Heighed } = createTestFactories() + expect(() => { + Heighed.create({ height: 2 } as any) + }).toThrow(/Error while converting/) + }) +} +test("it should be smart enough to discriminate by keys", () => { + const { Box, Plane, Square } = createTestFactories() + const doc = types.union(Square, Box).create({ width: 2 }) + expect(Box.is(doc)).toEqual(false) + expect(Square.is(doc)).toEqual(true) +}) +test("it should discriminate by value type", () => { + const Size = types.model("Size", { + width: 0, + height: 0 + }) + const Picture = types.model("Picture", { + url: "", + size: Size + }) + const Square = types.model("Square", { + size: 0 + }) + const PictureOrSquare = types.union(Picture, Square) + const doc = PictureOrSquare.create({ size: { width: 0, height: 0 } }) + expect(Picture.is(doc)).toEqual(true) + expect(Square.is(doc)).toEqual(false) +}) +test("it should compute exact union types", () => { + const { Box, Plane, Square } = createTestFactories() + expect(Plane.is(Box.create({ width: 3, height: 2 }))).toEqual(true) + expect(Plane.is(Square.create({ width: 3 }))).toEqual(true) +}) +test("it should compute exact union types - 2", () => { + const { Box, DispatchPlane, Square } = createTestFactories() + expect(DispatchPlane.is(Box.create({ width: 3, height: 2 }))).toEqual(true) + expect( + DispatchPlane.is( + Square.create({ width: 3, height: 2 } as any /* incorrect type, superfluous attr!*/) + ) + ).toEqual(true) +}) +test("it should use dispatch to discriminate", () => { + const { Box, DispatchPlane, Square } = createTestFactories() + const a = DispatchPlane.create({ width: 3 }) + expect(getSnapshot(a)).toEqual({ width: 3 }) +}) + +test("it should eagerly match by ambiguos value", () => { + const { ManWomanOrAll, All, Man } = createLiteralTestFactories() + const person = ManWomanOrAll.create({ type: "Z" }) + expect(All.is(person)).toEqual(true) + expect(Man.is(person)).toEqual(false) +}) + +test("it should eagerly match by ambiguos value - 2", () => { + const { All, Man } = createLiteralTestFactories() + const person = types.union(All, Man).create({ type: "M" }) + expect(All.is(person)).toEqual(true) + expect(Man.is(person)).toEqual(false) // not matched, All grabbed everything! +}) + +test("it should eagerly match by value literal", () => { + const { ManWomanOrAll, All, Man } = createLiteralTestFactories() + const person = ManWomanOrAll.create({ type: "M" }) + expect(All.is(person)).toEqual(false) + expect(Man.is(person)).toEqual(true) +}) + +test("dispatch", () => { + const Odd = types + .model({ + value: types.number + }) + .actions((self) => ({ + isOdd() { + return true + }, + isEven() { + return false + } + })) + const Even = types.model({ value: types.number }).actions((self) => ({ + isOdd() { + return false + }, + isEven() { + return true + } + })) + const Num = types.union( + { dispatcher: (snapshot) => (snapshot.value % 2 === 0 ? Even : Odd) }, + Even, + Odd + ) + expect(Num.create({ value: 3 }).isOdd()).toBe(true) + expect(Num.create({ value: 3 }).isEven()).toBe(false) + expect(Num.create({ value: 4 }).isOdd()).toBe(false) + expect(Num.create({ value: 4 }).isEven()).toBe(true) + if (process.env.NODE_ENV !== "production") { + expect(() => { + types.union( + ((snapshot: any) => (snapshot.value % 2 === 0 ? Even : Odd)) as any, // { dispatcher: snapshot => (snapshot.value % 2 === 0 ? Even : Odd) }, + Even, + Odd + ) + }).toThrow("expected object") + } +}) + +test("961 - apply snapshot to union should not throw when union keeps models with different properties and snapshot is got by getSnapshot", () => { + const Foo = types.model({ foo: 1 }) + const Bar = types.model({ bar: 1 }) + const U = types.union(Foo, Bar) + + const u = U.create({ foo: 1 }) + applySnapshot(u, getSnapshot(Bar.create())) +}) + +describe("1045 - secondary union types with applySnapshot and ids", () => { + function initTest( + useSnapshot: boolean, + useCreate: boolean, + submodel1First: boolean, + type: number + ) { + setLivelinessChecking("error") + + const Submodel1NoSP = types.model("Submodel1", { + id: types.identifier, + extraField1: types.string, + extraField2: types.maybe(types.string) + }) + + const Submodel1SP = types.snapshotProcessor(Submodel1NoSP, { + preProcessor(sn: SnapshotIn>) { + const { id, extraField1, extraField2 } = sn + return { + id, + extraField1: extraField1.toUpperCase(), + extraField2: extraField2?.toUpperCase() + } + } + }) + + const Submodel2NoSP = types.model("Submodel2", { + id: types.identifier, + extraField1: types.maybe(types.string), + extraField2: types.string + }) + + const Submodel2SP = types.snapshotProcessor(Submodel2NoSP, { + preProcessor(sn: SnapshotIn>) { + const { id, extraField1, extraField2 } = sn + return { + id, + extraField1: extraField1?.toUpperCase(), + extraField2: extraField2.toUpperCase() + } + } + }) + + const Submodel1 = useSnapshot ? Submodel1SP : Submodel1NoSP + const Submodel2 = useSnapshot ? Submodel2SP : Submodel2NoSP + + const Submodel = submodel1First + ? types.union(Submodel1, Submodel2) + : types.union(Submodel2, Submodel1) + + const Model = types.array(Submodel) + + const store = Model.create([{ id: "id1", extraField1: "extraField1" }]) + + return { + store, + applySn: function () { + const sn1 = { + id: "id1", + extraField1: "new extraField1", + extraField2: "some value" + } + const sn2 = { + id: "id1", + extraField1: undefined, + extraField2: "some value" + } + const sn = type === 1 ? sn1 : sn2 + const submodel = type === 1 ? Submodel1 : Submodel2 + const expected = useSnapshot + ? { + id: sn.id, + extraField1: sn.extraField1?.toUpperCase(), + extraField2: sn.extraField2?.toUpperCase() + } + : sn + + applySnapshot(store, [useCreate ? (submodel as any).create(sn) : sn]) + + expect(store.length).toBe(1) + expect(store[0]).toEqual(expected) + expect(getType(store[0])).toBe(useSnapshot ? submodel.getSubTypes() : submodel) + } + } + } + + for (const useSnapshot of [false, true]) { + describe(useSnapshot ? "with snapshotProcessor" : "without snapshotProcessor", () => { + for (const submodel1First of [true, false]) { + describe(submodel1First ? "submodel1 first" : "submodel2 first", () => { + for (const useCreate of [false, true]) { + describe(useCreate ? "using create" : "not using create", () => { + for (const type of [2, 1]) { + describe(`snapshot is of type Submodel${type}`, () => { + it(`apply snapshot works when the node is not touched`, () => { + configure({ + useProxies: "never" + }) + + const t = initTest(useSnapshot, useCreate, submodel1First, type) + t.applySn() + }) + + it(`apply snapshot works when the node is touched`, () => { + configure({ + useProxies: "never" + }) + + const t = initTest(useSnapshot, useCreate, submodel1First, type) + // tslint:disable-next-line:no-unused-expression + t.store[0] + t.applySn() + }) + }) + } + }) + } + }) + } + }) + } +}) diff --git a/__tests__/core/volatile.test.ts b/__tests__/core/volatile.test.ts new file mode 100644 index 000000000..347105d0c --- /dev/null +++ b/__tests__/core/volatile.test.ts @@ -0,0 +1,175 @@ +import { types, getSnapshot, recordPatches, unprotect } from "../../src" +import { reaction, isObservableProp, isObservable, autorun, observable } from "mobx" + +const Todo = types + .model({ + done: false + }) + .volatile((self) => ({ + state: Promise.resolve(1) + })) + .actions((self) => ({ + toggle() { + self.done = !self.done + }, + reload() { + self.state = Promise.resolve(2) + } + })) + +test("Properties should be readable and writable", () => { + const i = Todo.create() + expect(i.state instanceof Promise).toBe(true) + i.reload() + expect(i.state instanceof Promise).toBe(true) +}) + +test("VS should not show up in snapshots", () => { + expect(getSnapshot(Todo.create())).toEqual({ done: false }) +}) + +test("VS should not show up in patches", () => { + const i = Todo.create() + const r = recordPatches(i) + i.reload() + i.toggle() + r.stop() + expect(r.patches).toEqual([{ op: "replace", path: "/done", value: true }]) +}) + +test("VS be observable", () => { + const promises: Promise[] = [] + const i = Todo.create() + const d = reaction( + () => i.state, + (p) => promises.push(p) + ) + i.reload() + i.reload() + expect(promises.length).toBe(2) + d() +}) + +test("VS should not be deeply observable", () => { + const i = types + .model({}) + .volatile((self) => ({ + x: { a: 1 } + })) + .create() + unprotect(i) + expect(isObservableProp(i, "x")).toBe(true) + expect(isObservable(i.x)).toBe(false) + expect(isObservableProp(i.x, "a")).toBe(false) + i.x = { a: 2 } + expect(isObservableProp(i, "x")).toBe(true) + expect(isObservable(i.x)).toBe(false) + expect(isObservableProp(i.x, "a")).toBe(false) +}) + +test("VS should not be strongly typed observable", () => { + const i = Todo.create() + // TEST: type error i.state = 7 + i.state.then(() => {}) // it's a promise + // TEST: not available on snapshot: getSnapshot(i).state + expect(true).toBe(true) +}) + +test("VS should not be modifiable without action", () => { + const i = Todo.create() + expect(() => { + i.state = Promise.resolve(4) + }).toThrowError(/the object is protected and can only be modified by using an action/) +}) + +test("VS should expect a function as an argument", () => { + expect(() => { + const t = types + .model({}) + // @ts-ignore + .volatile({ state: 1 }) + .create() + }).toThrowError( + `You passed an object to volatile state as an argument, when function is expected` + ) +}) + +test("VS should not be modifiable when unprotected", () => { + const i = Todo.create() + unprotect(i) + const p = Promise.resolve(7) + expect(() => { + i.state = p + }).not.toThrow() + expect(i.state === p).toBe(true) +}) + +test("VS sample from the docs should work (1)", () => { + const T = types.model({}).extend((self) => { + const localState = observable.box(3) + + return { + views: { + get x() { + return localState.get() + } + }, + actions: { + setX(value: number) { + localState.set(value) + } + } + } + }) + + const t = T.create() + expect(t.x).toBe(3) + t.setX(5) + expect(t.x).toBe(5) + + // now observe it + const observed: number[] = [] + const dispose = autorun(() => { + observed.push(t.x) + }) + + t.setX(7) + expect(t.x).toBe(7) + expect(observed).toEqual([5, 7]) + dispose() +}) + +test("VS sample from the docs should work (2)", () => { + const T = types.model({}).extend((self) => { + let localState = 3 + + return { + views: { + getX() { + return localState + } + }, + actions: { + setX(value: number) { + localState = value + } + } + } + }) + + const t = T.create() + expect(t.getX()).toBe(3) + t.setX(5) + expect(t.getX()).toBe(5) + + // now observe it (should not be observable) + const observed: number[] = [] + const dispose = autorun(() => { + observed.push(t.getX()) + }) + + t.setX(7) + expect(t.getX()).toBe(7) + expect(observed).toEqual([5]) + dispose() +}) diff --git a/__tests__/perf/fixture-data.test.ts b/__tests__/perf/fixture-data.test.ts new file mode 100644 index 000000000..8b8add97b --- /dev/null +++ b/__tests__/perf/fixture-data.test.ts @@ -0,0 +1,40 @@ +import { rando, createHeros, createMonsters, createTreasure } from "./fixtures/fixture-data" +import { Hero, Monster, Treasure } from "./fixtures/fixture-models" + +test("createHeros", () => { + const data = createHeros(10) + expect(data.length).toBe(10) + const hero = Hero.create(data[0]) + expect(hero.descriptionLength > 1).toBe(true) +}) +test("createMonsters", () => { + const data = createMonsters(10, 10, 10) + expect(data.length).toBe(10) + expect(data[1].treasures.length).toBe(10) + expect(data[0].eatenHeroes.length).toBe(10) + const monster = Monster.create(data[0]) + expect(monster.eatenHeroes && monster.eatenHeroes.length === 10).toBe(true) + expect(monster.treasures.length === 10).toBe(true) +}) +test("createTreasure", () => { + const data = createTreasure(10) + expect(data.length).toBe(10) + const treasure = Treasure.create(data[1]) + expect(treasure.gold > 0).toBe(true) +}) +test("rando sorting", () => { + // i'm going straight to hell for this test... must get coverage to 100%.... no matter the cost. + let foundTrue = false + let foundFalse = false + let result + do { + result = rando() + if (result) { + foundTrue = true + } else { + foundFalse = true + } + } while (!foundTrue || !foundFalse) + expect(foundTrue).toBe(true) + expect(foundFalse).toBe(true) +}) diff --git a/__tests__/perf/fixture-models.test.ts b/__tests__/perf/fixture-models.test.ts new file mode 100644 index 000000000..c6b88fa57 --- /dev/null +++ b/__tests__/perf/fixture-models.test.ts @@ -0,0 +1,52 @@ +import { Hero, Monster, Treasure } from "./fixtures/fixture-models" +const mst = require("../../dist/mobx-state-tree.umd") +const { unprotect } = mst + +const SAMPLE_HERO = { + id: 1, + name: "jimmy", + level: 1, + role: "cleric", + description: "hi" +} +test("Hero computed fields", () => { + const hero = Hero.create(SAMPLE_HERO) + expect(hero.descriptionLength).toBe(2) +}) +test("Tresure", () => { + const treasure = Treasure.create({ gold: 1, trapped: true }) + expect(treasure.trapped).toBe(true) + expect(treasure.gold).toBe(1) +}) +test("Monster computed fields", () => { + const monster = Monster.create({ + id: "foo", + level: 1, + maxHp: 3, + hp: 1, + warning: "boo!", + createdAt: new Date(), + treasures: [ + { gold: 2, trapped: true }, + { gold: 3, trapped: true } + ], + eatenHeroes: [SAMPLE_HERO], + hasFangs: true, + hasClaws: true, + hasWings: true, + hasGrowl: true, + freestyle: null + }) + expect(monster.isAlive).toBe(true) + expect(monster.isFlashingRed).toBe(true) + unprotect(monster) + expect(monster.weight).toBe(2) + monster.level = 0 + monster.hasFangs = false + monster.hasWings = false + monster.eatenHeroes = null + expect(monster.weight).toBe(1) + monster.hp = 0 + expect(monster.isFlashingRed).toBe(false) + expect(monster.isAlive).toBe(false) +}) diff --git a/__tests__/perf/fixtures/fixture-data.ts b/__tests__/perf/fixtures/fixture-data.ts new file mode 100644 index 000000000..820d2a77e --- /dev/null +++ b/__tests__/perf/fixtures/fixture-data.ts @@ -0,0 +1,99 @@ +import { HeroRoles } from "./fixture-models" + +/** + * Creates data containing very few fields. + * + * @param count The number of items to create. + */ +export function createTreasure(count: number) { + const data = [] + let i = 0 + do { + data.push({ + trapped: i % 2 === 0, + gold: ((count % 10) + 1) * 10 + }) + i++ + } while (i < count) + return data +} + +// why yes i DID graduate high school, why do you ask? +export const rando = () => (Math.random() > 0.5 ? 1 : 0) + +const titles = ["Sir", "Lady", "Baron von", "Baroness", "Captain", "Dread", "Fancy"].sort(rando) +const givenNames = ["Abe", "Beth", "Chuck", "Dora", "Ernie", "Fran", "Gary", "Haily"].sort(rando) +const epicNames = ["Amazing", "Brauny", "Chafed", "Dapper", "Egomaniac", "Foul"].sort(rando) +const wtf = `Daenerys Stormborn of the House Targaryen, First of Her Name, the Unburnt, + Queen of the Andals and the First Men, Khaleesi of the Great Grass Sea, Breaker of Chains, + and Mother of Dragons. ` +/** + * Creates data with a medium number of fields and data. + * + * @param count The number of items to create. + */ +export function createHeros(count: number) { + const data = [] + let i = 0 + let even = true + let n1 + let n2 + let n3 + do { + n1 = titles[i % titles.length] + n2 = givenNames[i % givenNames.length] + n3 = epicNames[i % epicNames.length] + data.push({ + id: i, + name: `${n1} ${n2} the ${n3}`, + level: (count % 100) + 1, + role: HeroRoles[i % HeroRoles.length], + description: `${wtf} ${wtf} ${wtf}` + }) + even = !even + i++ + } while (i < count) + return data +} + +/** + * Creates data with a large number of fields and data. + * + * @param count The number of items to create. + * @param treasureCount The number of small children to create. + * @param heroCount The number of medium children to create. + */ +export function createMonsters(count: number, treasureCount: number, heroCount: number) { + const data = [] + let i = 0 + let even = true + do { + const treasures = createTreasure(treasureCount) + const eatenHeroes = createHeros(heroCount) + data.push({ + id: `omg-${i}-run!`, + freestyle: `${wtf} ${wtf} ${wtf}${wtf} ${wtf} ${wtf}`, + level: (count % 100) + 1, + hp: i % 2 === 0 ? 1 : 5 * i, + maxHp: 5 * i, + warning: "!!!!!!", + createdAt: new Date(), + hasFangs: even, + hasClaws: even, + hasWings: !even, + hasGrowl: !even, + fearsFire: even, + fearsWater: !even, + fearsWarriors: even, + fearsClerics: !even, + fearsMages: even, + fearsThieves: !even, + stenchLevel: i % 5, + treasures, + eatenHeroes + }) + even = !even + i++ + } while (i < count) + return data +} diff --git a/__tests__/perf/fixtures/fixture-models.ts b/__tests__/perf/fixtures/fixture-models.ts new file mode 100644 index 000000000..1790e23cc --- /dev/null +++ b/__tests__/perf/fixtures/fixture-models.ts @@ -0,0 +1,62 @@ +const mst = require("../../../dist/mobx-state-tree.umd") +const { types } = mst + +// tiny +export const Treasure = types.model("Treasure", { + trapped: types.boolean, + gold: types.optional(types.number, 0) +}) +// medium +export const HeroRoles = ["warrior", "wizard", "cleric", "thief"] +export const Hero = types + .model("Hero", { + id: types.identifierNumber, + name: types.string, + description: types.string, + level: types.optional(types.number, 1), + role: types.union(...exports.HeroRoles.map(types.literal)) + }) + .views((self: any) => ({ + get descriptionLength() { + return self.description.length + } + })) +// large +export const Monster = types + .model("Monster", { + id: types.identifier, + freestyle: types.frozen(), + level: types.number, + maxHp: types.number, + hp: types.number, + warning: types.maybeNull(types.string), + createdAt: types.maybeNull(types.Date), + treasures: types.optional(types.array(exports.Treasure), []), + eatenHeroes: types.maybeNull(types.array(exports.Hero)), + hasFangs: types.optional(types.boolean, false), + hasClaws: types.optional(types.boolean, false), + hasWings: types.optional(types.boolean, false), + hasGrowl: types.optional(types.boolean, false), + stenchLevel: types.optional(types.number, 0), + fearsFire: types.optional(types.boolean, false), + fearsWater: types.optional(types.boolean, false), + fearsWarriors: types.optional(types.boolean, false), + fearsClerics: types.optional(types.boolean, false), + fearsMages: types.optional(types.boolean, false), + fearsThieves: types.optional(types.boolean, false), + fearsProgrammers: types.optional(types.boolean, true) + }) + .views((self: any) => ({ + get isAlive() { + return self.hp > 0 + }, + get isFlashingRed() { + return self.hp > 0 && self.hp < self.maxHp && self.hp === 1 + }, + get weight() { + const victimWeight = self.eatenHeroes ? self.eatenHeroes.length : 0 + const fangWeight = self.hasFangs ? 10 : 5 + const wingWeight = self.hasWings ? 12 : 4 + return (victimWeight + fangWeight + wingWeight) * self.level > 5 ? 2 : 1 + } + })) diff --git a/__tests__/perf/perf.test.ts b/__tests__/perf/perf.test.ts new file mode 100644 index 000000000..96430a612 --- /dev/null +++ b/__tests__/perf/perf.test.ts @@ -0,0 +1,30 @@ +import { smallScenario, mediumScenario, largeScenario } from "./scenarios" +import { start } from "./timer" + +// TODO: Not sure how this should work. This feels super fragile. +const TOO_SLOW_MS = 10000 +test("performs well on small scenario", () => { + expect(smallScenario(10).elapsed < TOO_SLOW_MS).toBe(true) +}) +test("performs well on medium scenario", () => { + expect(mediumScenario(10).elapsed < TOO_SLOW_MS).toBe(true) +}) +test("performs well on large scenario", () => { + expect(largeScenario(10, 0, 0).elapsed < TOO_SLOW_MS).toBe(true) + expect(largeScenario(10, 10, 0).elapsed < TOO_SLOW_MS).toBe(true) + expect(largeScenario(10, 0, 10).elapsed < TOO_SLOW_MS).toBe(true) + expect(largeScenario(10, 10, 10).elapsed < TOO_SLOW_MS).toBe(true) +}) +test("timer", (done) => { + const go = start() + setTimeout(function () { + const lap = go(true) + setTimeout(function () { + const d = go() + expect(lap).not.toBe(0) + expect(d).not.toBe(0) + expect(lap).not.toBe(d) + done() + }, 2) + }, 2) +}) diff --git a/__tests__/perf/report.ts b/__tests__/perf/report.ts new file mode 100644 index 000000000..169b5121f --- /dev/null +++ b/__tests__/perf/report.ts @@ -0,0 +1,79 @@ +import { smallScenario, mediumScenario, largeScenario } from "./scenarios" + +// here's what we'll be testing +const plan = [ + "-----------", + "Small Model", + "-----------", + () => smallScenario(100), + () => smallScenario(1000), + () => smallScenario(10000), + () => smallScenario(1000), + () => smallScenario(100), + "", + "------------", + "Medium Model", + "------------", + () => mediumScenario(100), + () => mediumScenario(1000), + () => mediumScenario(10000), + () => mediumScenario(1000), + () => mediumScenario(100), + "", + "------------------------", + "Large Model - 0 children", + "------------------------", + () => largeScenario(100, 0, 0), + () => largeScenario(1000, 0, 0), + () => largeScenario(100, 0, 0), + "", + "-------------------------------------------", + "Large Model - 10 small & 10 medium children", + "-------------------------------------------", + () => largeScenario(50, 10, 10), + () => largeScenario(250, 10, 10), + () => largeScenario(50, 10, 10), + "", + "-------------------------------------------", + "Large Model - 100 small & 0 medium children", + "-------------------------------------------", + () => largeScenario(50, 100, 0), + () => largeScenario(250, 100, 0), + () => largeScenario(50, 100, 0), + "", + "-------------------------------------------", + "Large Model - 0 small & 100 medium children", + "-------------------------------------------", + () => largeScenario(50, 0, 100), + () => largeScenario(250, 0, 100), + () => largeScenario(50, 0, 100) +] +// burn a few to get the juices flowing +smallScenario(1000) +mediumScenario(500) +largeScenario(100, 10, 10) +// remember when this broke the internet? +function leftPad(value: string, length: number, char = " "): string { + return value.toString().length < length ? leftPad(char + value, length) : value +} +// let's start +plan.forEach((fn) => { + // strings get printed, i guess. + if (typeof fn === "string") { + console.log(fn) + return + } + // trigger awkward gc up front if we can + if (global.gc) { + global.gc() + } + // run the report + const result = fn() + // calculate some fields + const seconds = leftPad((result.elapsed / 1.0).toLocaleString(), 8) + const times = leftPad(`x ${result.count.toLocaleString()}`, 10) + const avg = leftPad((result.elapsed / result.count).toFixed(1), 4) + // print + console.log(`${seconds}ms | ${times} | ${avg}ms avg`) +}) +console.log("") diff --git a/packages/mobx-state-tree/__tests__/perf/scenarios.ts b/__tests__/perf/scenarios.ts similarity index 53% rename from packages/mobx-state-tree/__tests__/perf/scenarios.ts rename to __tests__/perf/scenarios.ts index 67df880fe..f2268d14e 100644 --- a/packages/mobx-state-tree/__tests__/perf/scenarios.ts +++ b/__tests__/perf/scenarios.ts @@ -8,12 +8,12 @@ import { createTreasure, createHeros, createMonsters } from "./fixtures/fixture- * @param count The number of records to create. */ export function smallScenario(count: number) { - const data = createTreasure(count) // ready? - const time = start() - const converted = data.map((d) => Treasure.create(d)) // go - const elapsed = time() - const sanity = converted.length === count - return { count, elapsed, sanity } + const data = createTreasure(count) // ready? + const time = start() + const converted = data.map((d) => Treasure.create(d)) // go + const elapsed = time() + const sanity = converted.length === count + return { count, elapsed, sanity } } /** * Covers models with a moderate number of fields + 1 computed field. @@ -21,12 +21,12 @@ export function smallScenario(count: number) { * @param count The number of records to create. */ export function mediumScenario(count: number) { - const data = createHeros(count) // ready? - const time = start() - const converted = data.map((d) => Hero.create(d)) // go - const elapsed = time() - const sanity = converted.length === count - return { count, elapsed, sanity } + const data = createHeros(count) // ready? + const time = start() + const converted = data.map((d) => Hero.create(d)) // go + const elapsed = time() + const sanity = converted.length === count + return { count, elapsed, sanity } } /** * Covers models with a large number of fields. @@ -36,10 +36,10 @@ export function mediumScenario(count: number) { * @param mediumChildren The number of medium children contained within. */ export function largeScenario(count: number, smallChildren: number, mediumChildren: number) { - const data = createMonsters(count, smallChildren, mediumChildren) // ready? - const time = start() - const converted = data.map((d) => Monster.create(d)) // go - const elapsed = time() - const sanity = converted.length === count - return { count, elapsed, sanity } + const data = createMonsters(count, smallChildren, mediumChildren) // ready? + const time = start() + const converted = data.map((d) => Monster.create(d)) // go + const elapsed = time() + const sanity = converted.length === count + return { count, elapsed, sanity } } diff --git a/packages/mobx-state-tree/__tests__/perf/timer.ts b/__tests__/perf/timer.ts similarity index 58% rename from packages/mobx-state-tree/__tests__/perf/timer.ts rename to __tests__/perf/timer.ts index be79e414e..66d15139c 100644 --- a/packages/mobx-state-tree/__tests__/perf/timer.ts +++ b/__tests__/perf/timer.ts @@ -15,10 +15,10 @@ * ``` */ export const start = () => { - const started = process.hrtime() - let last: [number, number] = [started[0], started[1]] - return (lapTime = false) => { - const final = process.hrtime(lapTime ? last : started) - return Math.round((final[0] * 1e9 + final[1]) / 1e6) - } + const started = process.hrtime() + let last: [number, number] = [started[0], started[1]] + return (lapTime = false) => { + const final = process.hrtime(lapTime ? last : started) + return Math.round((final[0] * 1e9 + final[1]) / 1e6) + } } diff --git a/packages/mobx-state-tree/__tests__/tsconfig.json b/__tests__/tsconfig.json similarity index 100% rename from packages/mobx-state-tree/__tests__/tsconfig.json rename to __tests__/tsconfig.json diff --git a/docs/API/index.md b/docs/API/index.md index 7085dda6d..78233c076 100644 --- a/docs/API/index.md +++ b/docs/API/index.md @@ -1,10 +1,10 @@ --- id: "index" -title: "mobx-state-tree - v5.2.0" +title: "mobx-state-tree - v5.3.0-alpha.1" sidebar_label: "Globals" --- -[mobx-state-tree - v5.2.0](index.md) +[mobx-state-tree - v5.3.0-alpha.1](index.md) ## Index @@ -177,7 +177,7 @@ sidebar_label: "Globals" Ƭ **IDisposer**: *function* -*Defined in [packages/mobx-state-tree/src/utils.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/utils.ts#L41)* +*Defined in [src/utils.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/utils.ts#L41)* A generic disposer. @@ -191,7 +191,7 @@ ___ Ƭ **IHooksGetter**: *function* -*Defined in [packages/mobx-state-tree/src/core/node/Hook.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/Hook.ts#L19)* +*Defined in [src/core/node/Hook.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/Hook.ts#L19)* #### Type declaration: @@ -209,7 +209,7 @@ ___ Ƭ **IMiddlewareEventType**: *"action" | "flow_spawn" | "flow_resume" | "flow_resume_error" | "flow_return" | "flow_throw"* -*Defined in [packages/mobx-state-tree/src/core/action.ts:16](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L16)* +*Defined in [src/core/action.ts:16](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L16)* ___ @@ -217,7 +217,7 @@ ___ Ƭ **IMiddlewareHandler**: *function* -*Defined in [packages/mobx-state-tree/src/core/action.ts:54](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L54)* +*Defined in [src/core/action.ts:54](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L54)* #### Type declaration: @@ -254,7 +254,7 @@ ___ Ƭ **ITypeDispatcher**: *function* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L27)* +*Defined in [src/types/utility-types/union.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L27)* #### Type declaration: @@ -272,7 +272,7 @@ ___ Ƭ **IValidationContext**: *[IValidationContextEntry](interfaces/ivalidationcontextentry.md)[]* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:23](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L23)* +*Defined in [src/core/type/type-checker.ts:23](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L23)* Array of validation context entries @@ -282,7 +282,7 @@ ___ Ƭ **IValidationResult**: *[IValidationError](interfaces/ivalidationerror.md)[]* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:36](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L36)* +*Defined in [src/core/type/type-checker.ts:36](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L36)* Type validation result, which is an array of type validation errors @@ -292,7 +292,7 @@ ___ Ƭ **Instance**: *T extends object ? T["Type"] : T* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:230](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L230)* +*Defined in [src/core/type/type.ts:230](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L230)* The instance representation of a given type. @@ -302,7 +302,7 @@ ___ Ƭ **LivelinessMode**: *"warn" | "error" | "ignore"* -*Defined in [packages/mobx-state-tree/src/core/node/livelinessChecking.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/livelinessChecking.ts#L7)* +*Defined in [src/core/node/livelinessChecking.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/livelinessChecking.ts#L7)* Defines what MST should do when running into reads / writes to objects that have died. - `"warn"`: Print a warning (default). @@ -315,7 +315,7 @@ ___ Ƭ **OnReferenceInvalidated**: *function* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:43](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L43)* +*Defined in [src/types/utility-types/reference.ts:43](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L43)* #### Type declaration: @@ -333,7 +333,7 @@ ___ Ƭ **OnReferenceInvalidatedEvent**: *object* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L34)* +*Defined in [src/types/utility-types/reference.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L34)* #### Type declaration: @@ -343,7 +343,7 @@ ___ Ƭ **ReferenceIdentifier**: *string | number* -*Defined in [packages/mobx-state-tree/src/types/utility-types/identifier.ts:142](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/identifier.ts#L142)* +*Defined in [src/types/utility-types/identifier.ts:142](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/identifier.ts#L142)* Valid types for identifiers. @@ -353,7 +353,7 @@ ___ Ƭ **ReferenceOptions**: *[ReferenceOptionsGetSet](interfaces/referenceoptionsgetset.md)‹IT› | [ReferenceOptionsOnInvalidated](interfaces/referenceoptionsoninvalidated.md)‹IT› | [ReferenceOptionsGetSet](interfaces/referenceoptionsgetset.md)‹IT› & [ReferenceOptionsOnInvalidated](interfaces/referenceoptionsoninvalidated.md)‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:473](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L473)* +*Defined in [src/types/utility-types/reference.ts:451](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L451)* ___ @@ -361,7 +361,7 @@ ___ Ƭ **SnapshotIn**: *T extends object ? T["CreationType"] : T extends IStateTreeNode ? IT["CreationType"] : T* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:235](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L235)* +*Defined in [src/core/type/type.ts:235](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L235)* The input (creation) snapshot representation of a given type. @@ -371,7 +371,7 @@ ___ Ƭ **SnapshotOrInstance**: *[SnapshotIn](index.md#snapshotin)‹T› | [Instance](index.md#instance)‹T›* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:276](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L276)* +*Defined in [src/core/type/type.ts:276](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L276)* A type which is equivalent to the union of SnapshotIn and Instance types of a given typeof TYPE or typeof VARIABLE. For primitives it defaults to the primitive itself. @@ -404,7 +404,7 @@ ___ Ƭ **SnapshotOut**: *T extends object ? T["SnapshotType"] : T extends IStateTreeNode ? IT["SnapshotType"] : T* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:244](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L244)* +*Defined in [src/core/type/type.ts:244](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L244)* The output snapshot representation of a given type. @@ -414,7 +414,7 @@ The output snapshot representation of a given type. • **DatePrimitive**: *[IType](interfaces/itype.md)‹number | Date, number, Date›* = _DatePrimitive -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:215](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L215)* +*Defined in [src/types/primitives.ts:215](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L215)* `types.Date` - Creates a type that can only contain a javascript Date value. @@ -432,12 +432,12 @@ ___ ### `Const` boolean • **boolean**: *[ISimpleType](interfaces/isimpletype.md)‹boolean›* = new CoreType( - "boolean", - TypeFlags.Boolean, - (v) => typeof v === "boolean" + "boolean", + TypeFlags.Boolean, + (v) => typeof v === "boolean" ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:169](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L169)* +*Defined in [src/types/primitives.ts:169](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L169)* `types.boolean` - Creates a type that can only contain a boolean value. This type is used for boolean values by default @@ -455,12 +455,12 @@ ___ ### `Const` finite • **finite**: *[ISimpleType](interfaces/isimpletype.md)‹number›* = new CoreType( - "finite", - TypeFlags.Finite, - (v) => isFinite(v) + "finite", + TypeFlags.Finite, + (v) => isFinite(v) ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:150](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L150)* +*Defined in [src/types/primitives.ts:150](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L150)* `types.finite` - Creates a type that can only contain an finite value. @@ -477,12 +477,12 @@ ___ ### `Const` float • **float**: *[ISimpleType](interfaces/isimpletype.md)‹number›* = new CoreType( - "float", - TypeFlags.Float, - (v) => isFloat(v) + "float", + TypeFlags.Float, + (v) => isFloat(v) ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:132](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L132)* +*Defined in [src/types/primitives.ts:132](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L132)* `types.float` - Creates a type that can only contain an float value. @@ -500,7 +500,7 @@ ___ • **identifier**: *[ISimpleType](interfaces/isimpletype.md)‹string›* = new IdentifierType() -*Defined in [packages/mobx-state-tree/src/types/utility-types/identifier.ts:110](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/identifier.ts#L110)* +*Defined in [src/types/utility-types/identifier.ts:110](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/identifier.ts#L110)* `types.identifier` - Identifiers are used to make references, lifecycle events and reconciling works. Inside a state tree, for each type can exist only one instance for each given identifier. @@ -524,7 +524,7 @@ ___ • **identifierNumber**: *[ISimpleType](interfaces/isimpletype.md)‹number›* = new IdentifierNumberType() -*Defined in [packages/mobx-state-tree/src/types/utility-types/identifier.ts:125](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/identifier.ts#L125)* +*Defined in [src/types/utility-types/identifier.ts:125](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/identifier.ts#L125)* `types.identifierNumber` - Similar to `types.identifier`. This one will serialize from / to a number when applying snapshots @@ -543,12 +543,12 @@ ___ ### `Const` integer • **integer**: *[ISimpleType](interfaces/isimpletype.md)‹number›* = new CoreType( - "integer", - TypeFlags.Integer, - (v) => isInteger(v) + "integer", + TypeFlags.Integer, + (v) => isInteger(v) ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:114](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L114)* +*Defined in [src/types/primitives.ts:114](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L114)* `types.integer` - Creates a type that can only contain an integer value. @@ -565,12 +565,12 @@ ___ ### `Const` nullType • **nullType**: *[ISimpleType](interfaces/isimpletype.md)‹null›* = new CoreType( - "null", - TypeFlags.Null, - (v) => v === null + "null", + TypeFlags.Null, + (v) => v === null ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:178](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L178)* +*Defined in [src/types/primitives.ts:178](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L178)* `types.null` - The type of the value `null` @@ -579,12 +579,12 @@ ___ ### `Const` number • **number**: *[ISimpleType](interfaces/isimpletype.md)‹number›* = new CoreType( - "number", - TypeFlags.Number, - (v) => typeof v === "number" + "number", + TypeFlags.Number, + (v) => typeof v === "number" ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L96)* +*Defined in [src/types/primitives.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L96)* `types.number` - Creates a type that can only contain a numeric value. This type is used for numeric values by default @@ -602,12 +602,12 @@ ___ ### `Const` string • **string**: *[ISimpleType](interfaces/isimpletype.md)‹string›* = new CoreType( - "string", - TypeFlags.String, - (v) => typeof v === "string" + "string", + TypeFlags.String, + (v) => typeof v === "string" ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:77](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L77)* +*Defined in [src/types/primitives.ts:77](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L77)* `types.string` - Creates a type that can only contain a string value. This type is used for string values by default @@ -625,12 +625,12 @@ ___ ### `Const` undefinedType • **undefinedType**: *[ISimpleType](interfaces/isimpletype.md)‹undefined›* = new CoreType( - "undefined", - TypeFlags.Undefined, - (v) => v === undefined + "undefined", + TypeFlags.Undefined, + (v) => v === undefined ) -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L187)* +*Defined in [src/types/primitives.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L187)* `types.undefined` - The type of the value `undefined` @@ -640,7 +640,7 @@ ___ ▸ **addDisposer**(`target`: IAnyStateTreeNode, `disposer`: [IDisposer](index.md#idisposer)): *[IDisposer](index.md#idisposer)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:752](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L752)* +*Defined in [src/core/mst-operations.ts:752](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L752)* Use this utility to register a function that should be called whenever the targeted state tree node is destroyed. This is a useful alternative to managing @@ -682,7 +682,7 @@ ___ ▸ **addMiddleware**(`target`: IAnyStateTreeNode, `handler`: [IMiddlewareHandler](index.md#imiddlewarehandler), `includeHooks`: boolean): *[IDisposer](index.md#idisposer)* -*Defined in [packages/mobx-state-tree/src/core/action.ts:163](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L163)* +*Defined in [src/core/action.ts:161](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L161)* Middleware can be used to intercept any action is invoked on the subtree where it is attached. If a tree is protected (by default), this means that any mutation of the tree will pass through your middleware. @@ -707,7 +707,7 @@ ___ ▸ **applyAction**(`target`: IAnyStateTreeNode, `actions`: [ISerializedActionCall](interfaces/iserializedactioncall.md) | [ISerializedActionCall](interfaces/iserializedactioncall.md)[]): *void* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L89)* +*Defined in [src/middlewares/on-action.ts:88](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L88)* Applies an action or a series of actions in a single MobX transaction. Does not return any value @@ -728,7 +728,7 @@ ___ ▸ **applyPatch**(`target`: IAnyStateTreeNode, `patch`: [IJsonPatch](interfaces/ijsonpatch.md) | ReadonlyArray‹[IJsonPatch](interfaces/ijsonpatch.md)›): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:125](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L125)* +*Defined in [src/core/mst-operations.ts:125](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L125)* Applies a JSON-patch to the given model instance or bails out if the patch couldn't be applied See [patches](https://github.com/mobxjs/mobx-state-tree#patches) for more details. @@ -750,7 +750,7 @@ ___ ▸ **applySnapshot**<**C**>(`target`: IStateTreeNode‹[IType](interfaces/itype.md)‹C, any, any››, `snapshot`: C): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:322](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L322)* +*Defined in [src/core/mst-operations.ts:322](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L322)* Applies a snapshot to a given model instances. Patch and snapshot listeners will be invoked as usual. @@ -773,7 +773,7 @@ ___ ▸ **array**<**IT**>(`subtype`: IT): *IArrayType‹IT›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/array.ts:337](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/array.ts#L337)* +*Defined in [src/types/complex-types/array.ts:333](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/array.ts#L333)* `types.array` - Creates an index based collection type who's children are all of a uniform declared type. @@ -813,7 +813,7 @@ ___ ▸ **cast**<**O**>(`snapshotOrInstance`: O): *O* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:881](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L881)* +*Defined in [src/core/mst-operations.ts:881](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L881)* Casts a node snapshot or instance type to an instance type so it can be assigned to a type instance. Note that this is just a cast for the type system, this is, it won't actually convert a snapshot to an instance, @@ -856,7 +856,7 @@ The same object cast as an instance ▸ **cast**<**O**>(`snapshotOrInstance`: TypeOfValue["CreationType"] | TypeOfValue["SnapshotType"] | TypeOfValue["Type"]): *O* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:884](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L884)* +*Defined in [src/core/mst-operations.ts:884](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L884)* Casts a node snapshot or instance type to an instance type so it can be assigned to a type instance. Note that this is just a cast for the type system, this is, it won't actually convert a snapshot to an instance, @@ -903,7 +903,7 @@ ___ ▸ **castFlowReturn**<**T**>(`val`: T): *T* -*Defined in [packages/mobx-state-tree/src/core/flow.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/flow.ts#L34)* +*Defined in [src/core/flow.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/flow.ts#L34)* **`deprecated`** Not needed since TS3.6. Used for TypeScript to make flows that return a promise return the actual promise result. @@ -926,7 +926,7 @@ ___ ▸ **castToReferenceSnapshot**<**I**>(`instance`: I): *Extract extends never ? I : ReferenceIdentifier* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:984](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L984)* +*Defined in [src/core/mst-operations.ts:984](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L984)* Casts a node instance type to a reference snapshot type so it can be assigned to a reference snapshot (e.g. to be used inside a create call). Note that this is just a cast for the type system, this is, it won't actually convert an instance to a reference snapshot, @@ -972,7 +972,7 @@ ___ ▸ **castToSnapshot**<**I**>(`snapshotOrInstance`: I): *Extract extends never ? I : TypeOfValue["CreationType"]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:950](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L950)* +*Defined in [src/core/mst-operations.ts:950](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L950)* Casts a node instance type to a snapshot type so it can be assigned to a type snapshot (e.g. to be used inside a create call). Note that this is just a cast for the type system, this is, it won't actually convert an instance to a snapshot, @@ -1017,7 +1017,7 @@ ___ ▸ **clone**<**T**>(`source`: T, `keepEnvironment`: boolean | any): *T* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:667](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L667)* +*Defined in [src/core/mst-operations.ts:667](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L667)* Returns a deep copy of the given state tree node as new tree. Shorthand for `snapshot(x) = getType(x).create(getSnapshot(x))` @@ -1043,7 +1043,7 @@ ___ ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›): *[IModelType](interfaces/imodeltype.md)‹PA & PB, OA & OB, _CustomJoin‹FCA, FCB›, _CustomJoin‹FSA, FSB››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:772](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L772)* +*Defined in [src/types/complex-types/model.ts:761](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L761)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1081,7 +1081,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›): *[IModelType](interfaces/imodeltype.md)‹PA & PB, OA & OB, _CustomJoin‹FCA, FCB›, _CustomJoin‹FSA, FSB››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:774](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L774)* +*Defined in [src/types/complex-types/model.ts:763](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L763)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1118,7 +1118,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC, OA & OB & OC, _CustomJoin‹FCA, _CustomJoin‹FCB, FCC››, _CustomJoin‹FSA, _CustomJoin‹FSB, FSC›››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:776](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L776)* +*Defined in [src/types/complex-types/model.ts:765](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L765)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1165,7 +1165,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC, OA & OB & OC, _CustomJoin‹FCA, _CustomJoin‹FCB, FCC››, _CustomJoin‹FSA, _CustomJoin‹FSB, FSC›››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:778](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L778)* +*Defined in [src/types/complex-types/model.ts:767](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L767)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1211,7 +1211,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD, OA & OB & OC & OD, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, FCD›››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, FSD››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:780](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L780)* +*Defined in [src/types/complex-types/model.ts:769](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L769)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1267,7 +1267,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD, OA & OB & OC & OD, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, FCD›››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, FSD››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:782](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L782)* +*Defined in [src/types/complex-types/model.ts:771](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L771)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1322,7 +1322,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE, OA & OB & OC & OD & OE, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, FCE››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, FSE›››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:784](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L784)* +*Defined in [src/types/complex-types/model.ts:773](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L773)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1387,7 +1387,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE, OA & OB & OC & OD & OE, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, FCE››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, FSE›››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:786](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L786)* +*Defined in [src/types/complex-types/model.ts:775](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L775)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1451,7 +1451,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF, OA & OB & OC & OD & OE & OF, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, FCF›››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, FSF››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:790](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L790)* +*Defined in [src/types/complex-types/model.ts:779](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L779)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1525,7 +1525,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF, OA & OB & OC & OD & OE & OF, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, FCF›››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, FSF››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:793](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L793)* +*Defined in [src/types/complex-types/model.ts:782](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L782)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1598,7 +1598,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG, OA & OB & OC & OD & OE & OF & OG, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, FCG››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, FSG›››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:796](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L796)* +*Defined in [src/types/complex-types/model.ts:785](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L785)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1681,7 +1681,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG, OA & OB & OC & OD & OE & OF & OG, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, FCG››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, FSG›››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:799](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L799)* +*Defined in [src/types/complex-types/model.ts:788](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L788)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1763,7 +1763,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG & PH, OA & OB & OC & OD & OE & OF & OG & OH, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, _CustomJoin‹FCG, FCH›››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, _CustomJoin‹FSG, FSH››››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:802](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L802)* +*Defined in [src/types/complex-types/model.ts:791](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L791)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1855,7 +1855,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG & PH, OA & OB & OC & OD & OE & OF & OG & OH, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, _CustomJoin‹FCG, FCH›››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, _CustomJoin‹FSG, FSH››››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:805](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L805)* +*Defined in [src/types/complex-types/model.ts:794](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L794)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -1946,7 +1946,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**, **PI**, **OI**, **FCI**, **FSI**>(`name`: string, `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›, `I`: [IModelType](interfaces/imodeltype.md)‹PI, OI, FCI, FSI›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG & PH & PI, OA & OB & OC & OD & OE & OF & OG & OH & OI, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, _CustomJoin‹FCG, _CustomJoin‹FCH, FCI››››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, _CustomJoin‹FSG, _CustomJoin‹FSH, FSI›››››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:808](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L808)* +*Defined in [src/types/complex-types/model.ts:797](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L797)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -2047,7 +2047,7 @@ Name | Type | ▸ **compose**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**, **PI**, **OI**, **FCI**, **FSI**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›, `I`: [IModelType](interfaces/imodeltype.md)‹PI, OI, FCI, FSI›): *[IModelType](interfaces/imodeltype.md)‹PA & PB & PC & PD & PE & PF & PG & PH & PI, OA & OB & OC & OD & OE & OF & OG & OH & OI, _CustomJoin‹FCA, _CustomJoin‹FCB, _CustomJoin‹FCC, _CustomJoin‹FCD, _CustomJoin‹FCE, _CustomJoin‹FCF, _CustomJoin‹FCG, _CustomJoin‹FCH, FCI››››››››, _CustomJoin‹FSA, _CustomJoin‹FSB, _CustomJoin‹FSC, _CustomJoin‹FSD, _CustomJoin‹FSE, _CustomJoin‹FSF, _CustomJoin‹FSG, _CustomJoin‹FSH, FSI›››››››››* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:811](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L811)* +*Defined in [src/types/complex-types/model.ts:800](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L800)* `types.compose` - Composes a new model from one or more existing model types. This method can be invoked in two forms: @@ -2151,7 +2151,7 @@ ___ ▸ **createActionTrackingMiddleware**<**T**>(`hooks`: [IActionTrackingMiddlewareHooks](interfaces/iactiontrackingmiddlewarehooks.md)‹T›): *[IMiddlewareHandler](index.md#imiddlewarehandler)* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:28](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L28)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:28](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L28)* Note: Consider migrating to `createActionTrackingMiddleware2`, it is easier to use. @@ -2181,7 +2181,7 @@ ___ ▸ **createActionTrackingMiddleware2**<**TEnv**>(`middlewareHooks`: [IActionTrackingMiddleware2Hooks](interfaces/iactiontrackingmiddleware2hooks.md)‹TEnv›): *[IMiddlewareHandler](index.md#imiddlewarehandler)* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:74](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L74)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:74](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L74)* Convenience utility to create action based middleware that supports async processes more easily. The flow is like this: @@ -2220,7 +2220,7 @@ ___ ▸ **custom**<**S**, **T**>(`options`: [CustomTypeOptions](interfaces/customtypeoptions.md)‹S, T›): *[IType](interfaces/itype.md)‹S | T, S, T›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:74](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L74)* +*Defined in [src/types/utility-types/custom.ts:74](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L74)* `types.custom` - Creates a custom type. Custom types can be used for arbitrary immutable values, that have a serializable representation. For example, to create your own Date representation, Decimal type etc. @@ -2284,7 +2284,7 @@ ___ ▸ **decorate**<**T**>(`handler`: [IMiddlewareHandler](index.md#imiddlewarehandler), `fn`: T, `includeHooks`: boolean): *T* -*Defined in [packages/mobx-state-tree/src/core/action.ts:202](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L202)* +*Defined in [src/core/action.ts:200](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L200)* Binds middleware to a specific action. @@ -2325,7 +2325,7 @@ ___ ▸ **destroy**(`target`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:699](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L699)* +*Defined in [src/core/mst-operations.ts:699](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L699)* Removes a model element from the state tree, and mark it as end-of-life; the element should not be used anymore @@ -2343,7 +2343,7 @@ ___ ▸ **detach**<**T**>(`target`: T): *T* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:688](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L688)* +*Defined in [src/core/mst-operations.ts:688](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L688)* Removes a model element from the state tree, and let it live on as a new state tree @@ -2365,7 +2365,7 @@ ___ ▸ **enumeration**<**T**>(`options`: T): *[ISimpleType](interfaces/isimpletype.md)‹UnionStringArray‹T››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/enumeration.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/enumeration.ts#L11)* +*Defined in [src/types/utility-types/enumeration.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/enumeration.ts#L11)* `types.enumeration` - Can be used to create an string based enumeration. (note: this methods is just sugar for a union of string literals) @@ -2391,7 +2391,7 @@ Name | Type | Description | ▸ **enumeration**<**T**>(`name`: string, `options`: T[]): *[ISimpleType](interfaces/isimpletype.md)‹UnionStringArray‹T[]››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/enumeration.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/enumeration.ts#L14)* +*Defined in [src/types/utility-types/enumeration.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/enumeration.ts#L14)* `types.enumeration` - Can be used to create an string based enumeration. (note: this methods is just sugar for a union of string literals) @@ -2422,7 +2422,7 @@ ___ ▸ **escapeJsonPath**(`path`: string): *string* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:77](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L77)* +*Defined in [src/core/json-patch.ts:77](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L77)* Escape slashes and backslashes. @@ -2442,7 +2442,7 @@ ___ ▸ **flow**<**R**, **Args**>(`generator`: function): *function* -*Defined in [packages/mobx-state-tree/src/core/flow.ts:21](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/flow.ts#L21)* +*Defined in [src/core/flow.ts:21](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/flow.ts#L21)* See [asynchronous actions](concepts/async-actions.md). @@ -2482,7 +2482,7 @@ ___ ▸ **frozen**<**C**>(`subType`: [IType](interfaces/itype.md)‹C, any, any›): *[IType](interfaces/itype.md)‹C, C, C›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/frozen.ts:58](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/frozen.ts#L58)* +*Defined in [src/types/utility-types/frozen.ts:54](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/frozen.ts#L54)* `types.frozen` - Frozen can be used to store any value that is serializable in itself (that is valid JSON). Frozen values need to be immutable or treated as if immutable. They need be serializable as well. @@ -2534,7 +2534,7 @@ Name | Type | ▸ **frozen**<**T**>(`defaultValue`: T): *[IType](interfaces/itype.md)‹T | undefined | null, T, T›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/frozen.ts:59](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/frozen.ts#L59)* +*Defined in [src/types/utility-types/frozen.ts:55](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/frozen.ts#L55)* `types.frozen` - Frozen can be used to store any value that is serializable in itself (that is valid JSON). Frozen values need to be immutable or treated as if immutable. They need be serializable as well. @@ -2586,7 +2586,7 @@ Name | Type | ▸ **frozen**<**T**>(): *[IType](interfaces/itype.md)‹T, T, T›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/frozen.ts:60](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/frozen.ts#L60)* +*Defined in [src/types/utility-types/frozen.ts:56](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/frozen.ts#L56)* `types.frozen` - Frozen can be used to store any value that is serializable in itself (that is valid JSON). Frozen values need to be immutable or treated as if immutable. They need be serializable as well. @@ -2636,7 +2636,7 @@ ___ ▸ **getChildType**(`object`: IAnyStateTreeNode, `propertyName?`: undefined | string): *[IAnyType](interfaces/ianytype.md)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:69](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L69)* +*Defined in [src/core/mst-operations.ts:69](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L69)* Returns the _declared_ type of the given sub property of an object, array or map. In the case of arrays and maps the property name is optional and will be ignored. @@ -2664,7 +2664,7 @@ ___ ▸ **getEnv**<**T**>(`target`: IAnyStateTreeNode): *T* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:774](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L774)* +*Defined in [src/core/mst-operations.ts:774](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L774)* Returns the environment of the current state tree. For more info on environments, see [Dependency injection](https://github.com/mobxjs/mobx-state-tree#dependency-injection) @@ -2692,7 +2692,7 @@ ___ ▸ **getIdentifier**(`target`: IAnyStateTreeNode): *string | null* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:550](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L550)* +*Defined in [src/core/mst-operations.ts:550](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L550)* Returns the identifier of the target node. This is the *string normalized* identifier, which might not match the type of the identifier attribute @@ -2711,7 +2711,7 @@ ___ ▸ **getLivelinessChecking**(): *[LivelinessMode](index.md#livelinessmode)* -*Defined in [packages/mobx-state-tree/src/core/node/livelinessChecking.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/livelinessChecking.ts#L27)* +*Defined in [src/core/node/livelinessChecking.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/livelinessChecking.ts#L27)* Returns the current liveliness checking mode. @@ -2725,7 +2725,7 @@ ___ ▸ **getMembers**(`target`: IAnyStateTreeNode): *[IModelReflectionData](interfaces/imodelreflectiondata.md)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:853](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L853)* +*Defined in [src/core/mst-operations.ts:853](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L853)* Returns a reflection of the model node, including name, properties, views, volatile state, and actions. `flowActions` is also provided as a separate array of names for any action that @@ -2750,7 +2750,7 @@ ___ ▸ **getNodeId**(`target`: IAnyStateTreeNode): *number* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:999](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L999)* +*Defined in [src/core/mst-operations.ts:999](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L999)* Returns the unique node id (not to be confused with the instance identifier) for a given instance. @@ -2772,7 +2772,7 @@ ___ ▸ **getParent**<**IT**>(`target`: IAnyStateTreeNode, `depth`: number): *TypeOrStateTreeNodeToStateTreeNode‹IT›* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:383](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L383)* +*Defined in [src/core/mst-operations.ts:383](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L383)* Returns the immediate parent of this object, or throws. @@ -2801,7 +2801,7 @@ ___ ▸ **getParentOfType**<**IT**>(`target`: IAnyStateTreeNode, `type`: IT): *IT["Type"]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:427](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L427)* +*Defined in [src/core/mst-operations.ts:427](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L427)* Returns the target's parent of a given type, or throws. @@ -2824,7 +2824,7 @@ ___ ▸ **getPath**(`target`: IAnyStateTreeNode): *string* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:467](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L467)* +*Defined in [src/core/mst-operations.ts:467](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L467)* Returns the path of the given object in the model tree @@ -2842,7 +2842,7 @@ ___ ▸ **getPathParts**(`target`: IAnyStateTreeNode): *string[]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:480](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L480)* +*Defined in [src/core/mst-operations.ts:480](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L480)* Returns the path of the given object as unescaped string array. @@ -2860,7 +2860,7 @@ ___ ▸ **getPropertyMembers**(`typeOrNode`: [IAnyModelType](interfaces/ianymodeltype.md) | IAnyStateTreeNode): *[IModelReflectionPropertiesData](interfaces/imodelreflectionpropertiesdata.md)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:814](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L814)* +*Defined in [src/core/mst-operations.ts:814](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L814)* Returns a reflection of the model type properties and name for either a model type or model node. @@ -2878,7 +2878,7 @@ ___ ▸ **getRelativePath**(`base`: IAnyStateTreeNode, `target`: IAnyStateTreeNode): *string* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:649](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L649)* +*Defined in [src/core/mst-operations.ts:649](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L649)* Given two state tree nodes that are part of the same tree, returns the shortest jsonpath needed to navigate from the one to the other @@ -2898,7 +2898,7 @@ ___ ▸ **getRoot**<**IT**>(`target`: IAnyStateTreeNode): *TypeOrStateTreeNodeToStateTreeNode‹IT›* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:452](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L452)* +*Defined in [src/core/mst-operations.ts:452](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L452)* Given an object in a model tree, returns the root object of that tree. @@ -2923,7 +2923,7 @@ ___ ▸ **getRunningActionContext**(): *[IActionContext](interfaces/iactioncontext.md) | undefined* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:26](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L26)* +*Defined in [src/core/actionContext.ts:26](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L26)* Returns the currently executing MST action context, or undefined if none. @@ -2935,7 +2935,7 @@ ___ ▸ **getSnapshot**<**S**>(`target`: IStateTreeNode‹[IType](interfaces/itype.md)‹any, S, any››, `applyPostProcess`: boolean): *S* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:337](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L337)* +*Defined in [src/core/mst-operations.ts:337](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L337)* Calculates a snapshot from the given model instance. The snapshot will always reflect the latest state but use structural sharing where possible. Doesn't require MobX transactions to be completed. @@ -2959,7 +2959,7 @@ ___ ▸ **getType**(`object`: IAnyStateTreeNode): *[IAnyComplexType](interfaces/ianycomplextype.md)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:47](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L47)* +*Defined in [src/core/mst-operations.ts:47](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L47)* Returns the _actual_ type of the given tree node. (Or throws) @@ -2977,7 +2977,7 @@ ___ ▸ **hasParent**(`target`: IAnyStateTreeNode, `depth`: number): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:357](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L357)* +*Defined in [src/core/mst-operations.ts:357](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L357)* Given a model instance, returns `true` if the object has a parent, that is, is part of another object, map or array. @@ -2996,7 +2996,7 @@ ___ ▸ **hasParentOfType**(`target`: IAnyStateTreeNode, `type`: [IAnyComplexType](interfaces/ianycomplextype.md)): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:407](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L407)* +*Defined in [src/core/mst-operations.ts:407](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L407)* Given a model instance, returns `true` if the object has a parent of given type, that is, is part of another object, map or array @@ -3015,7 +3015,7 @@ ___ ▸ **isActionContextChildOf**(`actionContext`: [IActionContext](interfaces/iactioncontext.md), `parent`: number | [IActionContext](interfaces/iactioncontext.md) | [IMiddlewareEvent](interfaces/imiddlewareevent.md)): *boolean* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:56](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L56)* +*Defined in [src/core/actionContext.ts:56](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L56)* Returns if the given action context is a parent of this action context. @@ -3034,7 +3034,7 @@ ___ ▸ **isActionContextThisOrChildOf**(`actionContext`: [IActionContext](interfaces/iactioncontext.md), `parentOrThis`: number | [IActionContext](interfaces/iactioncontext.md) | [IMiddlewareEvent](interfaces/imiddlewareevent.md)): *boolean* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:66](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L66)* +*Defined in [src/core/actionContext.ts:66](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L66)* Returns if the given action context is this or a parent of this action context. @@ -3053,7 +3053,7 @@ ___ ▸ **isAlive**(`target`: IAnyStateTreeNode): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:717](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L717)* +*Defined in [src/core/mst-operations.ts:717](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L717)* Returns true if the given state tree node is not killed yet. This means that the node is still a part of a tree, and that `destroy` @@ -3074,7 +3074,7 @@ ___ ▸ **isArrayType**<**Items**>(`type`: [IAnyType](interfaces/ianytype.md)): *type is IArrayType* -*Defined in [packages/mobx-state-tree/src/types/complex-types/array.ts:501](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/array.ts#L501)* +*Defined in [src/types/complex-types/array.ts:497](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/array.ts#L497)* Returns if a given value represents an array type. @@ -3098,7 +3098,7 @@ ___ ▸ **isFrozenType**<**IT**, **T**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/frozen.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/frozen.ts#L113)* +*Defined in [src/types/utility-types/frozen.ts:109](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/frozen.ts#L109)* Returns if a given value represents a frozen type. @@ -3122,7 +3122,7 @@ ___ ▸ **isIdentifierType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/identifier.ts:133](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/identifier.ts#L133)* +*Defined in [src/types/utility-types/identifier.ts:133](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/identifier.ts#L133)* Returns if a given value represents an identifier type. @@ -3144,7 +3144,7 @@ ___ ▸ **isLateType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/late.ts:141](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/late.ts#L141)* +*Defined in [src/types/utility-types/late.ts:137](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/late.ts#L137)* Returns if a given value represents a late type. @@ -3166,7 +3166,7 @@ ___ ▸ **isLiteralType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/literal.ts:86](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/literal.ts#L86)* +*Defined in [src/types/utility-types/literal.ts:82](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/literal.ts#L82)* Returns if a given value represents a literal type. @@ -3188,7 +3188,7 @@ ___ ▸ **isMapType**<**Items**>(`type`: [IAnyType](interfaces/ianytype.md)): *type is IMapType* -*Defined in [packages/mobx-state-tree/src/types/complex-types/map.ts:520](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/map.ts#L520)* +*Defined in [src/types/complex-types/map.ts:512](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/map.ts#L512)* Returns if a given value represents a map type. @@ -3212,7 +3212,7 @@ ___ ▸ **isModelType**<**IT**>(`type`: [IAnyType](interfaces/ianytype.md)): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:857](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L857)* +*Defined in [src/types/complex-types/model.ts:846](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L846)* Returns if a given value represents a model type. @@ -3234,7 +3234,7 @@ ___ ▸ **isOptionalType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/optional.ts:234](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/optional.ts#L234)* +*Defined in [src/types/utility-types/optional.ts:229](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/optional.ts#L229)* Returns if a value represents an optional type. @@ -3258,7 +3258,7 @@ ___ ▸ **isPrimitiveType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/primitives.ts:241](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/primitives.ts#L241)* +*Defined in [src/types/primitives.ts:241](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/primitives.ts#L241)* Returns if a given value represents a primitive type. @@ -3280,7 +3280,7 @@ ___ ▸ **isProtected**(`target`: IAnyStateTreeNode): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:311](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L311)* +*Defined in [src/core/mst-operations.ts:311](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L311)* Returns true if the object is in protected mode, @see protect @@ -3298,7 +3298,7 @@ ___ ▸ **isReferenceType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:533](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L533)* +*Defined in [src/types/utility-types/reference.ts:509](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L509)* Returns if a given value represents a reference type. @@ -3320,7 +3320,7 @@ ___ ▸ **isRefinementType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/refinement.ts:126](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/refinement.ts#L126)* +*Defined in [src/types/utility-types/refinement.ts:124](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/refinement.ts#L124)* Returns if a given value is a refinement type. @@ -3342,7 +3342,7 @@ ___ ▸ **isRoot**(`target`: IAnyStateTreeNode): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:493](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L493)* +*Defined in [src/core/mst-operations.ts:493](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L493)* Returns true if the given object is the root of a model tree. @@ -3360,7 +3360,7 @@ ___ ▸ **isStateTreeNode**<**IT**>(`value`: any): *value is STNValue, IT>* -*Defined in [packages/mobx-state-tree/src/core/node/node-utils.ts:68](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/node-utils.ts#L68)* +*Defined in [src/core/node/node-utils.ts:68](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/node-utils.ts#L68)* Returns true if the given value is a node in a state tree. More precisely, that is, if the value is an instance of a @@ -3386,7 +3386,7 @@ ___ ▸ **isType**(`value`: any): *value is IAnyType* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:539](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L539)* +*Defined in [src/core/type/type.ts:538](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L538)* Returns if a given value represents a type. @@ -3406,7 +3406,7 @@ ___ ▸ **isUnionType**<**IT**>(`type`: IT): *type is IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:282](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L282)* +*Defined in [src/types/utility-types/union.ts:280](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L280)* Returns if a given value represents a union type. @@ -3428,7 +3428,7 @@ ___ ▸ **isValidReference**<**N**>(`getter`: function, `checkIfAlive`: boolean): *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:597](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L597)* +*Defined in [src/core/mst-operations.ts:597](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L597)* Tests if a reference is valid (pointing to an existing node and optionally if alive) and returns if the check passes or not. @@ -3456,7 +3456,7 @@ ___ ▸ **joinJsonPath**(`path`: string[]): *string* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:98](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L98)* +*Defined in [src/core/json-patch.ts:98](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L98)* Generates a json-path compliant json path from path parts. @@ -3474,7 +3474,7 @@ ___ ▸ **late**<**T**>(`type`: function): *T* -*Defined in [packages/mobx-state-tree/src/types/utility-types/late.ts:103](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/late.ts#L103)* +*Defined in [src/types/utility-types/late.ts:99](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/late.ts#L99)* `types.late` - Defines a type that gets implemented later. This is useful when you have to deal with circular dependencies. Please notice that when defining circular dependencies TypeScript isn't smart enough to inference them. @@ -3503,7 +3503,7 @@ A function that returns the type that will be defined. ▸ **late**<**T**>(`name`: string, `type`: function): *T* -*Defined in [packages/mobx-state-tree/src/types/utility-types/late.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/late.ts#L104)* +*Defined in [src/types/utility-types/late.ts:100](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/late.ts#L100)* `types.late` - Defines a type that gets implemented later. This is useful when you have to deal with circular dependencies. Please notice that when defining circular dependencies TypeScript isn't smart enough to inference them. @@ -3540,7 +3540,7 @@ ___ ▸ **lazy**<**T**, **U**>(`name`: string, `options`: LazyOptions‹T, U›): *T* -*Defined in [packages/mobx-state-tree/src/types/utility-types/lazy.ts:22](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/lazy.ts#L22)* +*Defined in [src/types/utility-types/lazy.ts:22](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/lazy.ts#L22)* **Type parameters:** @@ -3563,7 +3563,7 @@ ___ ▸ **literal**<**S**>(`value`: S): *[ISimpleType](interfaces/isimpletype.md)‹S›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/literal.ts:73](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/literal.ts#L73)* +*Defined in [src/types/utility-types/literal.ts:69](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/literal.ts#L69)* `types.literal` - The literal type will return a type that will match only the exact given type. The given value must be a primitive, in order to be serialized to a snapshot correctly. @@ -3595,7 +3595,7 @@ ___ ▸ **map**<**IT**>(`subtype`: IT): *IMapType‹IT›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/map.ts:510](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/map.ts#L510)* +*Defined in [src/types/complex-types/map.ts:502](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/map.ts#L502)* `types.map` - Creates a key based collection type who's children are all of a uniform declared type. If the type stored in a map has an identifier, it is mandatory to store the child under that identifier in the map. @@ -3638,7 +3638,7 @@ ___ ▸ **maybe**<**IT**>(`type`: IT): *IMaybe‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/maybe.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/maybe.ts#L31)* +*Defined in [src/types/utility-types/maybe.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/maybe.ts#L31)* `types.maybe` - Maybe will make a type nullable, and also optional. The value `undefined` will be used to represent nullability. @@ -3661,7 +3661,7 @@ ___ ▸ **maybeNull**<**IT**>(`type`: IT): *IMaybeNull‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/maybe.ts:44](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/maybe.ts#L44)* +*Defined in [src/types/utility-types/maybe.ts:44](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/maybe.ts#L44)* `types.maybeNull` - Maybe will make a type nullable, and also optional. The value `null` will be used to represent no value. @@ -3684,7 +3684,7 @@ ___ ▸ **model**<**P**>(`name`: string, `properties?`: [P](undefined)): *[IModelType](interfaces/imodeltype.md)‹ModelPropertiesDeclarationToProperties‹P›, __type›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:741](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L741)* +*Defined in [src/types/complex-types/model.ts:730](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L730)* `types.model` - Creates a new model type by providing a name, properties, volatile state and actions. @@ -3705,7 +3705,7 @@ Name | Type | ▸ **model**<**P**>(`properties?`: [P](undefined)): *[IModelType](interfaces/imodeltype.md)‹ModelPropertiesDeclarationToProperties‹P›, __type›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:745](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L745)* +*Defined in [src/types/complex-types/model.ts:734](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L734)* `types.model` - Creates a new model type by providing a name, properties, volatile state and actions. @@ -3729,7 +3729,7 @@ ___ ▸ **onAction**(`target`: IAnyStateTreeNode, `listener`: function, `attachAfter`: boolean): *[IDisposer](index.md#idisposer)* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:226](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L226)* +*Defined in [src/middlewares/on-action.ts:225](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L225)* Registers a function that will be invoked for each action that is called on the provided model instance, or to any of its children. See [actions](https://github.com/mobxjs/mobx-state-tree#actions) for more details. onAction events are emitted only for the outermost called action in the stack. @@ -3789,7 +3789,7 @@ ___ ▸ **onPatch**(`target`: IAnyStateTreeNode, `callback`: function): *[IDisposer](index.md#idisposer)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L84)* +*Defined in [src/core/mst-operations.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L84)* Registers a function that will be invoked for each mutation that is applied to the provided model instance, or to any of its children. See [patches](https://github.com/mobxjs/mobx-state-tree#patches) for more details. onPatch events are emitted immediately and will not await the end of a transaction. @@ -3824,7 +3824,7 @@ ___ ▸ **onSnapshot**<**S**>(`target`: IStateTreeNode‹[IType](interfaces/itype.md)‹any, S, any››, `callback`: function): *[IDisposer](index.md#idisposer)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L104)* +*Defined in [src/core/mst-operations.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L104)* Registers a function that is invoked whenever a new snapshot for the given model instance is available. The listener will only be fire at the end of the current MobX (trans)action. @@ -3854,9 +3854,9 @@ ___ ### optional -▸ **optional**<**IT**>(`type`: IT, `defaultValueOrFunction`: OptionalDefaultValueOrFunction‹IT›): *IOptionalIType‹IT, []›* +▸ **optional**<**IT**>(`type`: IT, `defaultValueOrFunction`: OptionalDefaultValueOrFunction‹IT›): *IOptionalIType‹IT, [undefined]›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/optional.ts:160](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/optional.ts#L160)* +*Defined in [src/types/utility-types/optional.ts:155](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/optional.ts#L155)* `types.optional` - Can be used to create a property with a default value. @@ -3904,11 +3904,11 @@ Name | Type | `type` | IT | `defaultValueOrFunction` | OptionalDefaultValueOrFunction‹IT› | -**Returns:** *IOptionalIType‹IT, []›* +**Returns:** *IOptionalIType‹IT, [undefined]›* ▸ **optional**<**IT**, **OptionalVals**>(`type`: IT, `defaultValueOrFunction`: OptionalDefaultValueOrFunction‹IT›, `optionalValues`: OptionalVals): *IOptionalIType‹IT, OptionalVals›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/optional.ts:164](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/optional.ts#L164)* +*Defined in [src/types/utility-types/optional.ts:159](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/optional.ts#L159)* `types.optional` - Can be used to create a property with a default value. @@ -3967,7 +3967,7 @@ ___ ▸ **protect**(`target`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:266](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L266)* +*Defined in [src/core/mst-operations.ts:266](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L266)* The inverse of `unprotect`. @@ -3985,7 +3985,7 @@ ___ ▸ **recordActions**(`subject`: IAnyStateTreeNode, `filter?`: undefined | function): *[IActionRecorder](interfaces/iactionrecorder.md)* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:148](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L148)* +*Defined in [src/middlewares/on-action.ts:147](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L147)* Small abstraction around `onAction` and `applyAction`, attaches an action listener to a tree and records all the actions emitted. Returns an recorder object with the following signature: @@ -4023,7 +4023,7 @@ ___ ▸ **recordPatches**(`subject`: IAnyStateTreeNode, `filter?`: undefined | function): *[IPatchRecorder](interfaces/ipatchrecorder.md)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:178](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L178)* +*Defined in [src/core/mst-operations.ts:178](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L178)* Small abstraction around `onPatch` and `applyPatch`, attaches a patch listener to a tree and records all the patches. Returns a recorder object with the following signature: @@ -4066,7 +4066,7 @@ ___ ▸ **reference**<**IT**>(`subType`: IT, `options?`: [ReferenceOptions](index.md#referenceoptions)‹IT›): *IReferenceType‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:486](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L486)* +*Defined in [src/types/utility-types/reference.ts:464](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L464)* `types.reference` - Creates a reference to another type, which should have defined an identifier. See also the [reference and identifiers](https://github.com/mobxjs/mobx-state-tree#references-and-identifiers) section. @@ -4090,7 +4090,7 @@ ___ ▸ **refinement**<**IT**>(`name`: string, `type`: IT, `predicate`: function, `message?`: string | function): *IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/refinement.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/refinement.ts#L84)* +*Defined in [src/types/utility-types/refinement.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/refinement.ts#L84)* `types.refinement` - Creates a type that is more specific than the base type, e.g. `types.refinement(types.string, value => value.length > 5)` to create a type of strings that can only be longer then 5. @@ -4120,7 +4120,7 @@ Name | Type | ▸ **refinement**<**IT**>(`type`: IT, `predicate`: function, `message?`: string | function): *IT* -*Defined in [packages/mobx-state-tree/src/types/utility-types/refinement.ts:90](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/refinement.ts#L90)* +*Defined in [src/types/utility-types/refinement.ts:90](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/refinement.ts#L90)* `types.refinement` - Creates a type that is more specific than the base type, e.g. `types.refinement(types.string, value => value.length > 5)` to create a type of strings that can only be longer then 5. @@ -4152,7 +4152,7 @@ ___ ▸ **resolveIdentifier**<**IT**>(`type`: IT, `target`: IAnyStateTreeNode, `identifier`: [ReferenceIdentifier](index.md#referenceidentifier)): *IT["Type"] | undefined* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:526](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L526)* +*Defined in [src/core/mst-operations.ts:526](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L526)* Resolves a model instance given a root target, the type and the identifier you are searching for. Returns undefined if no value can be found. @@ -4177,7 +4177,7 @@ ___ ▸ **resolvePath**(`target`: IAnyStateTreeNode, `path`: string): *any* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:508](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L508)* +*Defined in [src/core/mst-operations.ts:508](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L508)* Resolves a path relatively to a given object. Returns undefined if no value can be found. @@ -4197,7 +4197,7 @@ ___ ▸ **safeReference**<**IT**>(`subType`: IT, `options`: __type | [ReferenceOptionsGetSet](interfaces/referenceoptionsgetset.md)‹IT› & object): *IReferenceType‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:537](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L537)* +*Defined in [src/types/utility-types/reference.ts:513](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L513)* `types.safeReference` - A safe reference is like a standard reference, except that it accepts the undefined value by default and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps @@ -4227,7 +4227,7 @@ Name | Type | ▸ **safeReference**<**IT**>(`subType`: IT, `options?`: __type | [ReferenceOptionsGetSet](interfaces/referenceoptionsgetset.md)‹IT› & object): *IMaybe‹IReferenceType‹IT››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:544](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L544)* +*Defined in [src/types/utility-types/reference.ts:520](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L520)* `types.safeReference` - A safe reference is like a standard reference, except that it accepts the undefined value by default and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps @@ -4261,7 +4261,7 @@ ___ ▸ **setLivelinessChecking**(`mode`: [LivelinessMode](index.md#livelinessmode)): *void* -*Defined in [packages/mobx-state-tree/src/core/node/livelinessChecking.ts:18](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/livelinessChecking.ts#L18)* +*Defined in [src/core/node/livelinessChecking.ts:18](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/livelinessChecking.ts#L18)* Defines what MST should do when running into reads / writes to objects that have died. By default it will print a warning. @@ -4281,7 +4281,7 @@ ___ ▸ **snapshotProcessor**<**IT**, **CustomC**, **CustomS**>(`type`: IT, `processors`: [ISnapshotProcessors](interfaces/isnapshotprocessors.md)‹IT["CreationType"], CustomC, IT["SnapshotType"], CustomS›, `name?`: undefined | string): *[ISnapshotProcessor](interfaces/isnapshotprocessor.md)‹IT, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts:246](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts#L246)* +*Defined in [src/types/utility-types/snapshotProcessor.ts:246](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/snapshotProcessor.ts#L246)* `types.snapshotProcessor` - Runs a pre/post snapshot processor before/after serializing a given type. @@ -4332,7 +4332,7 @@ ___ ▸ **splitJsonPath**(`path`: string): *string[]* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L118)* +*Defined in [src/core/json-patch.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L118)* Splits and decodes a json path into several parts. @@ -4350,7 +4350,7 @@ ___ ▸ **toGenerator**<**R**>(`p`: Promise‹R›): *Generator‹Promise‹R›, R, R›* -*Defined in [packages/mobx-state-tree/src/core/flow.ts:87](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/flow.ts#L87)* +*Defined in [src/core/flow.ts:87](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/flow.ts#L87)* **`experimental`** experimental api - might change on minor/patch releases @@ -4390,7 +4390,7 @@ ___ ▸ **toGeneratorFunction**<**R**, **Args**>(`p`: function): *(Anonymous function)* -*Defined in [packages/mobx-state-tree/src/core/flow.ts:60](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/flow.ts#L60)* +*Defined in [src/core/flow.ts:60](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/flow.ts#L60)* **`experimental`** experimental api - might change on minor/patch releases @@ -4439,7 +4439,7 @@ ___ ▸ **tryReference**<**N**>(`getter`: function, `checkIfAlive`: boolean): *N | undefined* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:565](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L565)* +*Defined in [src/core/mst-operations.ts:565](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L565)* Tests if a reference is valid (pointing to an existing node and optionally if alive) and returns such reference if the check passes, else it returns undefined. @@ -4468,7 +4468,7 @@ ___ ▸ **tryResolve**(`target`: IAnyStateTreeNode, `path`: string): *any* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:625](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L625)* +*Defined in [src/core/mst-operations.ts:625](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L625)* Try to resolve a given path relative to a given node. @@ -4487,7 +4487,7 @@ ___ ▸ **typecheck**<**IT**>(`type`: IT, `value`: ExtractCSTWithSTN‹IT›): *void* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:166](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L166)* +*Defined in [src/core/type/type-checker.ts:164](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L164)* Run's the typechecker for the given type on the given value, which can be a snapshot or an instance. Throws if the given value is not according the provided type specification. @@ -4512,7 +4512,7 @@ ___ ▸ **unescapeJsonPath**(`path`: string): *string* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:88](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L88)* +*Defined in [src/core/json-patch.ts:88](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L88)* Unescape slashes and backslashes. @@ -4530,7 +4530,7 @@ ___ ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:159](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L159)* +*Defined in [src/types/utility-types/union.ts:157](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L157)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4563,7 +4563,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:161](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L161)* +*Defined in [src/types/utility-types/union.ts:159](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L159)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4597,7 +4597,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:164](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L164)* +*Defined in [src/types/utility-types/union.ts:162](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L162)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4639,7 +4639,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:166](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L166)* +*Defined in [src/types/utility-types/union.ts:164](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L164)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4682,7 +4682,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:168](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L168)* +*Defined in [src/types/utility-types/union.ts:166](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L166)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4733,7 +4733,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:171](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L171)* +*Defined in [src/types/utility-types/union.ts:169](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L169)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4785,7 +4785,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:174](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L174)* +*Defined in [src/types/utility-types/union.ts:172](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L172)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4845,7 +4845,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:177](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L177)* +*Defined in [src/types/utility-types/union.ts:175](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L175)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4906,7 +4906,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:180](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L180)* +*Defined in [src/types/utility-types/union.ts:178](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L178)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -4975,7 +4975,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:183](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L183)* +*Defined in [src/types/utility-types/union.ts:181](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L181)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5045,7 +5045,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:186](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L186)* +*Defined in [src/types/utility-types/union.ts:184](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L184)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5123,7 +5123,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:189](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L189)* +*Defined in [src/types/utility-types/union.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L187)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5202,7 +5202,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG› | ModelCreationType2‹PH, FCH›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG› | ModelSnapshotType2‹PH, FSH›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG› | ModelInstanceType‹PH, OH››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:193](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L193)* +*Defined in [src/types/utility-types/union.ts:191](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L191)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5289,7 +5289,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG› | ModelCreationType2‹PH, FCH›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG› | ModelSnapshotType2‹PH, FSH›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG› | ModelInstanceType‹PH, OH››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:196](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L196)* +*Defined in [src/types/utility-types/union.ts:194](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L194)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5377,7 +5377,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**, **PI**, **OI**, **FCI**, **FSI**>(`A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›, `I`: [IModelType](interfaces/imodeltype.md)‹PI, OI, FCI, FSI›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG› | ModelCreationType2‹PH, FCH› | ModelCreationType2‹PI, FCI›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG› | ModelSnapshotType2‹PH, FSH› | ModelSnapshotType2‹PI, FSI›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG› | ModelInstanceType‹PH, OH› | ModelInstanceType‹PI, OI››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:200](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L200)* +*Defined in [src/types/utility-types/union.ts:198](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L198)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5473,7 +5473,7 @@ Name | Type | ▸ **union**<**PA**, **OA**, **FCA**, **FSA**, **PB**, **OB**, **FCB**, **FSB**, **PC**, **OC**, **FCC**, **FSC**, **PD**, **OD**, **FCD**, **FSD**, **PE**, **OE**, **FCE**, **FSE**, **PF**, **OF**, **FCF**, **FSF**, **PG**, **OG**, **FCG**, **FSG**, **PH**, **OH**, **FCH**, **FSH**, **PI**, **OI**, **FCI**, **FSI**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IModelType](interfaces/imodeltype.md)‹PA, OA, FCA, FSA›, `B`: [IModelType](interfaces/imodeltype.md)‹PB, OB, FCB, FSB›, `C`: [IModelType](interfaces/imodeltype.md)‹PC, OC, FCC, FSC›, `D`: [IModelType](interfaces/imodeltype.md)‹PD, OD, FCD, FSD›, `E`: [IModelType](interfaces/imodeltype.md)‹PE, OE, FCE, FSE›, `F`: [IModelType](interfaces/imodeltype.md)‹PF, OF, FCF, FSF›, `G`: [IModelType](interfaces/imodeltype.md)‹PG, OG, FCG, FSG›, `H`: [IModelType](interfaces/imodeltype.md)‹PH, OH, FCH, FSH›, `I`: [IModelType](interfaces/imodeltype.md)‹PI, OI, FCI, FSI›): *ITypeUnion‹ModelCreationType2‹PA, FCA› | ModelCreationType2‹PB, FCB› | ModelCreationType2‹PC, FCC› | ModelCreationType2‹PD, FCD› | ModelCreationType2‹PE, FCE› | ModelCreationType2‹PF, FCF› | ModelCreationType2‹PG, FCG› | ModelCreationType2‹PH, FCH› | ModelCreationType2‹PI, FCI›, ModelSnapshotType2‹PA, FSA› | ModelSnapshotType2‹PB, FSB› | ModelSnapshotType2‹PC, FSC› | ModelSnapshotType2‹PD, FSD› | ModelSnapshotType2‹PE, FSE› | ModelSnapshotType2‹PF, FSF› | ModelSnapshotType2‹PG, FSG› | ModelSnapshotType2‹PH, FSH› | ModelSnapshotType2‹PI, FSI›, ModelInstanceType‹PA, OA› | ModelInstanceType‹PB, OB› | ModelInstanceType‹PC, OC› | ModelInstanceType‹PD, OD› | ModelInstanceType‹PE, OE› | ModelInstanceType‹PF, OF› | ModelInstanceType‹PG, OG› | ModelInstanceType‹PH, OH› | ModelInstanceType‹PI, OI››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:203](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L203)* +*Defined in [src/types/utility-types/union.ts:201](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L201)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5570,7 +5570,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›): *ITypeUnion‹CA | CB, SA | SB, TA | TB›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:207](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L207)* +*Defined in [src/types/utility-types/union.ts:205](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L205)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5599,7 +5599,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›): *ITypeUnion‹CA | CB, SA | SB, TA | TB›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L209)* +*Defined in [src/types/utility-types/union.ts:207](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L207)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5629,7 +5629,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›): *ITypeUnion‹CA | CB | CC, SA | SB | SC, TA | TB | TC›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:211](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L211)* +*Defined in [src/types/utility-types/union.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L209)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5665,7 +5665,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›): *ITypeUnion‹CA | CB | CC, SA | SB | SC, TA | TB | TC›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L213)* +*Defined in [src/types/utility-types/union.ts:211](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L211)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5702,7 +5702,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›): *ITypeUnion‹CA | CB | CC | CD, SA | SB | SC | SD, TA | TB | TC | TD›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:215](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L215)* +*Defined in [src/types/utility-types/union.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L213)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5745,7 +5745,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›): *ITypeUnion‹CA | CB | CC | CD, SA | SB | SC | SD, TA | TB | TC | TD›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:218](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L218)* +*Defined in [src/types/utility-types/union.ts:216](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L216)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5789,7 +5789,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›): *ITypeUnion‹CA | CB | CC | CD | CE, SA | SB | SC | SD | SE, TA | TB | TC | TD | TE›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:220](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L220)* +*Defined in [src/types/utility-types/union.ts:218](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L218)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5839,7 +5839,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›): *ITypeUnion‹CA | CB | CC | CD | CE, SA | SB | SC | SD | SE, TA | TB | TC | TD | TE›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:222](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L222)* +*Defined in [src/types/utility-types/union.ts:220](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L220)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5890,7 +5890,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›): *ITypeUnion‹CA | CB | CC | CD | CE | CF, SA | SB | SC | SD | SE | SF, TA | TB | TC | TD | TE | TF›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:224](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L224)* +*Defined in [src/types/utility-types/union.ts:222](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L222)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -5947,7 +5947,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›): *ITypeUnion‹CA | CB | CC | CD | CE | CF, SA | SB | SC | SD | SE | SF, TA | TB | TC | TD | TE | TF›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:226](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L226)* +*Defined in [src/types/utility-types/union.ts:224](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L224)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6005,7 +6005,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG, SA | SB | SC | SD | SE | SF | SG, TA | TB | TC | TD | TE | TF | TG›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:228](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L228)* +*Defined in [src/types/utility-types/union.ts:226](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L226)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6069,7 +6069,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG, SA | SB | SC | SD | SE | SF | SG, TA | TB | TC | TD | TE | TF | TG›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:231](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L231)* +*Defined in [src/types/utility-types/union.ts:229](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L229)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6134,7 +6134,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**, **CH**, **SH**, **TH**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›, `H`: [IType](interfaces/itype.md)‹CH, SH, TH›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG | CH, SA | SB | SC | SD | SE | SF | SG | SH, TA | TB | TC | TD | TE | TF | TG | TH›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:233](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L233)* +*Defined in [src/types/utility-types/union.ts:231](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L231)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6205,7 +6205,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**, **CH**, **SH**, **TH**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›, `H`: [IType](interfaces/itype.md)‹CH, SH, TH›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG | CH, SA | SB | SC | SD | SE | SF | SG | SH, TA | TB | TC | TD | TE | TF | TG | TH›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:236](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L236)* +*Defined in [src/types/utility-types/union.ts:234](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L234)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6277,7 +6277,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**, **CH**, **SH**, **TH**, **CI**, **SI**, **TI**>(`A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›, `H`: [IType](interfaces/itype.md)‹CH, SH, TH›, `I`: [IType](interfaces/itype.md)‹CI, SI, TI›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG | CH | CI, SA | SB | SC | SD | SE | SF | SG | SH | SI, TA | TB | TC | TD | TE | TF | TG | TH | TI›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:239](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L239)* +*Defined in [src/types/utility-types/union.ts:237](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L237)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6355,7 +6355,7 @@ Name | Type | ▸ **union**<**CA**, **SA**, **TA**, **CB**, **SB**, **TB**, **CC**, **SC**, **TC**, **CD**, **SD**, **TD**, **CE**, **SE**, **TE**, **CF**, **SF**, **TF**, **CG**, **SG**, **TG**, **CH**, **SH**, **TH**, **CI**, **SI**, **TI**>(`options`: [UnionOptions](interfaces/unionoptions.md), `A`: [IType](interfaces/itype.md)‹CA, SA, TA›, `B`: [IType](interfaces/itype.md)‹CB, SB, TB›, `C`: [IType](interfaces/itype.md)‹CC, SC, TC›, `D`: [IType](interfaces/itype.md)‹CD, SD, TD›, `E`: [IType](interfaces/itype.md)‹CE, SE, TE›, `F`: [IType](interfaces/itype.md)‹CF, SF, TF›, `G`: [IType](interfaces/itype.md)‹CG, SG, TG›, `H`: [IType](interfaces/itype.md)‹CH, SH, TH›, `I`: [IType](interfaces/itype.md)‹CI, SI, TI›): *ITypeUnion‹CA | CB | CC | CD | CE | CF | CG | CH | CI, SA | SB | SC | SD | SE | SF | SG | SH | SI, TA | TB | TC | TD | TE | TF | TG | TH | TI›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:242](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L242)* +*Defined in [src/types/utility-types/union.ts:240](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L240)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6434,7 +6434,7 @@ Name | Type | ▸ **union**(...`types`: [IAnyType](interfaces/ianytype.md)[]): *[IAnyType](interfaces/ianytype.md)* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:245](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L245)* +*Defined in [src/types/utility-types/union.ts:243](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L243)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6448,7 +6448,7 @@ Name | Type | ▸ **union**(`dispatchOrType`: [UnionOptions](interfaces/unionoptions.md) | [IAnyType](interfaces/ianytype.md), ...`otherTypes`: [IAnyType](interfaces/ianytype.md)[]): *[IAnyType](interfaces/ianytype.md)* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:246](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L246)* +*Defined in [src/types/utility-types/union.ts:244](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L244)* `types.union` - Create a union of multiple types. If the correct type cannot be inferred unambiguously from a snapshot, provide a dispatcher function of the form `(snapshot) => Type`. @@ -6467,7 +6467,7 @@ ___ ▸ **unprotect**(`target`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:299](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L299)* +*Defined in [src/core/mst-operations.ts:299](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L299)* By default it is not allowed to directly modify a model. Models can only be modified through actions. However, in some cases you don't care about the advantages (like replayability, traceability, etc) this yields. @@ -6506,7 +6506,7 @@ ___ ▸ **walk**(`target`: IAnyStateTreeNode, `processor`: function): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:787](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L787)* +*Defined in [src/core/mst-operations.ts:787](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L787)* Performs a depth first walk through a tree. @@ -6532,178 +6532,178 @@ Name | Type | ### ▪ **types**: *object* -*Defined in [packages/mobx-state-tree/src/types/index.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L34)* +*Defined in [src/types/index.ts:34](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L34)* ### Date • **Date**: *[IType](interfaces/itype.md)‹number | Date, number, Date›* = DatePrimitive -*Defined in [packages/mobx-state-tree/src/types/index.ts:53](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L53)* +*Defined in [src/types/index.ts:53](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L53)* ### array • **array**: *[array](index.md#array)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:55](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L55)* +*Defined in [src/types/index.ts:55](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L55)* ### boolean • **boolean**: *[ISimpleType](interfaces/isimpletype.md)‹boolean›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:48](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L48)* +*Defined in [src/types/index.ts:48](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L48)* ### compose • **compose**: *[compose](index.md#compose)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L37)* +*Defined in [src/types/index.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L37)* ### custom • **custom**: *[custom](index.md#custom)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:38](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L38)* +*Defined in [src/types/index.ts:38](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L38)* ### enumeration • **enumeration**: *[enumeration](index.md#enumeration)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:35](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L35)* +*Defined in [src/types/index.ts:35](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L35)* ### finite • **finite**: *[ISimpleType](interfaces/isimpletype.md)‹number›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:52](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L52)* +*Defined in [src/types/index.ts:52](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L52)* ### float • **float**: *[ISimpleType](interfaces/isimpletype.md)‹number›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:51](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L51)* +*Defined in [src/types/index.ts:51](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L51)* ### frozen • **frozen**: *[frozen](index.md#frozen)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:56](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L56)* +*Defined in [src/types/index.ts:56](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L56)* ### identifier • **identifier**: *[ISimpleType](interfaces/isimpletype.md)‹string›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:57](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L57)* +*Defined in [src/types/index.ts:57](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L57)* ### identifierNumber • **identifierNumber**: *[ISimpleType](interfaces/isimpletype.md)‹number›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:58](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L58)* +*Defined in [src/types/index.ts:58](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L58)* ### integer • **integer**: *[ISimpleType](interfaces/isimpletype.md)‹number›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:50](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L50)* +*Defined in [src/types/index.ts:50](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L50)* ### late • **late**: *[late](index.md#late)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:59](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L59)* +*Defined in [src/types/index.ts:59](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L59)* ### lazy • **lazy**: *[lazy](index.md#lazy)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:60](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L60)* +*Defined in [src/types/index.ts:60](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L60)* ### literal • **literal**: *[literal](index.md#literal)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:43](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L43)* +*Defined in [src/types/index.ts:43](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L43)* ### map • **map**: *[map](index.md#map)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:54](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L54)* +*Defined in [src/types/index.ts:54](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L54)* ### maybe • **maybe**: *[maybe](index.md#maybe)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:44](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L44)* +*Defined in [src/types/index.ts:44](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L44)* ### maybeNull • **maybeNull**: *[maybeNull](index.md#maybenull)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:45](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L45)* +*Defined in [src/types/index.ts:45](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L45)* ### model • **model**: *[model](index.md#model)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:36](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L36)* +*Defined in [src/types/index.ts:36](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L36)* ### null • **null**: *[ISimpleType](interfaces/isimpletype.md)‹null›* = nullType -*Defined in [packages/mobx-state-tree/src/types/index.ts:62](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L62)* +*Defined in [src/types/index.ts:62](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L62)* ### number • **number**: *[ISimpleType](interfaces/isimpletype.md)‹number›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:49](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L49)* +*Defined in [src/types/index.ts:49](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L49)* ### optional • **optional**: *[optional](index.md#optional)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:42](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L42)* +*Defined in [src/types/index.ts:42](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L42)* ### reference • **reference**: *[reference](index.md#reference)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:39](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L39)* +*Defined in [src/types/index.ts:39](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L39)* ### refinement • **refinement**: *[refinement](index.md#refinement)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:46](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L46)* +*Defined in [src/types/index.ts:46](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L46)* ### safeReference • **safeReference**: *[safeReference](index.md#safereference)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:40](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L40)* +*Defined in [src/types/index.ts:40](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L40)* ### snapshotProcessor • **snapshotProcessor**: *[snapshotProcessor](index.md#snapshotprocessor)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:63](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L63)* +*Defined in [src/types/index.ts:63](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L63)* ### string • **string**: *[ISimpleType](interfaces/isimpletype.md)‹string›* -*Defined in [packages/mobx-state-tree/src/types/index.ts:47](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L47)* +*Defined in [src/types/index.ts:47](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L47)* ### undefined • **undefined**: *[ISimpleType](interfaces/isimpletype.md)‹undefined›* = undefinedType -*Defined in [packages/mobx-state-tree/src/types/index.ts:61](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L61)* +*Defined in [src/types/index.ts:61](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L61)* ### union • **union**: *[union](index.md#union)* -*Defined in [packages/mobx-state-tree/src/types/index.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/index.ts#L41)* +*Defined in [src/types/index.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/index.ts#L41)* diff --git a/docs/API/interfaces/customtypeoptions.md b/docs/API/interfaces/customtypeoptions.md index 498d42914..7baf69029 100644 --- a/docs/API/interfaces/customtypeoptions.md +++ b/docs/API/interfaces/customtypeoptions.md @@ -4,7 +4,7 @@ title: "CustomTypeOptions" sidebar_label: "CustomTypeOptions" --- -[mobx-state-tree - v5.2.0](../index.md) › [CustomTypeOptions](customtypeoptions.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [CustomTypeOptions](customtypeoptions.md) ## Type parameters @@ -35,7 +35,7 @@ sidebar_label: "CustomTypeOptions" • **name**: *string* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L15)* +*Defined in [src/types/utility-types/custom.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L15)* Friendly name @@ -45,7 +45,7 @@ Friendly name ▸ **fromSnapshot**(`snapshot`: S, `env?`: any): *T* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L17)* +*Defined in [src/types/utility-types/custom.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L17)* given a serialized value and environment, how to turn it into the target type @@ -64,7 +64,7 @@ ___ ▸ **getValidationMessage**(`snapshot`: S): *string* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:23](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L23)* +*Defined in [src/types/utility-types/custom.ts:23](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L23)* a non empty string is assumed to be a validation error @@ -82,7 +82,7 @@ ___ ▸ **isTargetType**(`value`: T | S): *boolean* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:21](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L21)* +*Defined in [src/types/utility-types/custom.ts:21](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L21)* if true, this is a converted value, if false, it's a snapshot @@ -100,7 +100,7 @@ ___ ▸ **toSnapshot**(`value`: T): *S* -*Defined in [packages/mobx-state-tree/src/types/utility-types/custom.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/custom.ts#L19)* +*Defined in [src/types/utility-types/custom.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/custom.ts#L19)* return the serialization of the current value diff --git a/docs/API/interfaces/functionwithflag.md b/docs/API/interfaces/functionwithflag.md index 144d68fdd..1589bcfdb 100644 --- a/docs/API/interfaces/functionwithflag.md +++ b/docs/API/interfaces/functionwithflag.md @@ -4,7 +4,7 @@ title: "FunctionWithFlag" sidebar_label: "FunctionWithFlag" --- -[mobx-state-tree - v5.2.0](../index.md) › [FunctionWithFlag](functionwithflag.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [FunctionWithFlag](functionwithflag.md) ## Hierarchy @@ -47,7 +47,7 @@ ___ • **_isFlowAction**? : *undefined | false | true* -*Defined in [packages/mobx-state-tree/src/core/action.ts:42](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L42)* +*Defined in [src/core/action.ts:42](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L42)* ___ @@ -55,7 +55,7 @@ ___ • **_isMSTAction**? : *undefined | false | true* -*Defined in [packages/mobx-state-tree/src/core/action.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L41)* +*Defined in [src/core/action.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L41)* ___ @@ -117,7 +117,7 @@ Defined in node_modules/typescript/lib/lib.es5.d.ts:298 *Inherited from void* -Defined in node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts:162 +Defined in node_modules/typescript/lib/lib.es2015.symbol.wellknown.d.ts:157 Determines whether the given value inherits from this function if this function was used as a constructor function. diff --git a/docs/API/interfaces/iactioncontext.md b/docs/API/interfaces/iactioncontext.md index a972c5670..0ae038116 100644 --- a/docs/API/interfaces/iactioncontext.md +++ b/docs/API/interfaces/iactioncontext.md @@ -4,7 +4,7 @@ title: "IActionContext" sidebar_label: "IActionContext" --- -[mobx-state-tree - v5.2.0](../index.md) › [IActionContext](iactioncontext.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IActionContext](iactioncontext.md) ## Hierarchy @@ -29,7 +29,7 @@ sidebar_label: "IActionContext" • **args**: *any[]* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:20](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L20)* +*Defined in [src/core/actionContext.ts:20](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L20)* Event arguments in an array (action arguments for actions) @@ -39,7 +39,7 @@ ___ • **context**: *IAnyStateTreeNode* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L15)* +*Defined in [src/core/actionContext.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L15)* Event context (node where the action was invoked) @@ -49,7 +49,7 @@ ___ • **id**: *number* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L9)* +*Defined in [src/core/actionContext.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L9)* Event unique id @@ -59,7 +59,7 @@ ___ • **name**: *string* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L6)* +*Defined in [src/core/actionContext.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L6)* Event name (action name for actions) @@ -69,7 +69,7 @@ ___ • **parentActionEvent**: *[IMiddlewareEvent](imiddlewareevent.md) | undefined* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L12)* +*Defined in [src/core/actionContext.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L12)* Parent action event object @@ -79,6 +79,6 @@ ___ • **tree**: *IAnyStateTreeNode* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L17)* +*Defined in [src/core/actionContext.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L17)* Event tree (root node of the node where the action was invoked) diff --git a/docs/API/interfaces/iactionrecorder.md b/docs/API/interfaces/iactionrecorder.md index 25c293180..b51e37b47 100644 --- a/docs/API/interfaces/iactionrecorder.md +++ b/docs/API/interfaces/iactionrecorder.md @@ -4,7 +4,7 @@ title: "IActionRecorder" sidebar_label: "IActionRecorder" --- -[mobx-state-tree - v5.2.0](../index.md) › [IActionRecorder](iactionrecorder.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IActionRecorder](iactionrecorder.md) ## Hierarchy @@ -29,7 +29,7 @@ sidebar_label: "IActionRecorder" • **actions**: *ReadonlyArray‹[ISerializedActionCall](iserializedactioncall.md)›* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L37)* +*Defined in [src/middlewares/on-action.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L37)* ___ @@ -37,7 +37,7 @@ ___ • **recording**: *boolean* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:38](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L38)* +*Defined in [src/middlewares/on-action.ts:38](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L38)* ## Methods @@ -45,7 +45,7 @@ ___ ▸ **replay**(`target`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L41)* +*Defined in [src/middlewares/on-action.ts:41](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L41)* **Parameters:** @@ -61,7 +61,7 @@ ___ ▸ **resume**(): *void* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:40](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L40)* +*Defined in [src/middlewares/on-action.ts:40](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L40)* **Returns:** *void* @@ -71,6 +71,6 @@ ___ ▸ **stop**(): *void* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:39](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L39)* +*Defined in [src/middlewares/on-action.ts:39](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L39)* **Returns:** *void* diff --git a/docs/API/interfaces/iactiontrackingmiddleware2call.md b/docs/API/interfaces/iactiontrackingmiddleware2call.md index b61ec5761..ba1c91d46 100644 --- a/docs/API/interfaces/iactiontrackingmiddleware2call.md +++ b/docs/API/interfaces/iactiontrackingmiddleware2call.md @@ -4,7 +4,7 @@ title: "IActionTrackingMiddleware2Call" sidebar_label: "IActionTrackingMiddleware2Call" --- -[mobx-state-tree - v5.2.0](../index.md) › [IActionTrackingMiddleware2Call](iactiontrackingmiddleware2call.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IActionTrackingMiddleware2Call](iactiontrackingmiddleware2call.md) ## Type parameters @@ -29,7 +29,7 @@ sidebar_label: "IActionTrackingMiddleware2Call" • **env**: *TEnv | undefined* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L6)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L6)* ___ @@ -37,4 +37,4 @@ ___ • **parentCall**? : *[IActionTrackingMiddleware2Call](iactiontrackingmiddleware2call.md)‹TEnv›* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L7)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L7)* diff --git a/docs/API/interfaces/iactiontrackingmiddleware2hooks.md b/docs/API/interfaces/iactiontrackingmiddleware2hooks.md index 05e624ac0..e6a8a9ba4 100644 --- a/docs/API/interfaces/iactiontrackingmiddleware2hooks.md +++ b/docs/API/interfaces/iactiontrackingmiddleware2hooks.md @@ -4,7 +4,7 @@ title: "IActionTrackingMiddleware2Hooks" sidebar_label: "IActionTrackingMiddleware2Hooks" --- -[mobx-state-tree - v5.2.0](../index.md) › [IActionTrackingMiddleware2Hooks](iactiontrackingmiddleware2hooks.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IActionTrackingMiddleware2Hooks](iactiontrackingmiddleware2hooks.md) ## Type parameters @@ -28,7 +28,7 @@ sidebar_label: "IActionTrackingMiddleware2Hooks" • **filter**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L11)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L11)* ___ @@ -36,7 +36,7 @@ ___ • **onFinish**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:13](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L13)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:13](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L13)* #### Type declaration: @@ -55,7 +55,7 @@ ___ • **onStart**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts#L12)* +*Defined in [src/middlewares/createActionTrackingMiddleware2.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/createActionTrackingMiddleware2.ts#L12)* #### Type declaration: diff --git a/docs/API/interfaces/iactiontrackingmiddlewarehooks.md b/docs/API/interfaces/iactiontrackingmiddlewarehooks.md index 282a727de..921ca9b82 100644 --- a/docs/API/interfaces/iactiontrackingmiddlewarehooks.md +++ b/docs/API/interfaces/iactiontrackingmiddlewarehooks.md @@ -4,7 +4,7 @@ title: "IActionTrackingMiddlewareHooks" sidebar_label: "IActionTrackingMiddlewareHooks" --- -[mobx-state-tree - v5.2.0](../index.md) › [IActionTrackingMiddlewareHooks](iactiontrackingmiddlewarehooks.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IActionTrackingMiddlewareHooks](iactiontrackingmiddlewarehooks.md) ## Type parameters @@ -31,7 +31,7 @@ sidebar_label: "IActionTrackingMiddlewareHooks" • **filter**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L6)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L6)* ___ @@ -39,7 +39,7 @@ ___ • **onFail**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L11)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:11](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L11)* #### Type declaration: @@ -59,7 +59,7 @@ ___ • **onResume**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L8)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L8)* #### Type declaration: @@ -78,7 +78,7 @@ ___ • **onStart**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L7)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:7](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L7)* #### Type declaration: @@ -96,7 +96,7 @@ ___ • **onSuccess**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L10)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L10)* #### Type declaration: @@ -116,7 +116,7 @@ ___ • **onSuspend**: *function* -*Defined in [packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts#L9)* +*Defined in [src/middlewares/create-action-tracking-middleware.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/create-action-tracking-middleware.ts#L9)* #### Type declaration: diff --git a/docs/API/interfaces/ianycomplextype.md b/docs/API/interfaces/ianycomplextype.md index ac6828ba9..7145423f4 100644 --- a/docs/API/interfaces/ianycomplextype.md +++ b/docs/API/interfaces/ianycomplextype.md @@ -4,7 +4,7 @@ title: "IAnyComplexType" sidebar_label: "IAnyComplexType" --- -[mobx-state-tree - v5.2.0](../index.md) › [IAnyComplexType](ianycomplextype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IAnyComplexType](ianycomplextype.md) Any kind of complex type. @@ -36,7 +36,7 @@ Any kind of complex type. *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -48,7 +48,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -60,7 +60,7 @@ Friendly type name. *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -83,7 +83,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -97,7 +97,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -119,7 +119,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. diff --git a/docs/API/interfaces/ianymodeltype.md b/docs/API/interfaces/ianymodeltype.md index 0e73539b5..b141844a3 100644 --- a/docs/API/interfaces/ianymodeltype.md +++ b/docs/API/interfaces/ianymodeltype.md @@ -4,7 +4,7 @@ title: "IAnyModelType" sidebar_label: "IAnyModelType" --- -[mobx-state-tree - v5.2.0](../index.md) › [IAnyModelType](ianymodeltype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IAnyModelType](ianymodeltype.md) Any model type. @@ -45,7 +45,7 @@ Any model type. *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -57,7 +57,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -69,7 +69,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[properties](imodeltype.md#properties)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L187)* +*Defined in [src/types/complex-types/model.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L187)* ## Methods @@ -79,7 +79,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[actions](imodeltype.md#actions)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:201](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L201)* +*Defined in [src/types/complex-types/model.ts:201](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L201)* **Type parameters:** @@ -107,7 +107,7 @@ ___ *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -130,7 +130,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -144,7 +144,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[extend](imodeltype.md#extend)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L209)* +*Defined in [src/types/complex-types/model.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L209)* **Type parameters:** @@ -176,7 +176,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -198,7 +198,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[named](imodeltype.md#named)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:189](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L189)* +*Defined in [src/types/complex-types/model.ts:189](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L189)* **Parameters:** @@ -216,7 +216,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[postProcessSnapshot](imodeltype.md#postprocesssnapshot)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:217](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L217)* +*Defined in [src/types/complex-types/model.ts:217](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L217)* **Type parameters:** @@ -244,7 +244,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[preProcessSnapshot](imodeltype.md#preprocesssnapshot)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L213)* +*Defined in [src/types/complex-types/model.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L213)* **Type parameters:** @@ -272,7 +272,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[props](imodeltype.md#props)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:193](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L193)* +*Defined in [src/types/complex-types/model.ts:193](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L193)* **Type parameters:** @@ -294,7 +294,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. @@ -317,7 +317,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[views](imodeltype.md#views)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:197](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L197)* +*Defined in [src/types/complex-types/model.ts:197](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L197)* **Type parameters:** @@ -345,7 +345,7 @@ ___ *Inherited from [IModelType](imodeltype.md).[volatile](imodeltype.md#volatile)* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:205](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L205)* +*Defined in [src/types/complex-types/model.ts:205](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L205)* **Type parameters:** diff --git a/docs/API/interfaces/ianytype.md b/docs/API/interfaces/ianytype.md index 598c0525f..c82d16fc6 100644 --- a/docs/API/interfaces/ianytype.md +++ b/docs/API/interfaces/ianytype.md @@ -4,7 +4,7 @@ title: "IAnyType" sidebar_label: "IAnyType" --- -[mobx-state-tree - v5.2.0](../index.md) › [IAnyType](ianytype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IAnyType](ianytype.md) Any kind of type. @@ -36,7 +36,7 @@ Any kind of type. *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -48,7 +48,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -60,7 +60,7 @@ Friendly type name. *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -83,7 +83,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -97,7 +97,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -119,7 +119,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. diff --git a/docs/API/interfaces/ihooks.md b/docs/API/interfaces/ihooks.md index 1f598b9d2..fcf0f5d7b 100644 --- a/docs/API/interfaces/ihooks.md +++ b/docs/API/interfaces/ihooks.md @@ -4,7 +4,7 @@ title: "IHooks" sidebar_label: "IHooks" --- -[mobx-state-tree - v5.2.0](../index.md) › [IHooks](ihooks.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IHooks](ihooks.md) ## Hierarchy @@ -25,7 +25,7 @@ sidebar_label: "IHooks" • **[Hook.afterAttach]**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/core/node/Hook.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/Hook.ts#L14)* +*Defined in [src/core/node/Hook.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/Hook.ts#L14)* ___ @@ -33,7 +33,7 @@ ___ • **[Hook.afterCreate]**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/core/node/Hook.ts:13](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/Hook.ts#L13)* +*Defined in [src/core/node/Hook.ts:13](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/Hook.ts#L13)* ___ @@ -41,7 +41,7 @@ ___ • **[Hook.beforeDestroy]**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/core/node/Hook.ts:16](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/Hook.ts#L16)* +*Defined in [src/core/node/Hook.ts:16](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/Hook.ts#L16)* ___ @@ -49,4 +49,4 @@ ___ • **[Hook.beforeDetach]**? : *undefined | function* -*Defined in [packages/mobx-state-tree/src/core/node/Hook.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/node/Hook.ts#L15)* +*Defined in [src/core/node/Hook.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/node/Hook.ts#L15)* diff --git a/docs/API/interfaces/ijsonpatch.md b/docs/API/interfaces/ijsonpatch.md index 8e5e19fe5..51838c9e2 100644 --- a/docs/API/interfaces/ijsonpatch.md +++ b/docs/API/interfaces/ijsonpatch.md @@ -4,7 +4,7 @@ title: "IJsonPatch" sidebar_label: "IJsonPatch" --- -[mobx-state-tree - v5.2.0](../index.md) › [IJsonPatch](ijsonpatch.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IJsonPatch](ijsonpatch.md) https://tools.ietf.org/html/rfc6902 http://jsonpatch.com/ @@ -29,7 +29,7 @@ http://jsonpatch.com/ • **op**: *"replace" | "add" | "remove"* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L8)* +*Defined in [src/core/json-patch.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L8)* ___ @@ -37,7 +37,7 @@ ___ • **path**: *string* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L9)* +*Defined in [src/core/json-patch.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L9)* ___ @@ -45,4 +45,4 @@ ___ • **value**? : *any* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L10)* +*Defined in [src/core/json-patch.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L10)* diff --git a/docs/API/interfaces/imiddlewareevent.md b/docs/API/interfaces/imiddlewareevent.md index 306be5e59..dcf409654 100644 --- a/docs/API/interfaces/imiddlewareevent.md +++ b/docs/API/interfaces/imiddlewareevent.md @@ -4,7 +4,7 @@ title: "IMiddlewareEvent" sidebar_label: "IMiddlewareEvent" --- -[mobx-state-tree - v5.2.0](../index.md) › [IMiddlewareEvent](imiddlewareevent.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IMiddlewareEvent](imiddlewareevent.md) ## Hierarchy @@ -34,7 +34,7 @@ sidebar_label: "IMiddlewareEvent" • **allParentIds**: *number[]* -*Defined in [packages/mobx-state-tree/src/core/action.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L37)* +*Defined in [src/core/action.ts:37](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L37)* Id of all events, from root until current (excluding current) @@ -46,7 +46,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[args](iactioncontext.md#args)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:20](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L20)* +*Defined in [src/core/actionContext.ts:20](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L20)* Event arguments in an array (action arguments for actions) @@ -58,7 +58,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[context](iactioncontext.md#context)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L15)* +*Defined in [src/core/actionContext.ts:15](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L15)* Event context (node where the action was invoked) @@ -70,7 +70,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[id](iactioncontext.md#id)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L9)* +*Defined in [src/core/actionContext.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L9)* Event unique id @@ -82,7 +82,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[name](iactioncontext.md#name)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L6)* +*Defined in [src/core/actionContext.ts:6](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L6)* Event name (action name for actions) @@ -94,7 +94,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[parentActionEvent](iactioncontext.md#parentactionevent)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L12)* +*Defined in [src/core/actionContext.ts:12](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L12)* Parent action event object @@ -104,7 +104,7 @@ ___ • **parentEvent**: *[IMiddlewareEvent](imiddlewareevent.md) | undefined* -*Defined in [packages/mobx-state-tree/src/core/action.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L32)* +*Defined in [src/core/action.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L32)* Parent event object @@ -114,7 +114,7 @@ ___ • **parentId**: *number* -*Defined in [packages/mobx-state-tree/src/core/action.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L30)* +*Defined in [src/core/action.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L30)* Parent event unique id @@ -124,7 +124,7 @@ ___ • **rootId**: *number* -*Defined in [packages/mobx-state-tree/src/core/action.ts:35](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L35)* +*Defined in [src/core/action.ts:35](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L35)* Root event unique id @@ -136,7 +136,7 @@ ___ *Inherited from [IActionContext](iactioncontext.md).[tree](iactioncontext.md#tree)* -*Defined in [packages/mobx-state-tree/src/core/actionContext.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/actionContext.ts#L17)* +*Defined in [src/core/actionContext.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/actionContext.ts#L17)* Event tree (root node of the node where the action was invoked) @@ -146,6 +146,6 @@ ___ • **type**: *[IMiddlewareEventType](../index.md#imiddlewareeventtype)* -*Defined in [packages/mobx-state-tree/src/core/action.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/action.ts#L27)* +*Defined in [src/core/action.ts:27](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/action.ts#L27)* Event type diff --git a/docs/API/interfaces/imodelreflectiondata.md b/docs/API/interfaces/imodelreflectiondata.md index bd690abb2..c556f895f 100644 --- a/docs/API/interfaces/imodelreflectiondata.md +++ b/docs/API/interfaces/imodelreflectiondata.md @@ -4,7 +4,7 @@ title: "IModelReflectionData" sidebar_label: "IModelReflectionData" --- -[mobx-state-tree - v5.2.0](../index.md) › [IModelReflectionData](imodelreflectiondata.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IModelReflectionData](imodelreflectiondata.md) ## Hierarchy @@ -29,7 +29,7 @@ sidebar_label: "IModelReflectionData" • **actions**: *string[]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:834](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L834)* +*Defined in [src/core/mst-operations.ts:834](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L834)* ___ @@ -37,7 +37,7 @@ ___ • **flowActions**: *string[]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:837](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L837)* +*Defined in [src/core/mst-operations.ts:837](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L837)* ___ @@ -47,7 +47,7 @@ ___ *Inherited from [IModelReflectionPropertiesData](imodelreflectionpropertiesdata.md).[name](imodelreflectionpropertiesdata.md#name)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:804](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L804)* +*Defined in [src/core/mst-operations.ts:804](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L804)* ___ @@ -57,7 +57,7 @@ ___ *Inherited from [IModelReflectionPropertiesData](imodelreflectionpropertiesdata.md).[properties](imodelreflectionpropertiesdata.md#properties)* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:805](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L805)* +*Defined in [src/core/mst-operations.ts:805](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L805)* #### Type declaration: @@ -69,7 +69,7 @@ ___ • **views**: *string[]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:835](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L835)* +*Defined in [src/core/mst-operations.ts:835](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L835)* ___ @@ -77,4 +77,4 @@ ___ • **volatile**: *string[]* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:836](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L836)* +*Defined in [src/core/mst-operations.ts:836](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L836)* diff --git a/docs/API/interfaces/imodelreflectionpropertiesdata.md b/docs/API/interfaces/imodelreflectionpropertiesdata.md index 088d4b941..1532c8e61 100644 --- a/docs/API/interfaces/imodelreflectionpropertiesdata.md +++ b/docs/API/interfaces/imodelreflectionpropertiesdata.md @@ -4,7 +4,7 @@ title: "IModelReflectionPropertiesData" sidebar_label: "IModelReflectionPropertiesData" --- -[mobx-state-tree - v5.2.0](../index.md) › [IModelReflectionPropertiesData](imodelreflectionpropertiesdata.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IModelReflectionPropertiesData](imodelreflectionpropertiesdata.md) ## Hierarchy @@ -25,7 +25,7 @@ sidebar_label: "IModelReflectionPropertiesData" • **name**: *string* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:804](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L804)* +*Defined in [src/core/mst-operations.ts:804](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L804)* ___ @@ -33,7 +33,7 @@ ___ • **properties**: *object* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:805](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L805)* +*Defined in [src/core/mst-operations.ts:805](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L805)* #### Type declaration: diff --git a/docs/API/interfaces/imodeltype.md b/docs/API/interfaces/imodeltype.md index d0f6ca356..82f2918fa 100644 --- a/docs/API/interfaces/imodeltype.md +++ b/docs/API/interfaces/imodeltype.md @@ -4,7 +4,7 @@ title: "IModelType" sidebar_label: "IModelType" --- -[mobx-state-tree - v5.2.0](../index.md) › [IModelType](imodeltype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IModelType](imodeltype.md) ## Type parameters @@ -55,7 +55,7 @@ sidebar_label: "IModelType" *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -67,7 +67,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -77,7 +77,7 @@ ___ • **properties**: *PROPS* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L187)* +*Defined in [src/types/complex-types/model.ts:187](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L187)* ## Methods @@ -85,7 +85,7 @@ ___ ▸ **actions**<**A**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS & A, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:201](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L201)* +*Defined in [src/types/complex-types/model.ts:201](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L201)* **Type parameters:** @@ -113,7 +113,7 @@ ___ *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -136,7 +136,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -148,7 +148,7 @@ ___ ▸ **extend**<**A**, **V**, **VS**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS & A & V & VS, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L209)* +*Defined in [src/types/complex-types/model.ts:209](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L209)* **Type parameters:** @@ -180,7 +180,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -200,7 +200,7 @@ ___ ▸ **named**(`newName`: string): *[IModelType](imodeltype.md)‹PROPS, OTHERS, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:189](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L189)* +*Defined in [src/types/complex-types/model.ts:189](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L189)* **Parameters:** @@ -216,7 +216,7 @@ ___ ▸ **postProcessSnapshot**<**NewS**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS, CustomC, NewS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:217](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L217)* +*Defined in [src/types/complex-types/model.ts:217](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L217)* **Type parameters:** @@ -242,7 +242,7 @@ ___ ▸ **preProcessSnapshot**<**NewC**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS, NewC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L213)* +*Defined in [src/types/complex-types/model.ts:213](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L213)* **Type parameters:** @@ -268,7 +268,7 @@ ___ ▸ **props**<**PROPS2**>(`props`: PROPS2): *[IModelType](imodeltype.md)‹PROPS & ModelPropertiesDeclarationToProperties‹PROPS2›, OTHERS, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:193](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L193)* +*Defined in [src/types/complex-types/model.ts:193](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L193)* **Type parameters:** @@ -290,7 +290,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. @@ -311,7 +311,7 @@ ___ ▸ **views**<**V**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS & V, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:197](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L197)* +*Defined in [src/types/complex-types/model.ts:197](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L197)* **Type parameters:** @@ -337,7 +337,7 @@ ___ ▸ **volatile**<**TP**>(`fn`: function): *[IModelType](imodeltype.md)‹PROPS, OTHERS & TP, CustomC, CustomS›* -*Defined in [packages/mobx-state-tree/src/types/complex-types/model.ts:205](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/complex-types/model.ts#L205)* +*Defined in [src/types/complex-types/model.ts:205](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/complex-types/model.ts#L205)* **Type parameters:** diff --git a/docs/API/interfaces/ipatchrecorder.md b/docs/API/interfaces/ipatchrecorder.md index 847a3cd80..d3e1b4f10 100644 --- a/docs/API/interfaces/ipatchrecorder.md +++ b/docs/API/interfaces/ipatchrecorder.md @@ -4,7 +4,7 @@ title: "IPatchRecorder" sidebar_label: "IPatchRecorder" --- -[mobx-state-tree - v5.2.0](../index.md) › [IPatchRecorder](ipatchrecorder.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IPatchRecorder](ipatchrecorder.md) ## Hierarchy @@ -32,7 +32,7 @@ sidebar_label: "IPatchRecorder" • **inversePatches**: *ReadonlyArray‹[IJsonPatch](ijsonpatch.md)›* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:138](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L138)* +*Defined in [src/core/mst-operations.ts:138](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L138)* ___ @@ -40,7 +40,7 @@ ___ • **patches**: *ReadonlyArray‹[IJsonPatch](ijsonpatch.md)›* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:137](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L137)* +*Defined in [src/core/mst-operations.ts:137](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L137)* ___ @@ -48,7 +48,7 @@ ___ • **recording**: *boolean* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:140](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L140)* +*Defined in [src/core/mst-operations.ts:140](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L140)* ___ @@ -56,7 +56,7 @@ ___ • **reversedInversePatches**: *ReadonlyArray‹[IJsonPatch](ijsonpatch.md)›* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:139](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L139)* +*Defined in [src/core/mst-operations.ts:139](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L139)* ## Methods @@ -64,7 +64,7 @@ ___ ▸ **replay**(`target?`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:143](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L143)* +*Defined in [src/core/mst-operations.ts:143](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L143)* **Parameters:** @@ -80,7 +80,7 @@ ___ ▸ **resume**(): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:142](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L142)* +*Defined in [src/core/mst-operations.ts:142](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L142)* **Returns:** *void* @@ -90,7 +90,7 @@ ___ ▸ **stop**(): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:141](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L141)* +*Defined in [src/core/mst-operations.ts:141](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L141)* **Returns:** *void* @@ -100,7 +100,7 @@ ___ ▸ **undo**(`target?`: IAnyStateTreeNode): *void* -*Defined in [packages/mobx-state-tree/src/core/mst-operations.ts:144](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/mst-operations.ts#L144)* +*Defined in [src/core/mst-operations.ts:144](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/mst-operations.ts#L144)* **Parameters:** diff --git a/docs/API/interfaces/ireversiblejsonpatch.md b/docs/API/interfaces/ireversiblejsonpatch.md index cd85e7647..d9052475f 100644 --- a/docs/API/interfaces/ireversiblejsonpatch.md +++ b/docs/API/interfaces/ireversiblejsonpatch.md @@ -4,7 +4,7 @@ title: "IReversibleJsonPatch" sidebar_label: "IReversibleJsonPatch" --- -[mobx-state-tree - v5.2.0](../index.md) › [IReversibleJsonPatch](ireversiblejsonpatch.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IReversibleJsonPatch](ireversiblejsonpatch.md) ## Hierarchy @@ -27,7 +27,7 @@ sidebar_label: "IReversibleJsonPatch" • **oldValue**: *any* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L14)* +*Defined in [src/core/json-patch.ts:14](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L14)* ___ @@ -37,7 +37,7 @@ ___ *Inherited from [IJsonPatch](ijsonpatch.md).[op](ijsonpatch.md#op)* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L8)* +*Defined in [src/core/json-patch.ts:8](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L8)* ___ @@ -47,7 +47,7 @@ ___ *Inherited from [IJsonPatch](ijsonpatch.md).[path](ijsonpatch.md#path)* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L9)* +*Defined in [src/core/json-patch.ts:9](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L9)* ___ @@ -57,4 +57,4 @@ ___ *Inherited from [IJsonPatch](ijsonpatch.md).[value](ijsonpatch.md#optional-value)* -*Defined in [packages/mobx-state-tree/src/core/json-patch.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/json-patch.ts#L10)* +*Defined in [src/core/json-patch.ts:10](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/json-patch.ts#L10)* diff --git a/docs/API/interfaces/iserializedactioncall.md b/docs/API/interfaces/iserializedactioncall.md index 07cdc6790..d773f1ab5 100644 --- a/docs/API/interfaces/iserializedactioncall.md +++ b/docs/API/interfaces/iserializedactioncall.md @@ -4,7 +4,7 @@ title: "ISerializedActionCall" sidebar_label: "ISerializedActionCall" --- -[mobx-state-tree - v5.2.0](../index.md) › [ISerializedActionCall](iserializedactioncall.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ISerializedActionCall](iserializedactioncall.md) ## Hierarchy @@ -24,7 +24,7 @@ sidebar_label: "ISerializedActionCall" • **args**? : *any[]* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:33](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L33)* +*Defined in [src/middlewares/on-action.ts:33](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L33)* ___ @@ -32,7 +32,7 @@ ___ • **name**: *string* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L31)* +*Defined in [src/middlewares/on-action.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L31)* ___ @@ -40,4 +40,4 @@ ___ • **path**? : *undefined | string* -*Defined in [packages/mobx-state-tree/src/middlewares/on-action.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/middlewares/on-action.ts#L32)* +*Defined in [src/middlewares/on-action.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/middlewares/on-action.ts#L32)* diff --git a/docs/API/interfaces/isimpletype.md b/docs/API/interfaces/isimpletype.md index 1f0a753fc..3864a3111 100644 --- a/docs/API/interfaces/isimpletype.md +++ b/docs/API/interfaces/isimpletype.md @@ -4,7 +4,7 @@ title: "ISimpleType" sidebar_label: "ISimpleType" --- -[mobx-state-tree - v5.2.0](../index.md) › [ISimpleType](isimpletype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ISimpleType](isimpletype.md) A simple type, this is, a type where the instance and the snapshot representation are the same. @@ -40,7 +40,7 @@ A simple type, this is, a type where the instance and the snapshot representatio *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -52,7 +52,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -64,7 +64,7 @@ Friendly type name. *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -87,7 +87,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -101,7 +101,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -123,7 +123,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. diff --git a/docs/API/interfaces/isnapshotprocessor.md b/docs/API/interfaces/isnapshotprocessor.md index fd5c314c8..85432566e 100644 --- a/docs/API/interfaces/isnapshotprocessor.md +++ b/docs/API/interfaces/isnapshotprocessor.md @@ -4,7 +4,7 @@ title: "ISnapshotProcessor" sidebar_label: "ISnapshotProcessor" --- -[mobx-state-tree - v5.2.0](../index.md) › [ISnapshotProcessor](isnapshotprocessor.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ISnapshotProcessor](isnapshotprocessor.md) A type that has its snapshots processed. @@ -44,7 +44,7 @@ A type that has its snapshots processed. *Inherited from [IType](itype.md).[identifierAttribute](itype.md#optional-identifierattribute)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -56,7 +56,7 @@ ___ *Inherited from [IType](itype.md).[name](itype.md#name)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -68,7 +68,7 @@ Friendly type name. *Inherited from [IType](itype.md).[create](itype.md#create)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -91,7 +91,7 @@ ___ *Inherited from [IType](itype.md).[describe](itype.md#describe)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -105,7 +105,7 @@ ___ *Inherited from [IType](itype.md).[is](itype.md#is)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -127,7 +127,7 @@ ___ *Inherited from [IType](itype.md).[validate](itype.md#validate)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. diff --git a/docs/API/interfaces/isnapshotprocessors.md b/docs/API/interfaces/isnapshotprocessors.md index 1b96dde31..c70783b84 100644 --- a/docs/API/interfaces/isnapshotprocessors.md +++ b/docs/API/interfaces/isnapshotprocessors.md @@ -4,7 +4,7 @@ title: "ISnapshotProcessors" sidebar_label: "ISnapshotProcessors" --- -[mobx-state-tree - v5.2.0](../index.md) › [ISnapshotProcessors](isnapshotprocessors.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ISnapshotProcessors](isnapshotprocessors.md) Snapshot processors. @@ -35,7 +35,7 @@ Snapshot processors. ▸ **postProcessor**(`snapshot`: S): *CustomS* -*Defined in [packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts:212](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts#L212)* +*Defined in [src/types/utility-types/snapshotProcessor.ts:212](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/snapshotProcessor.ts#L212)* Function that transforms an output snapshot. @@ -53,7 +53,7 @@ ___ ▸ **preProcessor**(`snapshot`: CustomC): *C* -*Defined in [packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts:207](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts#L207)* +*Defined in [src/types/utility-types/snapshotProcessor.ts:207](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/snapshotProcessor.ts#L207)* Function that transforms an input snapshot. diff --git a/docs/API/interfaces/itype.md b/docs/API/interfaces/itype.md index c9280b6aa..2365d2cbb 100644 --- a/docs/API/interfaces/itype.md +++ b/docs/API/interfaces/itype.md @@ -4,7 +4,7 @@ title: "IType" sidebar_label: "IType" --- -[mobx-state-tree - v5.2.0](../index.md) › [IType](itype.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IType](itype.md) A type, either complex or simple. @@ -50,7 +50,7 @@ A type, either complex or simple. • **identifierAttribute**? : *undefined | string* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L89)* +*Defined in [src/core/type/type.ts:89](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L89)* Name of the identifier attribute or null if none. @@ -60,7 +60,7 @@ ___ • **name**: *string* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L84)* +*Defined in [src/core/type/type.ts:84](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L84)* Friendly type name. @@ -70,7 +70,7 @@ Friendly type name. ▸ **create**(`snapshot?`: [C](undefined), `env?`: any): *this["Type"]* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L96)* +*Defined in [src/core/type/type.ts:96](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L96)* Creates an instance for the type given an snapshot input. @@ -91,7 +91,7 @@ ___ ▸ **describe**(): *string* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L118)* +*Defined in [src/core/type/type.ts:118](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L118)* Gets the textual representation of the type as a string. @@ -103,7 +103,7 @@ ___ ▸ **is**(`thing`: any): *thing is C | this["Type"]* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L104)* +*Defined in [src/core/type/type.ts:104](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L104)* Checks if a given snapshot / instance is of the given type. @@ -123,7 +123,7 @@ ___ ▸ **validate**(`thing`: C, `context`: [IValidationContext](../index.md#ivalidationcontext)): *[IValidationResult](../index.md#ivalidationresult)* -*Defined in [packages/mobx-state-tree/src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type.ts#L113)* +*Defined in [src/core/type/type.ts:113](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type.ts#L113)* Run's the type's typechecker on the given value with the given validation context. diff --git a/docs/API/interfaces/ivalidationcontextentry.md b/docs/API/interfaces/ivalidationcontextentry.md index f757df2cc..d1f729b06 100644 --- a/docs/API/interfaces/ivalidationcontextentry.md +++ b/docs/API/interfaces/ivalidationcontextentry.md @@ -4,7 +4,7 @@ title: "IValidationContextEntry" sidebar_label: "IValidationContextEntry" --- -[mobx-state-tree - v5.2.0](../index.md) › [IValidationContextEntry](ivalidationcontextentry.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IValidationContextEntry](ivalidationcontextentry.md) Validation context entry, this is, where the validation should run against which type @@ -25,7 +25,7 @@ Validation context entry, this is, where the validation should run against which • **path**: *string* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L17)* +*Defined in [src/core/type/type-checker.ts:17](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L17)* Subpath where the validation should be run, or an empty string to validate it all @@ -35,6 +35,6 @@ ___ • **type**: *[IAnyType](ianytype.md)* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L19)* +*Defined in [src/core/type/type-checker.ts:19](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L19)* Type to validate the subpath against diff --git a/docs/API/interfaces/ivalidationerror.md b/docs/API/interfaces/ivalidationerror.md index c4896942f..edf0ef019 100644 --- a/docs/API/interfaces/ivalidationerror.md +++ b/docs/API/interfaces/ivalidationerror.md @@ -4,7 +4,7 @@ title: "IValidationError" sidebar_label: "IValidationError" --- -[mobx-state-tree - v5.2.0](../index.md) › [IValidationError](ivalidationerror.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [IValidationError](ivalidationerror.md) Type validation error @@ -26,7 +26,7 @@ Type validation error • **context**: *[IValidationContext](../index.md#ivalidationcontext)* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:28](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L28)* +*Defined in [src/core/type/type-checker.ts:28](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L28)* Validation context @@ -36,7 +36,7 @@ ___ • **message**? : *undefined | string* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L32)* +*Defined in [src/core/type/type-checker.ts:32](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L32)* Error message @@ -46,6 +46,6 @@ ___ • **value**: *any* -*Defined in [packages/mobx-state-tree/src/core/type/type-checker.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/core/type/type-checker.ts#L30)* +*Defined in [src/core/type/type-checker.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/core/type/type-checker.ts#L30)* Value that was being validated, either a snapshot or an instance diff --git a/docs/API/interfaces/referenceoptionsgetset.md b/docs/API/interfaces/referenceoptionsgetset.md index 09fb10d59..ad687c4a6 100644 --- a/docs/API/interfaces/referenceoptionsgetset.md +++ b/docs/API/interfaces/referenceoptionsgetset.md @@ -4,7 +4,7 @@ title: "ReferenceOptionsGetSet" sidebar_label: "ReferenceOptionsGetSet" --- -[mobx-state-tree - v5.2.0](../index.md) › [ReferenceOptionsGetSet](referenceoptionsgetset.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ReferenceOptionsGetSet](referenceoptionsgetset.md) ## Type parameters @@ -27,7 +27,7 @@ sidebar_label: "ReferenceOptionsGetSet" ▸ **get**(`identifier`: [ReferenceIdentifier](../index.md#referenceidentifier), `parent`: IAnyStateTreeNode | null): *ReferenceT‹IT›* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:464](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L464)* +*Defined in [src/types/utility-types/reference.ts:442](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L442)* **Parameters:** @@ -44,7 +44,7 @@ ___ ▸ **set**(`value`: ReferenceT‹IT›, `parent`: IAnyStateTreeNode | null): *[ReferenceIdentifier](../index.md#referenceidentifier)* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:465](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L465)* +*Defined in [src/types/utility-types/reference.ts:443](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L443)* **Parameters:** diff --git a/docs/API/interfaces/referenceoptionsoninvalidated.md b/docs/API/interfaces/referenceoptionsoninvalidated.md index 840b5ee23..ea2beac43 100644 --- a/docs/API/interfaces/referenceoptionsoninvalidated.md +++ b/docs/API/interfaces/referenceoptionsoninvalidated.md @@ -4,7 +4,7 @@ title: "ReferenceOptionsOnInvalidated" sidebar_label: "ReferenceOptionsOnInvalidated" --- -[mobx-state-tree - v5.2.0](../index.md) › [ReferenceOptionsOnInvalidated](referenceoptionsoninvalidated.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [ReferenceOptionsOnInvalidated](referenceoptionsoninvalidated.md) ## Type parameters @@ -26,4 +26,4 @@ sidebar_label: "ReferenceOptionsOnInvalidated" • **onInvalidated**: *[OnReferenceInvalidated](../index.md#onreferenceinvalidated)‹ReferenceT‹IT››* -*Defined in [packages/mobx-state-tree/src/types/utility-types/reference.ts:470](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/reference.ts#L470)* +*Defined in [src/types/utility-types/reference.ts:448](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/reference.ts#L448)* diff --git a/docs/API/interfaces/unionoptions.md b/docs/API/interfaces/unionoptions.md index a02c047fe..63cf356ff 100644 --- a/docs/API/interfaces/unionoptions.md +++ b/docs/API/interfaces/unionoptions.md @@ -4,7 +4,7 @@ title: "UnionOptions" sidebar_label: "UnionOptions" --- -[mobx-state-tree - v5.2.0](../index.md) › [UnionOptions](unionoptions.md) +[mobx-state-tree - v5.3.0-alpha.1](../index.md) › [UnionOptions](unionoptions.md) ## Hierarchy @@ -23,7 +23,7 @@ sidebar_label: "UnionOptions" • **dispatcher**? : *[ITypeDispatcher](../index.md#itypedispatcher)* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L31)* +*Defined in [src/types/utility-types/union.ts:31](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L31)* ___ @@ -31,4 +31,4 @@ ___ • **eager**? : *undefined | false | true* -*Defined in [packages/mobx-state-tree/src/types/utility-types/union.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/707cb5de/packages/mobx-state-tree/src/types/utility-types/union.ts#L30)* +*Defined in [src/types/utility-types/union.ts:30](https://github.com/mobxjs/mobx-state-tree/blob/a397be56/src/types/utility-types/union.ts#L30)* diff --git a/jest.config.js b/jest.config.js new file mode 100644 index 000000000..2040f3010 --- /dev/null +++ b/jest.config.js @@ -0,0 +1,15 @@ +module.exports = { + displayName: "test", + testEnvironment: "node", + transform: { + "^.+\\.tsx?$": "ts-jest" + }, + testRegex: ".*\\.test\\.tsx?$", + moduleFileExtensions: ["ts", "tsx", "js"], + globals: { + "ts-jest": { + tsConfig: "__tests__/tsconfig.json" + } + }, + reporters: ["default", "jest-junit"] +} diff --git a/lerna.json b/lerna.json deleted file mode 100644 index 487cba5ee..000000000 --- a/lerna.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "npmClient": "yarn", - "useWorkspaces": true, - "version": "5.2.0", - "hoist": true -} diff --git a/package.json b/package.json index 004e9c52e..8207d3fbf 100644 --- a/package.json +++ b/package.json @@ -1,44 +1,120 @@ { - "private": true, - "dependencies": {}, - "scripts": { - "clean": "lerna run clean --stream", - "build": "lerna run build --stream", - "test": "lerna run test --stream", - "test:mst:dev": "cd packages/mobx-state-tree && yarn test:dev", - "test:mst:prod": "cd packages/mobx-state-tree && yarn test:prod", - "test:mst:others": "cd packages/mobx-state-tree && yarn test:others", - "test:all": "yarn test && yarn test:mst:dev && yarn test:mst:prod && yarn test:mst:others && yarn size && yarn coverage", - "size": "size-limit", - "coverage": "lerna run coverage --stream", - "release": "yarn build && lerna publish", - "tag-new-version": "lerna version", - "yarn-deduplicate": "yarn-deduplicate -s fewer yarn.lock", - "build-docs": "cd packages/mobx-state-tree && yarn build-docs && cd ../..", - "publish-docs": "yarn build-docs && cd ./website && GIT_USER=jamonholmgren USE_SSH=true yarn run publish-gh-pages", - "start": "cd website && yarn start", - "prepare": "husky install" - }, - "workspaces": [ - "packages/mobx-state-tree" - ], - "lint-staged": { - "*.{ts,tsx,js,jsx}": [ - "prettier --write" - ] - }, - "devDependencies": { - "@size-limit/preset-big-lib": "^5.0.3", - "codecov": "^3.8.3", - "cross-env": "^7.0.3", - "husky": "^7.0.0", - "lerna": "^4.0.0", - "lint-staged": "^11.1.2", - "prettier": "^2.4.1", - "size-limit": "^5.0.3", - "tslint": "^6.1.3", - "tslint-config-prettier": "^1.18.0", - "typescript": "^4.4.3", - "yarn-deduplicate": "^3.1.0" + "name": "mobx-state-tree", + "version": "5.3.0-alpha.1", + "description": "Opinionated, transactional, MobX powered state container", + "main": "dist/mobx-state-tree.js", + "umd:main": "dist/mobx-state-tree.umd.js", + "module": "dist/mobx-state-tree.module.js", + "browser": { + "./dist/mobx-state-tree.js": "./dist/mobx-state-tree.js", + "./dist/mobx-state-tree.module.js": "./dist/mobx-state-tree.module.js" + }, + "unpkg": "dist/mobx-state-tree.umd.min.js", + "jsnext:main": "dist/mobx-state-tree.module.js", + "react-native": "dist/mobx-state-tree.module.js", + "typings": "dist/index.d.ts", + "sideEffects": false, + "scripts": { + "clean": "shx rm -rf dist && shx rm -rf lib", + "build": "yarn clean && tsc && cpr lib dist --filter=\\.js$ && rollup -c", + "jest": "jest --testPathPattern=/__tests__/core/", + "jest:perf": "jest --testPathPattern=/__tests__/perf/", + "test:perf": "yarn build && yarn jest:perf && TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' /usr/bin/time node --expose-gc --require ts-node/register __tests__/perf/report.ts", + "test": "yarn test:dev && yarn test:prod", + "test:dev": "cross-env NODE_ENV=development JEST_JUNIT_OUTPUT=./test-results/dev.xml yarn jest", + "test:prod": "cross-env NODE_ENV=production JEST_JUNIT_OUTPUT=./test-results/prod.xml yarn jest", + "test:all": "yarn test && yarn test:dev && yarn test:prod && yarn size && yarn coverage", + "size": "size-limit", + "coverage": "yarn jest --coverage", + "tag-new-version": "yarn version && git push --tags", + "deduplicate": "yarn-deduplicate -s fewer yarn.lock", + "build-docs": "yarn run fix-typedoc && shx rm -rf ./docs/API && typedoc --options ./typedocconfig.js", + "publish-docs": "yarn build-docs && cd ./website && GIT_USER=jamonholmgren USE_SSH=true yarn run publish-gh-pages", + "start": "cd website && yarn start", + "prepare": "husky install", + "lint": "tslint -c ./tslint.json 'src/**/*.ts'", + "fix-typedoc": "shx rm -rf ./node_modules/typedoc/node_modules/typescript", + "prettier:list": "prettier --list-different \"src/**/*.ts\" \"__tests__/**/*.ts\"", + "prettier:check": "prettier --check \"src/**/*.ts\" \"__tests__/**/*.ts\"", + "prettier:write": "prettier --write \"src/**/*.ts\" \"__tests__/**/*.ts\"" + }, + "lint-staged": { + "*.{ts,tsx,js,jsx}": [ + "prettier --write" + ] + }, + "repository": { + "type": "git", + "url": "https://github.com/mobxjs/mobx-state-tree.git" + }, + "author": "Michel Weststrate", + "license": "MIT", + "bugs": { + "url": "https://github.com/mobxjs/mobx-state-tree/issues" + }, + "files": [ + "dist/" + ], + "devDependencies": { + "@size-limit/preset-big-lib": "^5.0.3", + "@types/jest": "^26.0.3", + "@types/node": "^12.0.2", + "codecov": "^3.8.3", + "concat": "^1.0.3", + "coveralls": "^3.1.0", + "cpr": "^3.0.1", + "cross-env": "^7.0.3", + "husky": "^7.0.0", + "jest": "^26.1.0", + "jest-junit": "^11.0.1", + "lint-staged": "^11.1.2", + "mobx": "^6.3.0", + "prettier": "^2.4.1", + "rollup": "^2.18.1", + "rollup-plugin-commonjs": "^10.0.0", + "rollup-plugin-filesize": "^9.0.1", + "rollup-plugin-node-resolve": "^5.0.0", + "rollup-plugin-replace": "^2.1.0", + "rollup-plugin-terser": "^6.1.0", + "shx": "^0.3.2", + "size-limit": "^5.0.3", + "spec.ts": "^1.1.3", + "ts-jest": "^26.1.1", + "ts-node": "^8.10.2", + "tslib": "^2.0.0", + "tslint": "^6.1.3", + "tslint-config-prettier": "^1.18.0", + "typedoc": "0.15.8", + "typedoc-plugin-markdown": "2.2.11", + "typescript": "^3.8.3", + "yarn-deduplicate": "^3.1.0" + }, + "peerDependencies": { + "mobx": "^6.3.0" + }, + "keywords": [ + "mobx", + "mobx-state-tree", + "promise", + "reactive", + "frp", + "functional-reactive-programming", + "state management" + ], + "gitHead": "27ec7ac0b0743a367fb01a7f40192f3042bd91f2", + "prettier": { + "printWidth": 100, + "tabWidth": 2, + "singleQuote": false, + "trailingComma": "none", + "semi": false + }, + "size-limit": [ + { + "path": "./dist/mobx-state-tree.min.js", + "limit": "25 KB", + "webpack": false, + "running": false } + ] } diff --git a/packages/mobx-state-tree/.gitignore b/packages/mobx-state-tree/.gitignore deleted file mode 100644 index 832a653a1..000000000 --- a/packages/mobx-state-tree/.gitignore +++ /dev/null @@ -1,11 +0,0 @@ -node_modules -*.log -lib -dist -coverage -.nyc_output -.idea -package-lock.json -/junit.xml -# copied from root folder on build -/README.md \ No newline at end of file diff --git a/packages/mobx-state-tree/.vscode/launch.json b/packages/mobx-state-tree/.vscode/launch.json deleted file mode 100644 index d197552f3..000000000 --- a/packages/mobx-state-tree/.vscode/launch.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "version": "0.2.0", - "configurations": [ - { - "type": "node", - "request": "launch", - "name": "debug unit test", - "program": "${workspaceRoot}/node_modules/.bin/jest", - "args": ["-i", "${file}"] - } - ] -} diff --git a/packages/mobx-state-tree/.vscode/tasks.json b/packages/mobx-state-tree/.vscode/tasks.json deleted file mode 100644 index 7f8015500..000000000 --- a/packages/mobx-state-tree/.vscode/tasks.json +++ /dev/null @@ -1,16 +0,0 @@ -{ - // See https://go.microsoft.com/fwlink/?LinkId=733558 - // for the documentation about the tasks.json format - "version": "0.1.0", - "command": "npm", - "isShellCommand": true, - "showOutput": "always", - "suppressTaskName": true, - "tasks": [ - { - "taskName": "build-tests", - "args": ["run", "build-tests"], - "isBuildCommand": true - } - ] -} diff --git a/packages/mobx-state-tree/__tests__/core/action.test.ts b/packages/mobx-state-tree/__tests__/core/action.test.ts deleted file mode 100644 index 6718c6895..000000000 --- a/packages/mobx-state-tree/__tests__/core/action.test.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { configure } from "mobx" -import { - recordActions, - types, - getSnapshot, - onAction, - applyPatch, - applySnapshot, - addMiddleware, - getRoot, - cast, - IMiddlewareEvent, - ISerializedActionCall, - Instance -} from "../../src" - -/// Simple action replay and invocation -const Task = types - .model({ - done: false - }) - .actions((self) => { - function toggle() { - self.done = !self.done - return self.done - } - return { - toggle - } - }) -test("it should be possible to invoke a simple action", () => { - const t1 = Task.create() - expect(t1.done).toBe(false) - expect(t1.toggle()).toBe(true) - expect(t1.done).toBe(true) -}) -test("it should be possible to record & replay a simple action", () => { - const t1 = Task.create() - const t2 = Task.create() - expect(t1.done).toBe(false) - expect(t2.done).toBe(false) - const recorder = recordActions(t1) - t1.toggle() - t1.toggle() - t1.toggle() - expect(recorder.actions).toEqual([ - { name: "toggle", path: "", args: [] }, - { name: "toggle", path: "", args: [] }, - { name: "toggle", path: "", args: [] } - ]) - recorder.replay(t2) - expect(t2.done).toBe(true) -}) -test("applying patches should be recordable and replayable", () => { - const t1 = Task.create() - const t2 = Task.create() - const recorder = recordActions(t1) - expect(t1.done).toBe(false) - applyPatch(t1, { op: "replace", path: "/done", value: true }) - expect(t1.done).toBe(true) - expect(recorder.actions).toEqual([ - { - name: "@APPLY_PATCHES", - path: "", - args: [[{ op: "replace", path: "/done", value: true }]] - } - ]) - recorder.replay(t2) - expect(t2.done).toBe(true) -}) -test("applying patches should be replacing the root store", () => { - const t1 = Task.create() - const recorder = recordActions(t1) - expect(t1.done).toBe(false) - applyPatch(t1, { op: "replace", path: "", value: { done: true } }) - expect(t1.done).toBe(true) - expect(recorder.actions).toEqual([ - { - name: "@APPLY_PATCHES", - path: "", - args: [[{ op: "replace", path: "", value: { done: true } }]] - } - ]) -}) -test("applying snapshots should be recordable and replayable", () => { - const t1 = Task.create() - const t2 = Task.create() - const recorder = recordActions(t1) - expect(t1.done).toBe(false) - applySnapshot(t1, { done: true }) - expect(t1.done).toBe(true) - expect(recorder.actions).toEqual([ - { - name: "@APPLY_SNAPSHOT", - path: "", - args: [{ done: true }] - } - ]) - recorder.replay(t2) - expect(t2.done).toBe(true) -}) -// Complex actions -const Customer = types.model("Customer", { - id: types.identifierNumber, - name: types.string -}) -const Order = types - .model("Order", { - customer: types.maybeNull(types.reference(Customer)) - }) - .actions((self) => { - function setCustomer(customer: Instance) { - self.customer = customer - } - function noopSetCustomer(_: Instance) { - // noop - } - return { - setCustomer, - noopSetCustomer - } - }) -const OrderStore = types.model("OrderStore", { - customers: types.array(Customer), - orders: types.array(Order) -}) -function createTestStore() { - const store = OrderStore.create({ - customers: [{ id: 1, name: "Mattia" }], - orders: [ - { - customer: null - } - ] - }) - onAction(store, () => {}) - return store -} -test("it should not be possible to pass a complex object", () => { - const store = createTestStore() - const recorder = recordActions(store) - expect(store.customers[0].name).toBe("Mattia") - store.orders[0].setCustomer(store.customers[0]) - expect(store.orders[0].customer!.name).toBe("Mattia") - expect(store.orders[0].customer).toBe(store.customers[0]) - expect(getSnapshot(store)).toEqual({ - customers: [ - { - id: 1, - name: "Mattia" - } - ], - orders: [ - { - customer: 1 - } - ] - }) - expect(recorder.actions).toEqual([ - { - name: "setCustomer", - path: "/orders/0", - args: [{ $MST_UNSERIALIZABLE: true, type: "[MSTNode: Customer]" }] - } - ]) -}) -if (process.env.NODE_ENV !== "production") { - test("it should not be possible to set the wrong type", () => { - const store = createTestStore() - expect(() => { - store.orders[0].setCustomer(store.orders[0] as any) - }).toThrowError( - "Error while converting to `(reference(Customer) | null)`:\n\n " + - "value of type Order: is not assignable to type: `(reference(Customer) | null)`, expected an instance of `(reference(Customer) | null)` or a snapshot like `(reference(Customer) | null?)` instead." - ) // wrong type! - }) -} -test("it should not be possible to pass the element of another tree", () => { - const store1 = createTestStore() - const store2 = createTestStore() - const recorder = recordActions(store2) - store2.orders[0].setCustomer(store1.customers[0]) - expect(recorder.actions).toEqual([ - { - name: "setCustomer", - path: "/orders/0", - args: [ - { - $MST_UNSERIALIZABLE: true, - type: "[MSTNode: Customer]" - } - ] - } - ]) -}) -test("it should not be possible to pass an unserializable object", () => { - const store = createTestStore() - const circular = { a: null as any } - circular.a = circular - const recorder = recordActions(store) - store.orders[0].noopSetCustomer(circular as any) - store.orders[0].noopSetCustomer(Buffer.from("bla") as any) - - // fix for newer node versions, which include extra data on dev mode - if ( - recorder.actions[0].args![0].type.startsWith( - "TypeError: Converting circular structure to JSON" - ) - ) { - recorder.actions[0].args![0].type = "TypeError: Converting circular structure to JSON" - } - - expect(recorder.actions).toEqual([ - { - args: [ - { - $MST_UNSERIALIZABLE: true, - type: "TypeError: Converting circular structure to JSON" - } - ], - name: "noopSetCustomer", - path: "/orders/0" - }, - { - args: [ - { - $MST_UNSERIALIZABLE: true, - type: "[object Buffer]" - } - ], - name: "noopSetCustomer", - path: "/orders/0" - } - ]) -}) -test("it should be possible to pass a complex plain object", () => { - const t1 = Task.create() - const t2 = Task.create() - const recorder = recordActions(t1) - ;(t1 as any).toggle({ bla: ["nuff", ["said"]] }) // nonsense, but serializable! - expect(recorder.actions).toEqual([ - { name: "toggle", path: "", args: [{ bla: ["nuff", ["said"]] }] } - ]) - recorder.replay(t2) - expect(t2.done).toBe(true) -}) -test("action should be bound", () => { - const task = Task.create() - const f = task.toggle - expect(f()).toBe(true) - expect(task.done).toBe(true) -}) -test("snapshot should be available and updated during an action", () => { - const Model = types - .model({ - x: types.number - }) - .actions((self) => { - function inc() { - self.x += 1 - const res = getSnapshot(self).x - self.x += 1 - return res - } - return { - inc - } - }) - const a = Model.create({ x: 2 }) - expect(a.inc()).toBe(3) - expect(a.x).toBe(4) - expect(getSnapshot(a).x).toBe(4) -}) - -test("indirectly called private functions should be able to modify state", () => { - const Model = types - .model({ - x: 3 - }) - .actions((self) => { - function incrementBy(delta: number) { - self.x += delta - } - return { - inc() { - incrementBy(1) - }, - dec() { - incrementBy(-1) - } - } - }) - const cnt = Model.create() - expect(cnt.x).toBe(3) - cnt.dec() - expect(cnt.x).toBe(2) - expect((cnt as any).incrementBy).toBe(undefined) -}) -test("volatile state survives reonciliation", () => { - const Model = types.model({ x: 3 }).actions((self) => { - let incrementor = 1 - return { - setIncrementor(value: number) { - incrementor = value - }, - inc() { - self.x += incrementor - } - } - }) - const Store = types.model({ - cnt: types.optional(Model, {}) - }) - const store = Store.create() - store.cnt.inc() - expect(store.cnt.x).toBe(4) - store.cnt.setIncrementor(3) - store.cnt.inc() - expect(store.cnt.x).toBe(7) - applySnapshot(store, { cnt: { x: 2 } }) - expect(store.cnt.x).toBe(2) - store.cnt.inc() - expect(store.cnt.x).toBe(5) // incrementor was not lost -}) -test("middleware events are correct", () => { - configure({ - useProxies: "never" - }) - - const A = types.model({}).actions((self) => ({ - a(x: number) { - return this.b(x * 2) - }, - b(y: number) { - return y + 1 - } - })) - const a = A.create() - const events: IMiddlewareEvent[] = [] - addMiddleware(a, function (call, next) { - events.push(call) - return next(call) - }) - a.a(7) - const event1 = { - args: [7], - context: {}, - id: process.env.NODE_ENV !== "production" ? 29 : 28, - name: "a", - parentId: 0, - rootId: process.env.NODE_ENV !== "production" ? 29 : 28, - allParentIds: [], - tree: {}, - type: "action", - parentEvent: undefined, - parentActionEvent: undefined - } - const event2 = { - args: [14], - context: {}, - id: process.env.NODE_ENV !== "production" ? 30 : 29, - name: "b", - parentId: process.env.NODE_ENV !== "production" ? 29 : 28, - rootId: process.env.NODE_ENV !== "production" ? 29 : 28, - allParentIds: [process.env.NODE_ENV !== "production" ? 29 : 28], - tree: {}, - type: "action", - parentEvent: event1, - parentActionEvent: event1 - } - expect(events).toEqual([event1, event2]) -}) - -test("actions are mockable", () => { - configure({ - useProxies: "never" - }) - - const M = types - .model() - .actions((self) => ({ - method(): number { - return 3 - } - })) - .views((self) => ({ - view(): number { - return 3 - } - })) - const m = M.create() - if (process.env.NODE_ENV === "production") { - expect(() => { - m.method = function () { - return 3 - } - }).toThrowError(TypeError) - expect(() => { - m.view = function () { - return 3 - } - }).toThrowError(TypeError) - } else { - m.method = function () { - return 4 - } - expect(m.method()).toBe(4) - m.view = function () { - return 4 - } - expect(m.view()).toBe(4) - } -}) - -test("after attach action should work correctly", () => { - const Todo = types - .model({ - title: "test" - }) - .actions((self) => ({ - remove() { - getRoot(self).remove(cast(self)) - } - })) - const S = types - .model({ - todos: types.array(Todo) - }) - .actions((self) => ({ - remove(todo: Instance) { - self.todos.remove(todo) - } - })) - - const s = S.create({ - todos: [{ title: "todo" }] - }) - const events: ISerializedActionCall[] = [] - onAction( - s, - (call) => { - events.push(call) - }, - true - ) - - s.todos[0].remove() - - expect(events).toEqual([ - { - args: [], - name: "remove", - path: "/todos/0" - } - ]) -}) diff --git a/packages/mobx-state-tree/__tests__/core/actionTrackingMiddleware2.test.ts b/packages/mobx-state-tree/__tests__/core/actionTrackingMiddleware2.test.ts deleted file mode 100644 index 065989e44..000000000 --- a/packages/mobx-state-tree/__tests__/core/actionTrackingMiddleware2.test.ts +++ /dev/null @@ -1,437 +0,0 @@ -import { - addMiddleware, - createActionTrackingMiddleware2, - types, - flow, - IActionTrackingMiddleware2Call -} from "../../src" - -function createTestMiddleware(m: any, actionName: string, value: number, calls: string[]) { - function checkCall(call: IActionTrackingMiddleware2Call) { - expect(call.name).toBe(actionName) - expect(call.args).toEqual([value]) - expect(call.context).toBe(m) - expect(call.env).toBe(call.id) - } - - const mware = createActionTrackingMiddleware2({ - filter(call) { - return call.name === actionName - }, - onStart(call) { - call.env = call.id // just to check env is copied properly down - calls.push(`${call.name} (${call.id}) - onStart`) - checkCall(call) - }, - onFinish(call, error) { - calls.push(`${call.name} (${call.id}) - onFinish (error: ${!!error})`) - checkCall(call) - } - }) - - addMiddleware(m, mware, false) -} - -async function doTest(m: any, mode: "success" | "fail") { - const calls: string[] = [] - - createTestMiddleware(m, "setX", 10, calls) - createTestMiddleware(m, "setY", 9, calls) - - try { - await m.setZ(8) // -> setY(9) -> setX(10) - if (mode === "fail") { - fail("should have failed") - } - } catch (e) { - if (mode === "fail") { - expect(e).toBe("error") - } else { - throw e - // fail("should have succeeded") - } - } - - return calls -} - -async function syncTest(mode: "success" | "fail") { - const M = types - .model({ - x: 1, - y: 2, - z: 3 - }) - .actions((self) => ({ - setX(v: number) { - self.x = v - if (mode === "fail") { - throw "error" - } - }, - setY(v: number) { - self.y = v - this.setX(v + 1) - }, - setZ(v: number) { - self.z = v - this.setY(v + 1) - } - })) - - const m = M.create() - - const calls = await doTest(m, mode) - - if (mode === "success") { - expect(calls).toEqual([ - "setY (2) - onStart", - "setX (3) - onStart", - "setX (3) - onFinish (error: false)", - "setY (2) - onFinish (error: false)" - ]) - } else { - expect(calls).toEqual([ - "setY (5) - onStart", - "setX (6) - onStart", - "setX (6) - onFinish (error: true)", - "setY (5) - onFinish (error: true)" - ]) - } -} - -test("sync action", async () => { - await syncTest("success") - await syncTest("fail") -}) - -async function flowTest(mode: "success" | "fail") { - const _subFlow = flow(function* subFlow() { - yield Promise.resolve() - }) - - const M = types - .model({ - x: 1, - y: 2, - z: 3 - }) - .actions((self) => ({ - setX: flow(function* flowSetX(v: number) { - yield Promise.resolve() - yield _subFlow() - self.x = v - if (mode === "fail") { - throw "error" - } - }), - setY: flow(function* flowSetY(v: number) { - self.y = v - yield (self as any).setX(v + 1) - }), - setZ: flow(function* flowSetZ(v: number) { - self.z = v - yield (self as any).setY(v + 1) - }) - })) - - const m = M.create() - - const calls = await doTest(m, mode) - - if (mode === "success") { - expect(calls).toEqual([ - "setY (9) - onStart", - "setX (11) - onStart", - "setX (11) - onFinish (error: false)", - "setY (9) - onFinish (error: false)" - ]) - } else { - expect(calls).toEqual([ - "setY (16) - onStart", - "setX (18) - onStart", - "setX (18) - onFinish (error: true)", - "setY (16) - onFinish (error: true)" - ]) - } -} - -test("flow action", async () => { - await flowTest("success") - await flowTest("fail") -}) - -test("#1250", async () => { - const M = types - .model({ - x: 0, - y: 0 - }) - .actions((self) => ({ - setX: flow(function* () { - self.x = 10 - yield new Promise((resolve) => setTimeout(resolve, 1000)) - }), - setY() { - self.y = 10 - } - })) - - const calls: string[] = [] - const mware = createActionTrackingMiddleware2({ - filter(call) { - calls.push( - `${call.name} (${call.id}) <- (${call.parentCall && call.parentCall.id}) - filter` - ) - return true - }, - onStart(call) { - calls.push( - `${call.name} (${call.id}) <- (${call.parentCall && call.parentCall.id}) - onStart` - ) - }, - onFinish(call, error) { - calls.push( - `${call.name} (${call.id}) <- (${ - call.parentCall && call.parentCall.id - }) - onFinish (error: ${!!error})` - ) - } - }) - - const model = M.create({}) - - addMiddleware(model, mware, false) - - expect(model.x).toBe(0) - expect(model.y).toBe(0) - expect(calls).toEqual([]) - - const p = model.setX() - expect(model.x).toBe(10) - expect(model.y).toBe(0) - expect(calls).toEqual([ - "setX (21) <- (undefined) - filter", - "setX (21) <- (undefined) - onStart" - ]) - calls.length = 0 - - await new Promise((r) => - setTimeout(() => { - model.setY() - r() - }, 500) - ) - expect(model.x).toBe(10) - expect(model.y).toBe(10) - expect(calls).toEqual([ - "setY (23) <- (undefined) - filter", - "setY (23) <- (undefined) - onStart", - "setY (23) <- (undefined) - onFinish (error: false)" - ]) - calls.length = 0 - - await p - expect(model.x).toBe(10) - expect(model.y).toBe(10) - expect(calls).toEqual(["setX (21) <- (undefined) - onFinish (error: false)"]) - calls.length = 0 -}) - -/** - * Test that when createActionTrackingMiddleware2 is called with valid hooks and a synchronous action, it runs onStart and onFinish hooks. - */ -test("successful execution", () => { - const M = types.model({}).actions((self) => ({ - test() {} - })) - - const calls: string[] = [] - - const mware = createActionTrackingMiddleware2({ - filter(call) { - calls.push(`${call.name} - filter`) - return true - }, - onStart(call) { - calls.push(`${call.name} - onStart`) - }, - onFinish(call, error) { - calls.push(`${call.name} - onFinish (error: ${!!error})`) - } - }) - - const model = M.create({}) - addMiddleware(model, mware, false) - - model.test() - - expect(calls).toEqual(["test - filter", "test - onStart", "test - onFinish (error: false)"]) -}) - -/** - * Test that when createActionTrackingMiddleware2 is called with valid hooks and an asynchronous action, it runs onStart and onFinish hooks. - */ -test("successful execution with async action", async () => { - const M = types.model({}).actions((self) => ({ - async test() {} - })) - - const calls: string[] = [] - - const mware = createActionTrackingMiddleware2({ - filter(call) { - calls.push(`${call.name} - filter`) - return true - }, - onStart(call) { - calls.push(`${call.name} - onStart`) - }, - onFinish(call, error) { - calls.push(`${call.name} - onFinish (error: ${!!error})`) - } - }) - - const model = M.create({}) - addMiddleware(model, mware, false) - - await model.test() - - expect(calls).toEqual(["test - filter", "test - onStart", "test - onFinish (error: false)"]) -}) - -/** - * Test the filter for createActionTrackingMiddleware2 when it passes, and when it fails. - */ -describe("filtering", () => { - /** - * Test that when the filter returns true, the action is tracked. We check - * this by checking that the onStart and onFinish hooks are called for `runThisOne`, - * which is the name provided to the `filter` function. - */ - it("calls onStart and onFinish hooks for actions that pass the filter", () => { - const M = types.model({}).actions((self) => ({ - trackThisOne() {}, - doNotTrackThisOne() {} - })) - - const calls: string[] = [] - - const mware = createActionTrackingMiddleware2({ - filter(call) { - return call.name === "trackThisOne" - }, - onStart(call) { - calls.push(`${call.name} - onStart`) - }, - onFinish(call, error) { - calls.push(`${call.name} - onFinish (error: ${!!error})`) - } - }) - - const model = M.create({}) - addMiddleware(model, mware, false) - - model.trackThisOne() - // We call this action to prove that it is not tracked since it fails - there's also a test for this below. - model.doNotTrackThisOne() - - expect(calls).toEqual(["trackThisOne - onStart", "trackThisOne - onFinish (error: false)"]) - }) - /** - * Test that when the filter returns false, the action is not tracked. We check - * this by checking that the onStart and onFinish hooks are not called for `doNotTrackThisOne`, - */ - it("does not call onStart and onFinish hooks for actions that do not pass the filter", () => { - const M = types.model({}).actions((self) => ({ - trackThisOne() {}, - doNotTrackThisOne() {} - })) - - const calls: string[] = [] - - const mware = createActionTrackingMiddleware2({ - filter(call) { - return call.name === "trackThisOne" - }, - onStart(call) { - calls.push(`${call.name} - onStart`) - }, - onFinish(call, error) { - calls.push(`${call.name} - onFinish (error: ${!!error})`) - } - }) - - const model = M.create({}) - addMiddleware(model, mware, false) - - model.doNotTrackThisOne() - - expect(calls).toEqual([]) - }) -}) - -/** - * Test that parent actions and child actions have the expected order of operations - - * if we had an action `a` that called an action `b1`, then `b2` inside `a`, the flow would be: - * - * - `filter(a)` - * - `onStart(a)` - * - `filter(b1)` - * - `onStart(b1)` - * - `onFinish(b1)` - * - `filter(b2)` - * - `onStart(b2)` - * - `onFinish(b2)` - * - `onFinish(a)` - * - * See https://mobx-state-tree.js.org/API/#createactiontrackingmiddleware2 - */ -describe("nested actions", () => { - test("complete in the expected recursive order", () => { - const M = types - .model({}) - .actions((self) => ({ - childAction1() {}, - childAction2() {} - })) - .actions((self) => ({ - parentAction() { - self.childAction1() - self.childAction2() - } - })) - - const calls: string[] = [] - - const mware = createActionTrackingMiddleware2({ - filter(call) { - calls.push(`${call.name} - filter`) - return true - }, - onStart(call) { - calls.push(`${call.name} - onStart`) - }, - onFinish(call, error) { - calls.push(`${call.name} - onFinish (error: ${!!error})`) - } - }) - - const model = M.create({}) - addMiddleware(model, mware, false) - - model.parentAction() - - expect(calls).toEqual([ - "parentAction - filter", - "parentAction - onStart", - "childAction1 - filter", - "childAction1 - onStart", - "childAction1 - onFinish (error: false)", - "childAction2 - filter", - "childAction2 - onStart", - "childAction2 - onFinish (error: false)", - "parentAction - onFinish (error: false)" - ]) - }) -}) diff --git a/packages/mobx-state-tree/__tests__/core/array.test.ts b/packages/mobx-state-tree/__tests__/core/array.test.ts deleted file mode 100644 index ef2cfaf78..000000000 --- a/packages/mobx-state-tree/__tests__/core/array.test.ts +++ /dev/null @@ -1,569 +0,0 @@ -import { - unprotect, - onSnapshot, - onPatch, - clone, - isAlive, - applyPatch, - getPath, - applySnapshot, - getSnapshot, - types, - IJsonPatch, - setLivelinessChecking, - detach, - cast -} from "../../src" -import { observable, autorun, configure } from "mobx" - -const createTestFactories = () => { - const ItemFactory = types.optional( - types.model({ - to: "world" - }), - {} - ) - const Factory = types.array(ItemFactory) - return { Factory, ItemFactory } -} -// === FACTORY TESTS === -test("it should create a factory", () => { - const { Factory } = createTestFactories() - expect(getSnapshot(Factory.create())).toEqual([]) -}) -test("it should succeed if not optional and no default provided", () => { - const Factory = types.array(types.string) - expect(getSnapshot(Factory.create())).toEqual([]) -}) -test("it should restore the state from the snapshot", () => { - configure({ - useProxies: "never" - }) - - const { Factory } = createTestFactories() - const instance = Factory.create([{ to: "universe" }]) - expect(getSnapshot(instance)).toEqual([{ to: "universe" }]) - expect("" + instance).toBe("AnonymousModel@/0") // just the normal to string -}) -// === SNAPSHOT TESTS === -test("it should emit snapshots", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let snapshots: typeof Factory.SnapshotType[] = [] - onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) - doc.push(ItemFactory.create()) - expect(snapshots).toEqual([[{ to: "world" }]]) -}) -test("it should apply snapshots", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applySnapshot(doc, [{ to: "universe" }]) - expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) -}) -test("it should return a snapshot", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.push(ItemFactory.create()) - expect(getSnapshot(doc)).toEqual([{ to: "world" }]) -}) -// === PATCHES TESTS === -test("it should emit add patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.push(ItemFactory.create({ to: "universe" })) - expect(patches).toEqual([{ op: "add", path: "/0", value: { to: "universe" } }]) -}) -test("it should apply an add patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, { op: "add", path: "/0", value: { to: "universe" } }) - expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) -}) -test("it should emit update patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.push(ItemFactory.create()) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc[0] = ItemFactory.create({ to: "universe" }) - expect(patches).toEqual([{ op: "replace", path: "/0", value: { to: "universe" } }]) -}) -test("it should apply an update patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, { op: "replace", path: "/0", value: { to: "universe" } }) - expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) -}) -test("it should emit remove patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.push(ItemFactory.create()) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.splice(0) - expect(patches).toEqual([{ op: "remove", path: "/0" }]) -}) -test("it should apply a remove patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.push(ItemFactory.create()) - doc.push(ItemFactory.create({ to: "universe" })) - applyPatch(doc, { op: "remove", path: "/0" }) - expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) -}) -test("it should apply patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, [ - { op: "add", path: "/0", value: { to: "mars" } }, - { op: "replace", path: "/0", value: { to: "universe" } } - ]) - expect(getSnapshot(doc)).toEqual([{ to: "universe" }]) -}) -// === TYPE CHECKS === -test("it should check the type correctly", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - expect(Factory.is(doc)).toEqual(true) - expect(Factory.is([])).toEqual(true) - expect(Factory.is({})).toEqual(false) - expect(Factory.is([{ to: "mars" }])).toEqual(true) - expect(Factory.is([{ wrongKey: true }])).toEqual(true) - expect(Factory.is([{ to: true }])).toEqual(false) -}) -test("paths shoud remain correct when splicing", () => { - const Task = types.model("Task", { - done: false - }) - const store = types - .model({ - todos: types.array(Task) - }) - .create({ - todos: [{}] - }) - unprotect(store) - expect(store.todos.map(getPath)).toEqual(["/todos/0"]) - store.todos.push({}) - expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) - store.todos.unshift({}) - expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) - store.todos.splice(0, 2) - expect(store.todos.map(getPath)).toEqual(["/todos/0"]) - store.todos.splice(0, 1, {}, {}, {}) - expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) - store.todos.remove(store.todos[1]) - expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) -}) -test("items should be reconciled correctly when splicing - 1", () => { - configure({ - useProxies: "never" - }) - - const Task = types.model("Task", { - x: types.string - }) - const a = Task.create({ x: "a" }), - b = Task.create({ x: "b" }), - c = Task.create({ x: "c" }), - d = Task.create({ x: "d" }) - const store = types - .model({ - todos: types.array(Task) - }) - .create({ - todos: [a] - }) - unprotect(store) - expect(store.todos.slice()).toEqual([a]) - expect(isAlive(a)).toBe(true) - store.todos.push(b) - expect(store.todos.slice()).toEqual([a, b]) - store.todos.unshift(c) - expect(store.todos.slice()).toEqual([c, a, b]) - store.todos.splice(0, 2) - expect(store.todos.slice()).toEqual([b]) - expect(isAlive(a)).toBe(false) - expect(isAlive(b)).toBe(true) - expect(isAlive(c)).toBe(false) - - setLivelinessChecking("error") - expect(() => store.todos.splice(0, 1, a, c, d)).toThrowError( - "You are trying to read or write to an object that is no longer part of a state tree. (Object type: 'Task', Path upon death: '/todos/1', Subpath: '', Action: ''). Either detach nodes first, or don't use objects after removing / replacing them in the tree." - ) - store.todos.splice(0, 1, clone(a), clone(c), clone(d)) - expect(store.todos.map((_) => _.x)).toEqual(["a", "c", "d"]) -}) -test("items should be reconciled correctly when splicing - 2", () => { - const Task = types.model("Task", { - x: types.string - }) - const a = Task.create({ x: "a" }), - b = Task.create({ x: "b" }), - c = Task.create({ x: "c" }), - d = Task.create({ x: "d" }) - const store = types - .model({ - todos: types.array(Task) - }) - .create({ - todos: [a, b, c, d] - }) - unprotect(store) - store.todos.splice(2, 1, { x: "e" }, { x: "f" }) - // becomes, a, b, e, f, d - expect(store.todos.length).toBe(5) - expect(store.todos[0] === a).toBe(true) - expect(store.todos[1] === b).toBe(true) - expect(store.todos[2] !== c).toBe(true) - expect(store.todos[2].x).toBe("e") - expect(store.todos[3] !== d).toBe(true) - expect(store.todos[3].x).toBe("f") - expect(store.todos[4] === d).toBe(true) // preserved and moved - expect(store.todos[4].x).toBe("d") - expect(store.todos.map(getPath)).toEqual([ - "/todos/0", - "/todos/1", - "/todos/2", - "/todos/3", - "/todos/4" - ]) - store.todos.splice(1, 3, { x: "g" }) - // becomes a, g, d - expect(store.todos.length).toBe(3) - expect(store.todos[0] === a).toBe(true) - expect(store.todos[1].x).toBe("g") - expect(store.todos[2].x).toBe("d") - expect(store.todos[1] !== b).toBe(true) - expect(store.todos[2] === d).toBe(true) // still original d - expect(store.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) -}) -test("it should reconciliate keyed instances correctly", () => { - const Store = types.model({ - todos: types.optional( - types.array( - types.model("Task", { - id: types.identifier, - task: "", - done: false - }) - ), - [] - ) - }) - const store = Store.create({ - todos: [ - { id: "1", task: "coffee", done: false }, - { id: "2", task: "tea", done: false }, - { id: "3", task: "biscuit", done: false } - ] - }) - expect(store.todos.map((todo) => todo.task)).toEqual(["coffee", "tea", "biscuit"]) - expect(store.todos.map((todo) => todo.done)).toEqual([false, false, false]) - expect(store.todos.map((todo) => todo.id)).toEqual(["1", "2", "3"]) - const coffee = store.todos[0] - const tea = store.todos[1] - const biscuit = store.todos[2] - applySnapshot(store, { - todos: [ - { id: "2", task: "Tee", done: true }, - { id: "1", task: "coffee", done: true }, - { id: "4", task: "biscuit", done: false }, - { id: "5", task: "stuffz", done: false } - ] - }) - expect(store.todos.map((todo) => todo.task)).toEqual(["Tee", "coffee", "biscuit", "stuffz"]) - expect(store.todos.map((todo) => todo.done)).toEqual([true, true, false, false]) - expect(store.todos.map((todo) => todo.id)).toEqual(["2", "1", "4", "5"]) - expect(store.todos[0] === tea).toBe(true) - expect(store.todos[1] === coffee).toBe(true) - expect(store.todos[2] === biscuit).toBe(false) -}) -test("it correctly reconciliate when swapping", () => { - const Task = types.model("Task", {}) - const Store = types.model({ - todos: types.optional(types.array(Task), []) - }) - const s = Store.create() - unprotect(s) - const a = Task.create() - const b = Task.create() - s.todos.push(a, b) - s.todos.replace([b, a]) - expect(s.todos[0] === b).toBe(true) - expect(s.todos[1] === a).toBe(true) - expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) -}) -test("it correctly reconciliate when swapping using snapshots", () => { - const Task = types.model("Task", {}) - const Store = types.model({ - todos: types.array(Task) - }) - const s = Store.create() - unprotect(s) - const a = Task.create() - const b = Task.create() - s.todos.push(a, b) - s.todos.replace([getSnapshot(b), getSnapshot(a)]) - expect(s.todos[0] === b).toBe(true) - expect(s.todos[1] === a).toBe(true) - expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1"]) - s.todos.push({}) - expect(s.todos[0] === b).toBe(true) - expect(s.todos[1] === a).toBe(true) - expect(s.todos.map(getPath)).toEqual(["/todos/0", "/todos/1", "/todos/2"]) -}) -test("it should not be allowed to add the same item twice to the same store", () => { - const Task = types.model("Task", {}) - const Store = types.model({ - todos: types.optional(types.array(Task), []) - }) - const s = Store.create() - unprotect(s) - const a = Task.create() - s.todos.push(a) - expect(() => { - s.todos.push(a) - }).toThrowError( - "Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/todos/1', but it lives already at '/todos/0'" - ) - const b = Task.create() - expect(() => { - s.todos.push(b, b) - }).toThrowError( - "Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/todos/2', but it lives already at '/todos/1'" - ) -}) -test("it should support observable arrays", () => { - const TestArray = types.array(types.number) - const testArray = TestArray.create(observable([1, 2])) - expect(testArray[0] === 1).toBe(true) - expect(testArray.length === 2).toBe(true) - expect(Array.isArray(testArray.slice())).toBe(true) -}) - -test("it should support observable arrays, array should be real when useProxies eq 'always'", () => { - configure({ - useProxies: "always" - }) - - const TestArray = types.array(types.number) - const testArray = TestArray.create(observable([1, 2])) - expect(testArray[0] === 1).toBe(true) - expect(testArray.length === 2).toBe(true) - expect(Array.isArray(testArray)).toBe(true) -}) - -test("it should support observable arrays, array should be not real when useProxies eq 'never'", () => { - configure({ - useProxies: "never" - }) - - const TestArray = types.array(types.number) - const testArray = TestArray.create(observable([1, 2])) - expect(testArray[0] === 1).toBe(true) - expect(testArray.length === 2).toBe(true) - expect(Array.isArray(testArray.slice())).toBe(true) - expect(Array.isArray(testArray)).toBe(false) -}) - -test("it should correctly handle re-adding of the same objects", () => { - const Store = types - .model("Task", { - objects: types.array(types.maybe(types.frozen())) - }) - .actions((self) => ({ - setObjects(objects: {}[]) { - self.objects.replace(objects) - } - })) - const store = Store.create({ - objects: [] - }) - expect(store.objects.slice()).toEqual([]) - const someObject = {} - store.setObjects([someObject]) - expect(store.objects.slice()).toEqual([someObject]) - store.setObjects([someObject]) - expect(store.objects.slice()).toEqual([someObject]) -}) -test("it should work correctly for splicing primitive array", () => { - const store = types.array(types.number).create([1, 2, 3]) - unprotect(store) - store.splice(0, 1) - expect(store.slice()).toEqual([2, 3]) - store.unshift(1) - expect(store.slice()).toEqual([1, 2, 3]) - store.replace([4, 5]) - expect(store.slice()).toEqual([4, 5]) - store.clear() - expect(store.slice()).toEqual([]) -}) -test("it should keep unchanged for structrual equalled snapshot", () => { - const Store = types.model({ - todos: types.array( - types.model("Task", { - id: types.identifier, - task: "", - done: false - }) - ), - numbers: types.array(types.number) - }) - const store = Store.create({ - todos: [ - { id: "1", task: "coffee", done: false }, - { id: "2", task: "tea", done: false }, - { id: "3", task: "biscuit", done: false } - ], - numbers: [1, 2, 3] - }) - - const values: boolean[][] = [] - autorun(() => { - values.push(store.todos.map((todo) => todo.done)) - }) - applySnapshot(store.todos, [ - { id: "1", task: "coffee", done: false }, - { id: "2", task: "tea", done: false }, - { id: "3", task: "biscuit", done: true } - ]) - applySnapshot(store.todos, [ - { id: "1", task: "coffee", done: false }, - { id: "2", task: "tea", done: false }, - { id: "3", task: "biscuit", done: true } - ]) - expect(values).toEqual([ - [false, false, false], - [false, false, true] - ]) - - const values1: number[][] = [] - autorun(() => { - values1.push(store.numbers.slice()) - }) - applySnapshot(store.numbers, [1, 2, 4]) - applySnapshot(store.numbers, [1, 2, 4]) - expect(values1).toEqual([ - [1, 2, 3], - [1, 2, 4] - ]) -}) - -// === OPERATIONS TESTS === -test("#1105 - it should return pop/shift'ed values for scalar arrays", () => { - const ScalarArray = types - .model({ - array: types.array(types.number) - }) - .actions((self) => { - return { - shift() { - return self.array.shift() - } - } - }) - - const test = ScalarArray.create({ array: [3, 5] }) - - expect(test.shift()).toEqual(3) - expect(test.shift()).toEqual(5) -}) - -test("it should return pop/shift'ed values for object arrays", () => { - const TestObject = types.model({ id: types.string }) - const ObjectArray = types - .model({ - array: types.array(TestObject) - }) - .actions((self) => { - return { - shift() { - return self.array.shift() - }, - pop() { - return self.array.pop() - } - } - }) - - const test = ObjectArray.create({ - array: [{ id: "foo" }, { id: "mid" }, { id: "bar" }] - }) - - const foo = test.shift()! - expect(isAlive(foo)).toBe(false) - const bar = test.pop()! - expect(isAlive(bar)).toBe(false) - - // we have to use clone or getSnapshot to access dead nodes data - expect(clone(foo)).toEqual({ id: "foo" }) - expect(getSnapshot(bar)).toEqual({ id: "bar" }) -}) - -test("#1173 - detaching an array should not eliminate its children", () => { - const M = types.model({}) - const AM = types.array(M) - const Store = types.model({ items: AM }) - const s = Store.create({ items: [{}, {}, {}] }) - const n0 = s.items[0] - - unprotect(s) - - const detachedItems = detach(s.items) - expect(s.items).not.toBe(detachedItems) - expect(s.items.length).toBe(0) - expect(detachedItems.length).toBe(3) - expect(detachedItems[0]).toBe(n0) -}) - -test("initializing an array instance from another array instance should end up in the same instance", () => { - const A = types.array(types.number) - const a1 = A.create([1, 2, 3]) - const a2 = A.create(a1) - expect(a1).toBe(a2) - expect(getSnapshot(a1)).toEqual([1, 2, 3]) -}) - -test("assigning filtered instances works", () => { - const Task = types.model("Task", { - done: false - }) - const store = types - .model({ - todos: types.array(Task) - }) - .actions((self) => ({ - clearFinishedTodos() { - self.todos = cast(self.todos.filter((todo) => !todo.done)) - } - })) - .create({ - todos: [{ done: true }, { done: false }, { done: true }] - }) - - expect(store.todos.length).toBe(3) - const done = store.todos.filter((t) => t.done) - const notDone = store.todos.filter((t) => !t.done) - expect(store.todos.every((t) => isAlive(t))) - store.clearFinishedTodos() - expect(store.todos.length).toBe(1) - expect(store.todos[0]).toBe(notDone[0]) - expect(done.every((t) => !isAlive(t))).toBe(true) - expect(notDone.every((t) => isAlive(t))).toBe(true) -}) - -test("#1676 - should accept read-only arrays", () => { - const ArrayType = types.array(types.string) - const data = ["foo", "bar"] as const - const instance = ArrayType.create(data) - expect(getSnapshot(instance)).toEqual(["foo", "bar"]) -}) diff --git a/packages/mobx-state-tree/__tests__/core/async.test.ts b/packages/mobx-state-tree/__tests__/core/async.test.ts deleted file mode 100644 index c65ebc0ac..000000000 --- a/packages/mobx-state-tree/__tests__/core/async.test.ts +++ /dev/null @@ -1,438 +0,0 @@ -import { configure, reaction } from "mobx" -import { - addMiddleware, - decorate, - destroy, - flow, - IMiddlewareEvent, - IMiddlewareEventType, - IMiddlewareHandler, - recordActions, - toGenerator, - // TODO: export IRawActionCall - toGeneratorFunction, - types -} from "../../src" - -function delay(time: number, value: TV, shouldThrow = false): Promise { - return new Promise((resolve, reject) => { - setTimeout(() => { - if (shouldThrow) reject(value) - else resolve(value) - }, time) - }) -} - -function testCoffeeTodo( - done: () => void, - generator: ( - self: any - ) => (str: string) => Generator, string | void | undefined, undefined>, - shouldError: boolean, - resultValue: string | undefined, - producedCoffees: any[] -) { - configure({ enforceActions: "observed" }) - const Todo = types - .model({ - title: "get coffee" - }) - .actions((self) => ({ - startFetch: flow(generator(self)) - })) - const events: IMiddlewareEvent[] = [] - const coffees: any[] = [] - const t1 = Todo.create({}) - addMiddleware(t1, (c, next) => { - events.push(c) - return next(c) - }) - reaction( - () => t1.title, - (coffee) => coffees.push(coffee) - ) - function handleResult(res: string | undefined | void) { - expect(res).toBe(resultValue) - expect(coffees).toEqual(producedCoffees) - const filtered = filterRelevantStuff(events) - expect(filtered).toMatchSnapshot() - configure({ enforceActions: "never" }) - done() - } - t1.startFetch("black").then( - (r) => { - expect(shouldError).toBe(false) - handleResult(r) - }, - (r) => { - expect(shouldError).toBe(true) - handleResult(r) - } - ) -} -test("flow happens in single ticks", (done) => { - const X = types - .model({ - y: 1 - }) - .actions((self) => ({ - p: flow(function* () { - self.y++ - self.y++ - yield delay(1, true, false) - self.y++ - self.y++ - }) - })) - const x = X.create() - const values: number[] = [] - reaction( - () => x.y, - (v) => values.push(v) - ) - x.p().then(() => { - expect(x.y).toBe(5) - expect(values).toEqual([3, 5]) - done() - }) -}) -test("can handle async actions", (done) => { - testCoffeeTodo( - done, - (self) => - function* fetchData(kind: string) { - self.title = "getting coffee " + kind - self.title = yield delay(100, "drinking coffee") - return "awake" - }, - false, - "awake", - ["getting coffee black", "drinking coffee"] - ) -}) -test("can handle erroring actions", (done) => { - testCoffeeTodo( - done, - (self) => - function* fetchData(kind: string) { - throw kind - }, - true, - "black", - [] - ) -}) -test("can handle try catch", (t) => { - testCoffeeTodo( - t, - (self) => - function* fetchData(kind: string) { - try { - yield delay(10, "tea", true) - return undefined - } catch (e) { - self.title = e - return "biscuit" - } - }, - false, - "biscuit", - ["tea"] - ) -}) -test("empty sequence works", (t) => { - testCoffeeTodo(t, () => function* fetchData(kind: string) {}, false, undefined, []) -}) -test("can handle throw from yielded promise works", (t) => { - testCoffeeTodo( - t, - () => - function* fetchData(kind: string) { - yield delay(10, "x", true) - }, - true, - "x", - [] - ) -}) -test("typings", (done) => { - const M = types.model({ title: types.string }).actions((self) => { - function* a(x: string) { - yield delay(10, "x", false) - self.title = "7" - return 23 - } - // tslint:disable-next-line:no-shadowed-variable - const b = flow(function* b(x: string) { - yield delay(10, "x", false) - self.title = "7" - return 24 - }) - return { a: flow(a), b } - }) - const m1 = M.create({ title: "test " }) - const resA = m1.a("z") - const resB = m1.b("z") - Promise.all([resA, resB]).then(([x1, x2]) => { - expect(x1).toBe(23) - expect(x2).toBe(24) - done() - }) -}) -test("typings", (done) => { - const M = types.model({ title: types.string }).actions((self) => { - function* a(x: string) { - yield delay(10, "x", false) - self.title = "7" - return 23 - } - // tslint:disable-next-line:no-shadowed-variable - const b = flow(function* b(x: string) { - yield delay(10, "x", false) - self.title = "7" - return 24 - }) - return { a: flow(a), b } - }) - const m1 = M.create({ title: "test " }) - const resA = m1.a("z") - const resB = m1.b("z") - Promise.all([resA, resB]).then(([x1, x2]) => { - expect(x1).toBe(23) - expect(x2).toBe(24) - done() - }) -}) -test("recordActions should only emit invocation", (done) => { - let calls = 0 - const M = types - .model({ - title: types.string - }) - .actions((self) => { - function* a(x: string) { - yield delay(10, "x", false) - calls++ - return 23 - } - return { - a: flow(a) - } - }) - const m1 = M.create({ title: "test " }) - const recorder = recordActions(m1) - m1.a("x").then(() => { - recorder.stop() - expect(recorder.actions).toEqual([ - { - args: ["x"], - name: "a", - path: "" - } - ]) - expect(calls).toBe(1) - recorder.replay(m1) - setTimeout(() => { - expect(calls).toBe(2) - done() - }, 50) - }) -}) -test("can handle nested async actions", (t) => { - // tslint:disable-next-line:no-shadowed-variable - const uppercase = flow(function* uppercase(value: string) { - const res = yield delay(20, value.toUpperCase()) - return res - }) - testCoffeeTodo( - t, - (self) => - function* fetchData(kind: string) { - self.title = yield uppercase("drinking " + kind) - return self.title - }, - false, - "DRINKING BLACK", - ["DRINKING BLACK"] - ) -}) -test("can handle nested async actions when using decorate", (done) => { - const events: [IMiddlewareEventType, string][] = [] - const middleware: IMiddlewareHandler = (call, next) => { - events.push([call.type, call.name]) - return next(call) - } - // tslint:disable-next-line:no-shadowed-variable - const uppercase = flow(function* uppercase(value: string) { - const res = yield delay(20, value.toUpperCase()) - return res - }) - const Todo = types.model({}).actions((self) => { - // tslint:disable-next-line:no-shadowed-variable - const act = flow(function* act(value: string) { - return yield uppercase(value) - }) - return { act: decorate(middleware, act) } - }) - Todo.create() - .act("x") - .then((res) => { - expect(res).toBe("X") - expect(events).toEqual([ - ["action", "act"], - ["flow_spawn", "act"], - ["flow_resume", "act"], - ["flow_resume", "act"], - ["flow_return", "act"] - ]) - done() - }) -}) - -test("flow gain back control when node become not alive during yield", async () => { - expect.assertions(2) - const rejectError = new Error("Reject Error") - const MyModel = types.model({}).actions(() => { - return { - doAction() { - return flow(function* () { - try { - yield delay(20, "").then(() => Promise.reject(rejectError)) - } catch (e) { - expect(e).toEqual(rejectError) - throw e - } - })() - } - } - }) - - const m = MyModel.create({}) - const p = m.doAction() - destroy(m) - try { - await p - } catch (e) { - expect(e).toEqual(rejectError) - } -}) - -function filterRelevantStuff(stuff: IMiddlewareEvent[]) { - return stuff.map((x: any) => { - delete x.context - delete x.tree - return x - }) -} - -test("flow typings", async () => { - const promise = Promise.resolve() - - const M = types.model({ x: 5 }).actions((self) => ({ - // should be () => Promise - voidToVoid: flow(function* () { - yield promise - }), // should be (val: number) => Promise - numberToNumber: flow(function* (val: number) { - yield promise - return val - }), // should be () => Promise - voidToNumber: flow(function* () { - yield promise - return Promise.resolve(2) - }) - })) - - const m = M.create() - - // these should compile - const a: void = await m.voidToVoid() - expect(a).toBe(undefined) - const b: number = await m.numberToNumber(4) - expect(b).toBe(4) - const c: number = await m.voidToNumber() - expect(c).toBe(2) - await m.voidToNumber().then((d) => { - const _d: number = d - expect(_d).toBe(2) - }) -}) - -/** - * Detect explicit `any` type. - * https://stackoverflow.com/a/55541672/4289902 - */ -type IfAny = 0 extends 1 & T ? Y : N - -/** - * Ensure that the type of the passed value is of the expected type, and is NOT the TypeScript `any` type - */ -function ensureNotAnyType(value: IfAny) {} - -test("yield* typings for toGeneratorFunction", async () => { - const voidPromise = () => Promise.resolve() - const numberPromise = () => Promise.resolve(7) - const stringWithArgsPromise = (input1: string, input2: boolean) => - Promise.resolve("test-result") - - const voidGen = toGeneratorFunction(voidPromise) - const numberGen = toGeneratorFunction(numberPromise) - const stringWithArgsGen = toGeneratorFunction(stringWithArgsPromise) - - const M = types.model({ x: 5 }).actions((self) => { - function* testAction() { - const voidResult = yield* voidGen() - ensureNotAnyType(voidResult) - - const numberResult = yield* numberGen() - ensureNotAnyType(numberResult) - - const stringResult = yield* stringWithArgsGen("input", true) - ensureNotAnyType(stringResult) - - return stringResult - } - - return { - testAction: flow(testAction) - } - }) - - const m = M.create() - - const result = await m.testAction() - ensureNotAnyType(result) - expect(result).toBe("test-result") -}) - -test("yield* typings for toGenerator", async () => { - const voidPromise = () => Promise.resolve() - const numberPromise = () => Promise.resolve(7) - const stringWithArgsPromise = (input1: string, input2: boolean) => - Promise.resolve("test-result") - - const M = types.model({ x: 5 }).actions((self) => { - function* testAction() { - const voidResult = yield* toGenerator(voidPromise()) - ensureNotAnyType(voidResult) - - const numberResult = yield* toGenerator(numberPromise()) - ensureNotAnyType(numberResult) - - const stringResult = yield* toGenerator(stringWithArgsPromise("input", true)) - ensureNotAnyType(stringResult) - - return stringResult - } - - return { - testAction: flow(testAction) - } - }) - - const m = M.create() - - const result = await m.testAction() - ensureNotAnyType(result) - expect(result).toBe("test-result") -}) diff --git a/packages/mobx-state-tree/__tests__/core/boxes-store.test.ts b/packages/mobx-state-tree/__tests__/core/boxes-store.test.ts deleted file mode 100644 index 92e10f248..000000000 --- a/packages/mobx-state-tree/__tests__/core/boxes-store.test.ts +++ /dev/null @@ -1,167 +0,0 @@ -/** - * Based on examples/boxes/domain-state.js - */ -import { values } from "mobx" -import { - types, - getParent, - hasParent, - recordPatches, - unprotect, - getSnapshot, - Instance -} from "../../src" - -export const Box = types - .model("Box", { - id: types.identifier, - name: "", - x: 0, - y: 0 - }) - .views((self) => ({ - get width() { - return self.name.length * 15 - }, - get isSelected(): boolean { - if (!hasParent(self)) return false - return getParent(getParent(self)).selection === self - } - })) - .actions((self) => { - function move(dx: number, dy: number) { - self.x += dx - self.y += dy - } - function setName(newName: string) { - self.name = newName - } - return { - move, - setName - } - }) -export const Arrow = types.model("Arrow", { - id: types.identifier, - from: types.reference(Box), - to: types.reference(Box) -}) -export const Store = types - .model("Store", { - boxes: types.map(Box), - arrows: types.array(Arrow), - selection: types.reference(Box) - }) - .actions((self) => { - function afterCreate() { - unprotect(self) - } - function addBox(id: string, name: string, x: number, y: number) { - const box = Box.create({ name, x, y, id }) - self.boxes.put(box) - return box - } - function addArrow(id: string, from: string, to: string) { - self.arrows.push(Arrow.create({ id, from, to })) - } - function setSelection(selection: Instance) { - self.selection = selection - } - function createBox( - id: string, - name: string, - x: number, - y: number, - source: Instance | null | undefined, - arrowId: string | null - ) { - const box = addBox(id, name, x, y) - setSelection(box) - if (source) addArrow(arrowId!, source.id, box.id) - } - return { - afterCreate, - addBox, - addArrow, - setSelection, - createBox - } - }) -function createStore() { - return Store.create({ - boxes: { - cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, - aa: { id: "aa", name: "Bratislava", x: 650, y: 300 } - }, - arrows: [{ id: "dd", from: "cc", to: "aa" }], - selection: "aa" - }) -} -test("store is deserialized correctly", () => { - const s = createStore() - expect(s.boxes.size).toBe(2) - expect(s.arrows.length).toBe(1) - expect(s.selection === s.boxes.get("aa")).toBe(true) - expect(s.arrows[0].from.name).toBe("Rotterdam") - expect(s.arrows[0].to.name).toBe("Bratislava") - expect(values(s.boxes).map((b) => b.isSelected)).toEqual([false, true]) -}) -test("store emits correct patch paths", () => { - const s = createStore() - const recorder1 = recordPatches(s) - const recorder2 = recordPatches(s.boxes) - const recorder3 = recordPatches(s.boxes.get("cc")!) - s.arrows[0].from.x += 117 - expect(recorder1.patches).toEqual([{ op: "replace", path: "/boxes/cc/x", value: 217 }]) - expect(recorder2.patches).toEqual([{ op: "replace", path: "/cc/x", value: 217 }]) - expect(recorder3.patches).toEqual([{ op: "replace", path: "/x", value: 217 }]) -}) -test("box operations works correctly", () => { - const s = createStore() - s.createBox("a", "A", 0, 0, null, null) - s.createBox("b", "B", 100, 100, s.boxes.get("aa"), "aa2b") - expect(getSnapshot(s)).toEqual({ - boxes: { - cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, - aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, - a: { id: "a", name: "A", x: 0, y: 0 }, - b: { id: "b", name: "B", x: 100, y: 100 } - }, - arrows: [ - { id: "dd", from: "cc", to: "aa" }, - { id: "aa2b", from: "aa", to: "b" } - ], - selection: "b" - }) - s.boxes.get("a")!.setName("I'm groot") - expect(getSnapshot(s)).toEqual({ - boxes: { - cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, - aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, - a: { id: "a", name: "I'm groot", x: 0, y: 0 }, - b: { id: "b", name: "B", x: 100, y: 100 } - }, - arrows: [ - { id: "dd", from: "cc", to: "aa" }, - { id: "aa2b", from: "aa", to: "b" } - ], - selection: "b" - }) - expect(JSON.stringify(s)).toEqual(JSON.stringify(getSnapshot(s))) - s.boxes.get("a")!.move(50, 50) - expect(getSnapshot(s)).toEqual({ - boxes: { - cc: { id: "cc", name: "Rotterdam", x: 100, y: 100 }, - aa: { id: "aa", name: "Bratislava", x: 650, y: 300 }, - a: { id: "a", name: "I'm groot", x: 50, y: 50 }, - b: { id: "b", name: "B", x: 100, y: 100 } - }, - arrows: [ - { id: "dd", from: "cc", to: "aa" }, - { id: "aa2b", from: "aa", to: "b" } - ], - selection: "b" - }) - expect(s.boxes.get("b")!.width).toBe(15) - expect(Box.create({ id: "hello" }).isSelected).toBe(false) -}) diff --git a/packages/mobx-state-tree/__tests__/core/circular1.test.ts b/packages/mobx-state-tree/__tests__/core/circular1.test.ts deleted file mode 100644 index 35aa2b59a..000000000 --- a/packages/mobx-state-tree/__tests__/core/circular1.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { types } from "../../src" -import { LateTodo2, LateStore2 } from "./circular2.test" -// combine function hosting with types.late to support circular refs between files! -export function LateStore1() { - return types.model({ - todo: types.late(LateTodo2) - }) -} -export function LateTodo1() { - return types.model({ - done: types.boolean - }) -} -test("circular test 1 should work", () => { - const Store1 = types.late(LateStore1) - const Store2 = types.late(LateStore2) - expect(Store1.is({})).toBe(false) - expect(Store1.is({ todo: { done: true } })).toBe(true) - const s1 = Store1.create({ todo: { done: true } }) - expect(s1.todo.done).toBe(true) - expect(Store2.is({})).toBe(false) - expect(Store2.is({ todo: { done: true } })).toBe(true) - const s2 = Store2.create({ todo: { done: true } }) - expect(s2.todo.done).toBe(true) -}) diff --git a/packages/mobx-state-tree/__tests__/core/circular2.test.ts b/packages/mobx-state-tree/__tests__/core/circular2.test.ts deleted file mode 100644 index 4e9e0cfe1..000000000 --- a/packages/mobx-state-tree/__tests__/core/circular2.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { types } from "../../src" -import { LateTodo1, LateStore1 } from "./circular1.test" -// combine function hosting with types.late to support circular refs between files! -export function LateTodo2() { - return types.model({ - done: types.boolean - }) -} -export function LateStore2() { - return types.model({ - todo: types.late(LateTodo1) - }) -} -test("circular test 2 should work", () => { - const Store1 = types.late(LateStore1) - const Store2 = types.late(LateStore2) - expect(Store1.is({})).toBe(false) - expect(Store1.is({ todo: { done: true } })).toBe(true) - const s1 = Store1.create({ todo: { done: true } }) - expect(s1.todo.done).toBe(true) - expect(Store2.is({})).toBe(false) - expect(Store2.is({ todo: { done: true } })).toBe(true) - const s2 = Store2.create({ todo: { done: true } }) - expect(s2.todo.done).toBe(true) -}) diff --git a/packages/mobx-state-tree/__tests__/core/custom-type.test.ts b/packages/mobx-state-tree/__tests__/core/custom-type.test.ts deleted file mode 100644 index c0ddf9b74..000000000 --- a/packages/mobx-state-tree/__tests__/core/custom-type.test.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { - types, - recordPatches, - onSnapshot, - unprotect, - applySnapshot, - applyPatch, - SnapshotOut -} from "../../src" - -class Decimal { - public number: number - public fraction: number - - constructor(value: string) { - const parts = value.split(".") - this.number = Number(parts[0]) - this.fraction = Number(parts[1]) - } - - toNumber() { - return this.number + Number("0." + this.fraction) - } - - toString() { - return `${this.number}.${this.fraction}` - } -} - -{ - const DecimalPrimitive = types.custom({ - name: "Decimal", - fromSnapshot(value: string, env: any) { - if (env && env.test) env.test(value) - return new Decimal(value) - }, - toSnapshot(value: Decimal) { - return value.toString() - }, - isTargetType(value: string | Decimal): value is Decimal { - return value instanceof Decimal - }, - getValidationMessage(value: string): string { - if (/^-?\d+\.\d+$/.test(value)) return "" // OK - return `'${value}' doesn't look like a valid decimal number` - } - }) - - const Wallet = types.model({ - balance: DecimalPrimitive, - lastTransaction: types.maybeNull(DecimalPrimitive) - }) - - test("it should allow for custom primitive types", () => { - const w1 = Wallet.create({ - balance: new Decimal("2.5") - }) - - expect(w1.balance.number).toBe(2) - expect(w1.balance.fraction).toBe(5) - - const w2 = Wallet.create({ balance: "3.5" }) - expect(w2.balance.number).toBe(3) - expect(w2.balance.fraction).toBe(5) - - if (process.env.NODE_ENV !== "production") - expect(() => Wallet.create({ balance: "two point one" })).toThrow( - "(Invalid value for type 'Decimal': 'two point one' doesn't look like a valid decimal number)" - ) - }) - - // test reassignment / reconcilation / conversion works - test("reassignments will work", () => { - const w1 = Wallet.create({ balance: "2.5" }) - unprotect(w1) - - const p = recordPatches(w1) - const snapshots: SnapshotOut[] = [] - onSnapshot(w1, (s) => { - snapshots.push(s) - }) - - const b1 = w1.balance - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = "2.5" as any // TODO: make cast work with custom types - expect(b1).toBeInstanceOf(Decimal) - expect(w1.balance).toBe(b1) // reconciled - - w1.balance = new Decimal("2.5") // not reconciling! // TODO: introduce custom hook for that? - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = new Decimal("3.5") - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = "4.5" as any - expect(b1).toBeInstanceOf(Decimal) - - w1.lastTransaction = b1 - expect(w1.lastTransaction).toBe(b1) - - w1.lastTransaction = null - expect(w1.lastTransaction).toBe(null) - - // patches & snapshots - expect(snapshots).toMatchSnapshot() - p.stop() - expect(p.patches).toMatchSnapshot() - }) - - test("passes environment to fromSnapshot", () => { - const env = { test: jest.fn() } - Wallet.create({ balance: "3.0" }, env) - expect(env.test).toBeCalledWith("3.0") - }) -} - -{ - test("complex representation", () => {}) - - const DecimalTuple = types.custom<[number, number], Decimal>({ - name: "DecimalTuple", - fromSnapshot(value: [number, number]) { - return new Decimal(value[0] + "." + value[1]) - }, - toSnapshot(value: Decimal) { - return [value.number, value.fraction] - }, - isTargetType(value: [number, number] | Decimal): value is Decimal { - return value instanceof Decimal - }, - getValidationMessage(value: [number, number]): string { - if (Array.isArray(value) && value.length === 2) return "" // OK - return `'${JSON.stringify(value)}' doesn't look like a valid decimal number` - } - }) - - const Wallet = types.model({ balance: DecimalTuple }) - - test("it should allow for complex custom primitive types", () => { - const w1 = Wallet.create({ - balance: new Decimal("2.5") - }) - - expect(w1.balance.number).toBe(2) - expect(w1.balance.fraction).toBe(5) - - const w2 = Wallet.create({ balance: [3, 5] }) - expect(w2.balance.number).toBe(3) - expect(w2.balance.fraction).toBe(5) - - if (process.env.NODE_ENV !== "production") - expect(() => Wallet.create({ balance: "two point one" } as any)).toThrow( - "(Invalid value for type 'DecimalTuple': '\"two point one\"' doesn't look like a valid decimal number)" - ) - }) - - // test reassignment / reconcilation / conversion works - test("complex reassignments will work", () => { - const w1 = Wallet.create({ balance: [2, 5] }) - unprotect(w1) - - const p = recordPatches(w1) - const snapshots: SnapshotOut[] = [] - onSnapshot(w1, (s) => { - snapshots.push(s) - }) - - const b1 = w1.balance - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = [2, 5] as any - expect(b1).toBeInstanceOf(Decimal) - expect(w1.balance).not.toBe(b1) // not reconciled, balance is not deep equaled (TODO: future feature?) - - w1.balance = new Decimal("2.5") // not reconciling! - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = new Decimal("3.5") - expect(b1).toBeInstanceOf(Decimal) - - w1.balance = [4, 5] as any - expect(b1).toBeInstanceOf(Decimal) - - // patches & snapshots - expect(snapshots).toMatchSnapshot() - p.stop() - expect(p.patches).toMatchSnapshot() - }) - - test("can apply snapshot and patch", () => { - const w1 = Wallet.create({ balance: [3, 0] }) - applySnapshot(w1, { balance: [4, 5] }) - expect(w1.balance).toBeInstanceOf(Decimal) - expect(w1.balance.toString()).toBe("4.5") - - applyPatch(w1, { - op: "replace", - path: "/balance", - value: [5, 0] - }) - expect(w1.balance.toString()).toBe("5.0") - }) -} diff --git a/packages/mobx-state-tree/__tests__/core/deprecated.test.ts b/packages/mobx-state-tree/__tests__/core/deprecated.test.ts deleted file mode 100644 index 120c16632..000000000 --- a/packages/mobx-state-tree/__tests__/core/deprecated.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { deprecated } from "../../src/utils" -import { flow, createFlowSpawner } from "../../src/core/flow" -import { process as mstProcess, createProcessSpawner } from "../../src/core/process" - -function createDeprecationListener() { - // clear previous deprecation dedupe keys - deprecated.ids = {} - // save console.warn native implementation - const originalWarn = console.warn - // create spy to track warning call - const spyWarn = (console.warn = jest.fn()) - // return callback to check if warn was called properly - return function isDeprecated() { - // replace original implementation - console.warn = originalWarn - // test for correct log message, if in development - if (process.env.NODE_ENV !== "production") { - expect(spyWarn).toHaveBeenCalledTimes(1) - expect(spyWarn.mock.calls[0][0].message).toMatch(/Deprecation warning:/) - } - } -} -test("`process` should mirror `flow`", () => { - const isDeprecated = createDeprecationListener() - const generator = function* () {} - const flowResult = flow(generator) - const processResult = mstProcess(generator) - expect(processResult.name).toBe(flowResult.name) - isDeprecated() -}) -test("`createProcessSpawner` should mirror `createFlowSpawner`", () => { - const isDeprecated = createDeprecationListener() - const alias = "generatorAlias" - const generator = function* (): IterableIterator {} - const flowSpawnerResult = createFlowSpawner(alias, generator) - const processSpawnerResult = createProcessSpawner(alias, generator) - expect(processSpawnerResult.name).toBe(flowSpawnerResult.name) - isDeprecated() -}) diff --git a/packages/mobx-state-tree/__tests__/core/enum.test.ts b/packages/mobx-state-tree/__tests__/core/enum.test.ts deleted file mode 100644 index 0e44ffb50..000000000 --- a/packages/mobx-state-tree/__tests__/core/enum.test.ts +++ /dev/null @@ -1,74 +0,0 @@ -import { types, unprotect } from "../../src" - -enum ColorEnum { - Red = "Red", - Orange = "Orange", - Green = "Green" -} -const colorEnumValues = Object.values(ColorEnum) as ColorEnum[] - -test("should support enums", () => { - const TrafficLight = types.model({ color: types.enumeration("Color", colorEnumValues) }) - expect(TrafficLight.is({ color: ColorEnum.Green })).toBe(true) - expect(TrafficLight.is({ color: "Blue" })).toBe(false) - expect(TrafficLight.is({ color: undefined })).toBe(false) - const l = TrafficLight.create({ color: ColorEnum.Orange }) - unprotect(l) - l.color = ColorEnum.Red - expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') - if (process.env.NODE_ENV !== "production") { - expect(() => (l.color = "Blue" as any)).toThrowError( - /Error while converting `"Blue"` to `Color`/ - ) - } -}) -test("should support anonymous enums", () => { - const TrafficLight = types.model({ color: types.enumeration(colorEnumValues) }) - const l = TrafficLight.create({ color: ColorEnum.Orange }) - unprotect(l) - l.color = ColorEnum.Red - expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') - if (process.env.NODE_ENV !== "production") { - expect(() => (l.color = "Blue" as any)).toThrowError( - /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ - ) - } -}) -test("should support optional enums", () => { - const TrafficLight = types.optional(types.enumeration(colorEnumValues), ColorEnum.Orange) - const l = TrafficLight.create() - expect(l).toBe(ColorEnum.Orange) -}) -test("should support optional enums inside a model", () => { - const TrafficLight = types.model({ - color: types.optional(types.enumeration(colorEnumValues), ColorEnum.Orange) - }) - const l = TrafficLight.create({}) - expect(l.color).toBe(ColorEnum.Orange) -}) -test("should support plain string[] arrays", () => { - const colorOptions: string[] = ["Red", "Orange", "Green"] - const TrafficLight = types.model({ color: types.enumeration(colorOptions) }) - const l = TrafficLight.create({ color: "Orange" }) - unprotect(l) - l.color = "Red" - expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') - if (process.env.NODE_ENV !== "production") { - expect(() => (l.color = "Blue" as any)).toThrowError( - /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ - ) - } -}) -test("should support readonly enums as const", () => { - const colorOptions = ["Red", "Orange", "Green"] as const - const TrafficLight = types.model({ color: types.enumeration(colorOptions) }) - const l = TrafficLight.create({ color: "Orange" }) - unprotect(l) - l.color = "Red" - expect(TrafficLight.describe()).toBe('{ color: ("Red" | "Orange" | "Green") }') - if (process.env.NODE_ENV !== "production") { - expect(() => (l.color = "Blue" as any)).toThrowError( - /Error while converting `"Blue"` to `"Red" | "Orange" | "Green"`/ - ) - } -}) diff --git a/packages/mobx-state-tree/__tests__/core/env.test.ts b/packages/mobx-state-tree/__tests__/core/env.test.ts deleted file mode 100644 index 71ff6886c..000000000 --- a/packages/mobx-state-tree/__tests__/core/env.test.ts +++ /dev/null @@ -1,313 +0,0 @@ -import { configure } from "mobx" -import { - types, - getEnv, - clone, - detach, - unprotect, - walk, - getPath, - castToSnapshot, - hasParent, - Instance, - destroy, - getParent, - IAnyStateTreeNode, - isStateTreeNode, - isAlive -} from "../../src" - -// tslint:disable: no-unused-expression - -const Todo = types - .model({ - title: "test" - }) - .views((self) => ({ - get description() { - return getEnv(self).useUppercase ? self.title.toUpperCase() : self.title - } - })) -const Store = types.model({ - todos: types.array(Todo) -}) -function createEnvironment() { - return { - useUppercase: true - } -} -test("it should be possible to use environments", () => { - const env = createEnvironment() - const todo = Todo.create({}, env) - expect(todo.description).toBe("TEST") - env.useUppercase = false - expect(todo.description).toBe("test") -}) -test("it should be possible to inherit environments", () => { - const env = createEnvironment() - const store = Store.create({ todos: [{}] }, env) - expect(store.todos[0].description).toBe("TEST") - env.useUppercase = false - expect(store.todos[0].description).toBe("test") -}) -test("getEnv returns empty object without environment", () => { - const todo = Todo.create() - expect(getEnv(todo)).toEqual({}) -}) -test("detach should preserve environment", () => { - const env = createEnvironment() - const store = Store.create({ todos: [{}] }, env) - unprotect(store) - const todo = detach(store.todos[0]) - expect(todo.description).toBe("TEST") - env.useUppercase = false - expect(todo.description).toBe("test") -}) -test("it is possible to assign instance with the same environment as the parent to a tree", () => { - const env = createEnvironment() - const store = Store.create({ todos: [] }, env) - const todo = Todo.create({}, env) - unprotect(store) - store.todos.push(todo) - expect(store.todos.length === 1).toBe(true) - expect(getEnv(store.todos) === getEnv(store.todos[0])).toBe(true) - expect(getEnv(todo) === getEnv(store.todos[0])).toBe(true) -}) -test("it is not possible to assign instance with a different environment than the parent to a tree", () => { - if (process.env.NODE_ENV !== "production") { - const env1 = createEnvironment() - const env2 = createEnvironment() - const store = Store.create({ todos: [] }, env1) - const todo = Todo.create({}, env2) - unprotect(store) - expect(() => store.todos.push(todo)).toThrowError( - "[mobx-state-tree] A state tree cannot be made part of another state tree as long as their environments are different." - ) - } -}) -test("it is possible to set a value inside a map of a map when using the same environment", () => { - const env = createEnvironment() - const EmptyModel = types.model({}) - const MapOfEmptyModel = types.model({ - map: types.map(EmptyModel) - }) - const MapOfMapOfEmptyModel = types.model({ - map: types.map(MapOfEmptyModel) - }) - const mapOfMap = MapOfMapOfEmptyModel.create( - { - map: { - whatever: { - map: {} - } - } - }, - env - ) - unprotect(mapOfMap) - // this should not throw - mapOfMap.map.get("whatever")!.map.set("1234", EmptyModel.create({}, env)) - expect(getEnv(mapOfMap) === env).toBe(true) - expect(getEnv(mapOfMap.map.get("whatever")!.map.get("1234")!) === env).toBe(true) -}) -test("clone preserves environnment", () => { - const env = createEnvironment() - const store = Store.create({ todos: [{}] }, env) - { - const todo = clone(store.todos[0]) - expect(getEnv(todo) === env).toBe(true) - } - { - const todo = clone(store.todos[0], true) - expect(getEnv(todo) === env).toBe(true) - } - { - const todo = clone(store.todos[0], false) - expect(getEnv(todo)).toEqual({}) - } - { - const env2 = createEnvironment() - const todo = clone(store.todos[0], env2) - expect(env2 === getEnv(todo)).toBe(true) - } -}) - -test("#1231", () => { - configure({ - useProxies: "never" - }) - - const envObj = createEnvironment() - const logs: string[] = [] - - function nofParents(node: IAnyStateTreeNode) { - let parents = 0 - let parent = node - while (hasParent(parent)) { - parents++ - parent = getParent(parent) - } - return parents - } - - function leafsFirst(root: IAnyStateTreeNode) { - const nodes: IAnyStateTreeNode[] = [] - walk(root, (i) => { - if (isStateTreeNode(i)) { - nodes.push(i) - } - }) - // sort by number of parents - nodes.sort((a, b) => { - return nofParents(b) - nofParents(a) - }) - return nodes - } - - function check(root: Instance, name: string, mode: "detach" | "destroy") { - function logFail(operation: string, n: any) { - logs.push(`fail: (${name}) ${operation}: ${getPath(n)}, ${n}`) - } - function log(operation: string, n: any) { - logs.push(`ok: (${name}) ${operation}: ${getPath(n)}, ${n}`) - } - - // make sure all nodes are there - root.s1.arr[0].title - root.s1.m.get("one")!.title - root.s2 - const nodes = leafsFirst(root) - expect(nodes.length).toBe(7) - - nodes.forEach((i) => { - const env = getEnv(i) - const parent = hasParent(i) - if (!parent && i !== root) { - logFail("expected a parent, but none found", i) - } else { - log("had parent or was root", i) - } - if (env !== envObj) { - logFail("expected same env as root, but was different", i) - } else { - log("same env as root", i) - } - }) - - unprotect(root) - nodes.forEach((i) => { - const optional = optionalPaths.includes(getPath(i)) - if (mode === "detach") { - log("detaching node", i) - detach(i) - } else { - log("destroying node", i) - destroy(i) - } - const env = getEnv(i) - const parent = hasParent(i) - const alive = isAlive(i) - if (mode === "detach") { - if (parent) { - logFail(`expected no parent after detach, but one was found`, i) - } else { - log(`no parent after detach`, i) - } - if (env !== envObj) { - logFail("expected same env as root after detach, but it was not", i) - } else { - log("env kept after detach", i) - } - if (!alive) { - logFail("expected to be alive after detach, but it was not", i) - } else { - log("alive after detach", i) - } - } else { - // destroy might or might not keep the env, but doesn't matter so we don't check - if (optional) { - // optional (undefined) nodes will be assigned undefined and reconciled, therefore they will be kept alive - if (!parent) { - logFail( - `expected a parent after destroy (since it is optional), but none was found`, - i - ) - } else { - log(`had parent after destroy (since it is optional)`, i) - } - if (!alive) { - logFail( - "expected to be alive after destroy (since it is optional), but it was not", - i - ) - } else { - log("alive after destroy (since it is optional)", i) - } - } else { - if (parent) { - logFail(`expected no parent after destroy, but one was found`, i) - } else { - log(`no parent after destroy`, i) - } - if (alive) { - logFail("expected to be dead after destroy, but it was not", i) - } else { - log("dead after destroy", i) - } - } - } - }) - } - - const T = types.model("T", { title: "some title" }) - - const S1Arr = types.array(T) - const S1Map = types.map(T) - const S1 = types.model("S1", { - arr: S1Arr, - m: S1Map - }) - - const S2 = types.model("S2", {}) - - const RS = types.model("RS", { - s1: types.optional(S1, {}), - s2: types.optional(S2, {}) - }) - - const optionalPaths = ["/s1", "/s2", "/s1/m", "/s1/arr"] - - const data = { - s1: castToSnapshot( - S1.create({ - arr: S1Arr.create([T.create({})]), - m: castToSnapshot(S1Map.create({ one: T.create({}) })) - }) - ), - s2: S2.create() - } - const rsCreate = RS.create(data, envObj) - const rsCreate2 = clone(rsCreate, true) - - const rsSnap = RS.create( - { - s1: { - arr: [{}], - m: { one: {} } - }, - s2: {} - }, - envObj - ) - const rsSnap2 = clone(rsCreate, true) - - check(rsCreate, "using create", "detach") - check(rsSnap, "using snapshot", "detach") - check(rsCreate2, "using create", "destroy") - check(rsSnap2, "using snapshot", "destroy") - - const fails = logs.filter((l) => l.startsWith("fail:")) - if (fails.length > 0) { - fail(`\n${fails.join("\n")}`) - } -}) diff --git a/packages/mobx-state-tree/__tests__/core/frozen.test.ts b/packages/mobx-state-tree/__tests__/core/frozen.test.ts deleted file mode 100644 index 3618b70fa..000000000 --- a/packages/mobx-state-tree/__tests__/core/frozen.test.ts +++ /dev/null @@ -1,91 +0,0 @@ -import { getSnapshot, types, unprotect } from "../../src" - -test("it should accept any serializable value", () => { - const Factory = types.model({ - value: types.frozen<{ a: number; b: number } | undefined>() - }) - const doc = Factory.create() - unprotect(doc) - doc.value = { a: 1, b: 2 } - expect(getSnapshot(doc)).toEqual({ value: { a: 1, b: 2 } }) -}) - -if (process.env.NODE_ENV !== "production") { - test("it should throw if value is not serializable", () => { - const Factory = types.model({ - value: types.frozen() - }) - const doc = Factory.create() - unprotect(doc) - expect(() => { - doc.value = function IAmUnserializable() {} - }).toThrowError(/Error while converting to `frozen`/) - }) -} - -test("it should accept any default value value", () => { - const Factory = types.model({ - value: types.frozen(3) - }) - const doc = Factory.create() - expect(Factory.is({})).toBeTruthy() - expect(getSnapshot(doc)).toEqual({ value: 3 }) -}) - -test("it should type strongly", () => { - type Point = { x: number; y: number } - const Mouse = types - .model({ - loc: types.frozen() - }) - .actions((self) => ({ - moveABit() { - // self.loc.x += 1; // compile error, x is readonly! - ;(self.loc as any).x += 1 // throws, frozen! - } - })) - - expect(Mouse.is({})).toBeTruthy() // any value is acceptable to frozen, even undefined... - - const m = Mouse.create({ - // loc: 3 // type error! - loc: { x: 2, y: 3 } - }) - - if (process.env.NODE_ENV !== "production") { - expect(() => { - m.moveABit() - }).toThrow("Cannot assign to read only property 'x'") - } -}) - -if (process.env.NODE_ENV !== "production") { - test("it should be capable of using another MST type", () => { - const Point = types.model("Point", { x: types.number, y: types.number }) - const Mouse = types.model({ - loc: types.frozen(Point) - }) - - expect(Mouse.is({})).toBeFalsy() - expect(Mouse.is({ loc: {} })).toBeFalsy() - expect(Mouse.is({ loc: { x: 3, y: 2 } })).toBeTruthy() - - expect(() => { - ;(Mouse.create as any)() - }).toThrow( - 'at path "/loc" value `undefined` is not assignable to type: `frozen(Point)` (Value is not a plain object)' - ) - expect(() => { - Mouse.create({ loc: { x: 4 } } as any) - }).toThrow( - 'at path "/loc/y" value `undefined` is not assignable to type: `number` (Value is not a number)' - ) - - const m = Mouse.create({ - loc: { x: 3, y: 2 } - }) - - const x = m.loc.x - expect(x).toBe(3) - }) -} diff --git a/packages/mobx-state-tree/__tests__/core/hooks.test.ts b/packages/mobx-state-tree/__tests__/core/hooks.test.ts deleted file mode 100644 index 4ec842a6a..000000000 --- a/packages/mobx-state-tree/__tests__/core/hooks.test.ts +++ /dev/null @@ -1,456 +0,0 @@ -import { - addDisposer, - destroy, - detach, - types, - unprotect, - getSnapshot, - applySnapshot, - onSnapshot, - isAlive, - hasParent, - cast, - resolvePath, - getParent -} from "../../src" - -function createTestStore(listener: (s: string) => void) { - const Todo = types - .model("Todo", { - title: "" - }) - .actions((self) => { - function afterCreate() { - listener("new todo: " + self.title) - addDisposer(self, () => { - listener("custom disposer 1 for " + self.title) - }) - addDisposer(self, () => { - listener("custom disposer 2 for " + self.title) - }) - } - function beforeDestroy() { - listener("destroy todo: " + self.title) - } - function afterAttach() { - listener("attach todo: " + self.title) - } - function beforeDetach() { - listener("detach todo: " + self.title) - } - return { - afterCreate, - beforeDestroy, - afterAttach, - beforeDetach - } - }) - const Store = types - .model("Store", { - todos: types.array(Todo) - }) - .actions((self) => { - function afterCreate() { - unprotect(self) - listener("new store: " + self.todos.length) - addDisposer(self, () => { - listener("custom disposer for store") - }) - } - function beforeDestroy() { - listener("destroy store: " + self.todos.length) - } - return { - afterCreate, - beforeDestroy - } - }) - return { - store: Store.create({ - todos: [{ title: "Get coffee" }, { title: "Get biscuit" }, { title: "Give talk" }] - }), - Store, - Todo - } -} - -// NOTE: as we defer creation (and thus, hooks) till first real access, -// some of original hooks do not fire at all -test("it should trigger lifecycle hooks", () => { - const events: string[] = [] - // new store: 3 - const { store, Todo } = createTestStore((e) => events.push(e)) - - events.push("-") - // access (new, attach), then detach "Give Talk" - const talk = detach(store.todos[2]) - expect(isAlive(talk)).toBe(true) - expect(hasParent(talk)).toBe(false) - - events.push("--") - - // access (new, attach), then destroy biscuit - const oldBiscuit = store.todos.pop()! - expect(isAlive(oldBiscuit)).toBe(false) - - events.push("---") - // new and then attach "add sugar" - const sugar = Todo.create({ - title: "add sugar" - }) - store.todos.push(sugar) - - events.push("----") - // destroy elements in the array ("add sugar"), then store - destroy(store) - expect(isAlive(store)).toBe(false) - - events.push("-----") - // destroy "Give talk" - destroy(talk) - expect(isAlive(talk)).toBe(false) - - expect(events).toEqual([ - "new store: 3", - "-", - "new todo: Give talk", - "attach todo: Give talk", - "detach todo: Give talk", - "--", - "new todo: Get biscuit", - "attach todo: Get biscuit", - "destroy todo: Get biscuit", - "custom disposer 2 for Get biscuit", - "custom disposer 1 for Get biscuit", - "---", - "new todo: add sugar", - "attach todo: add sugar", - "----", - "destroy todo: add sugar", - "custom disposer 2 for add sugar", - "custom disposer 1 for add sugar", - "destroy store: 2", - "custom disposer for store", - "-----", - "destroy todo: Give talk", - "custom disposer 2 for Give talk", - "custom disposer 1 for Give talk" - ]) -}) - -test("lifecycle hooks can access their children", () => { - const events: string[] = [] - function listener(e: string) { - events.push(e) - } - - const Child = types - .model("Todo", { - title: "" - }) - .actions((self) => ({ - afterCreate() { - listener("new child: " + self.title) - }, - afterAttach() { - listener("parent available: " + !!getParent(self)) - } - })) - - const Parent = types - .model("Parent", { - child: Child - }) - .actions((self) => ({ - afterCreate() { - // **This the key line**: it is trying to access the child - listener("new parent, child.title: " + self.child?.title) - } - })) - - const Store = types.model("Store", { - parent: types.maybe(Parent) - }) - - const store = Store.create({ - parent: { - child: { title: "Junior" } - } - }) - // As expected no hooks are called. - // The `parent` is not accessed it is just loaded. - events.push("-") - - // Simple access does a sensible thing - const parent = store.parent - expect(events).toEqual([ - "-", - "new child: Junior", - "new parent, child.title: Junior", - "parent available: true" - ]) - - // Clear the events and make a new store - events.length = 0 - const store2 = Store.create({ - parent: { - child: { title: "Junior" } - } - }) - events.push("-") - - // Previously resolvePath would cause problems because the parent hooks - // would be called before the child was fully created - const child = resolvePath(store2, "/parent/child") - expect(events).toEqual([ - "-", - "new child: Junior", - "new parent, child.title: Junior", - "parent available: true" - ]) -}) - -type CarSnapshot = { id: string } -const Car = types - .model("Car", { - id: types.number - }) - .preProcessSnapshot((snapshot) => - Object.assign({}, snapshot, { id: Number(snapshot.id) * 2 }) - ) - .postProcessSnapshot((snapshot) => - Object.assign({}, snapshot, { id: "" + snapshot.id / 2 }) - ) - -const Factory = types.model("Factory", { - car: Car -}) - -const Motorcycle = types - .model("Motorcycle", { - id: types.string - }) - .preProcessSnapshot((snapshot) => - Object.assign({}, snapshot, { id: snapshot.id.toLowerCase() }) - ) - .postProcessSnapshot((snapshot) => - Object.assign({}, snapshot, { id: snapshot.id.toUpperCase() }) - ) -const MotorcycleFactory = types.model("MotorcycleFactory", { - motorcycles: types.array(Motorcycle) -}) - -test("it should preprocess snapshots when creating", () => { - const car = Car.create({ id: "1" }) - expect(car.id).toBe(2) -}) -test("it should preprocess snapshots when updating", () => { - const car = Car.create({ id: "1" }) - expect(car.id).toBe(2) - applySnapshot(car, { id: "6" }) - expect(car.id).toBe(12) -}) -test("it should postprocess snapshots when generating snapshot - 1", () => { - const car = Car.create({ id: "1" }) - expect(car.id).toBe(2) - expect(getSnapshot(car)).toEqual({ id: "1" }) -}) -test("it should not apply postprocessor to snapshot on getSnapshot", () => { - const car = Car.create({ id: "1" }) - let error = false - onSnapshot(car, (snapshot) => { - error = true - }) - expect(getSnapshot(car)).toEqual({ id: "1" }) - expect(getSnapshot(car, false)).toEqual({ id: 2 }) - expect(error).toBeFalsy() -}) -test("it should preprocess snapshots when creating as property type", () => { - const f = Factory.create({ car: { id: "1" } }) - expect(f.car.id).toBe(2) -}) -test("it should preprocess snapshots when updating", () => { - const f = Factory.create({ car: { id: "1" } }) - expect(f.car.id).toBe(2) - applySnapshot(f, { car: { id: "6" } }) - expect(f.car.id).toBe(12) -}) -test("it should postprocess snapshots when generating snapshot - 2", () => { - const f = Factory.create({ car: { id: "1" } }) - expect(f.car.id).toBe(2) - expect(getSnapshot(f)).toEqual({ car: { id: "1" } }) -}) - -test("it should postprocess non-initialized children", () => { - const f = MotorcycleFactory.create({ motorcycles: [{ id: "a" }, { id: "b" }] }) - expect(getSnapshot(f)).toEqual({ motorcycles: [{ id: "A" }, { id: "B" }] }) -}) - -test("base hooks can be composed", () => { - const events: string[] = [] - function listener(message: string) { - events.push(message) - } - const Todo = types - .model("Todo", { title: "" }) - .actions((self) => { - function afterCreate() { - listener("aftercreate1") - } - function beforeDestroy() { - listener("beforedestroy1") - } - function afterAttach() { - listener("afterattach1") - } - function beforeDetach() { - listener("beforedetach1") - } - return { afterCreate, beforeDestroy, afterAttach, beforeDetach } - }) - .actions((self) => { - function afterCreate() { - listener("aftercreate2") - } - function beforeDestroy() { - listener("beforedestroy2") - } - function afterAttach() { - listener("afterattach2") - } - function beforeDetach() { - listener("beforedetach2") - } - return { afterCreate, beforeDestroy, afterAttach, beforeDetach } - }) - const Store = types.model("Store", { todos: types.array(Todo) }) - const store = Store.create({ todos: [] }) - const todo = Todo.create() - unprotect(store) - store.todos.push(todo) - detach(todo) - destroy(todo) - expect(events).toEqual([ - "aftercreate1", - "aftercreate2", - "afterattach1", - "afterattach2", - "beforedetach1", - "beforedetach2", - "beforedestroy1", - "beforedestroy2" - ]) -}) -test("snapshot processors can be composed", () => { - const X = types - .model({ - x: 1 - }) - .preProcessSnapshot((s) => ({ - x: s.x! - 3 - })) - .preProcessSnapshot((s) => ({ - x: s.x! / 5 - })) - .postProcessSnapshot((s) => { - return { x: s.x + 3 } - }) - .postProcessSnapshot((s) => { - return { x: s.x * 5 } - }) - - const x = X.create({ x: 25 }) - expect(x.x).toBe(2) - expect(getSnapshot(x).x).toBe(25) -}) - -test("addDisposer must return the passed disposer", () => { - const listener = jest.fn() - const M = types.model({}).actions((self) => { - expect(addDisposer(self, listener)).toBe(listener) - return {} - }) - M.create() -}) - -test("array calls all hooks", () => { - const events: string[] = [] - function listener(message: string) { - events.push(message) - } - const Item = types.model("Item", { id: types.string }) - const Collection = types.array(Item).hooks((self) => ({ - afterCreate() { - listener("afterCreate") - }, - afterAttach() { - listener("afterAttach") - }, - beforeDetach() { - listener("beforeDetach") - }, - beforeDestroy() { - listener("beforeDestroy") - } - })) - const Holder = types.model("Holder", { items: types.maybe(Collection) }) - - const collection = Collection.create([{ id: "1" }, { id: "2" }, { id: "3" }]) - expect(events).toStrictEqual(["afterCreate"]) - const holder = Holder.create({ items: collection }) - unprotect(holder) - expect(events).toStrictEqual(["afterCreate", "afterAttach"]) - detach(holder.items!) - expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach"]) - holder.items = collection - expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach", "afterAttach"]) - holder.items = undefined - expect(events).toStrictEqual([ - "afterCreate", - "afterAttach", - "beforeDetach", - "afterAttach", - "beforeDestroy" - ]) -}) - -test("map calls all hooks", () => { - const events: string[] = [] - function listener(message: string) { - events.push(message) - } - const Item = types.model("Item", { id: types.string }) - const Collection = types.map(Item).hooks((self) => ({ - afterCreate() { - listener("afterCreate") - }, - afterAttach() { - listener("afterAttach") - }, - beforeDetach() { - listener("beforeDetach") - }, - beforeDestroy() { - listener("beforeDestroy") - } - })) - const Holder = types.model("Holder", { items: types.maybe(Collection) }) - - const collection = Collection.create({ "1": { id: "1" }, "2": { id: "2" }, "3": { id: "3" } }) - expect(events).toStrictEqual(["afterCreate"]) - const holder = Holder.create({ items: cast(collection) }) - unprotect(holder) - expect(events).toStrictEqual(["afterCreate", "afterAttach"]) - detach(holder.items!) - expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach"]) - holder.items = collection - expect(events).toStrictEqual(["afterCreate", "afterAttach", "beforeDetach", "afterAttach"]) - holder.items = undefined - expect(events).toStrictEqual([ - "afterCreate", - "afterAttach", - "beforeDetach", - "afterAttach", - "beforeDestroy" - ]) -}) diff --git a/packages/mobx-state-tree/__tests__/core/identifier.test.ts b/packages/mobx-state-tree/__tests__/core/identifier.test.ts deleted file mode 100644 index c25a133fa..000000000 --- a/packages/mobx-state-tree/__tests__/core/identifier.test.ts +++ /dev/null @@ -1,320 +0,0 @@ -import { - types, - tryResolve, - resolvePath, - SnapshotOrInstance, - IAnyModelType, - IAnyComplexType, - resolveIdentifier, - getIdentifier, - detach -} from "../../src" - -if (process.env.NODE_ENV !== "production") { - test("#275 - Identifiers should check refinement", () => { - const Model = types - .model("Model", { - id: types.refinement( - "id", - types.string, - (identifier) => identifier.indexOf("Model_") === 0 - ) - }) - .actions((self) => ({ - setId(id: string) { - self.id = id - } - })) - const ParentModel = types - .model("ParentModel", { - models: types.array(Model) - }) - .actions((self) => ({ - addModel(model: SnapshotOrInstance) { - self.models.push(model) - } - })) - expect(() => { - ParentModel.create({ models: [{ id: "WrongId_1" }] }) - }).toThrow() - expect(() => { - const parentStore = ParentModel.create({ models: [] }) - parentStore.addModel({ id: "WrongId_2" }) - }).toThrow() - expect(() => { - const model = Model.create({ id: "Model_1" }) - model.setId("WrongId_3") - }).toThrow() - expect(() => { - Model.create({ id: "WrongId_4" }) - }).toThrow() - }) -} -test("#158 - #88 - Identifiers should accept any string character", () => { - const Todo = types.model("Todo", { - id: types.identifier, - title: types.string - }) - expect(() => { - ;["coffee", "cof$fee", "cof|fee", "cof/fee"].forEach((id) => { - Todo.create({ - id: id, - title: "Get coffee" - }) - }) - }).not.toThrow() -}) -test("#187 - identifiers should not break late types", () => { - expect(() => { - const MstNode = types.model("MstNode", { - value: types.number, - next: types.maybe(types.late((): IAnyModelType => MstNode)) - }) - }).not.toThrow() -}) -if (process.env.NODE_ENV !== "production") { - test("should throw if multiple identifiers provided", () => { - expect(() => { - const Model = types.model("Model", { - id: types.identifierNumber, - pk: types.identifierNumber - }) - Model.create({ id: 1, pk: 2 }) - }).toThrowError( - `[mobx-state-tree] Cannot define property 'pk' as object identifier, property 'id' is already defined as identifier property` - ) - }) - test("should throw if identifier of wrong type", () => { - expect(() => { - const Model = types.model("Model", { id: types.identifier }) - Model.create({ id: 1 as any as string }) - }).toThrowError( - 'at path "/id" value `1` is not assignable to type: `identifier` (Value is not a valid identifier, expected a string).' - ) - }) - test("identifier should be used only on model types - no parent provided", () => { - expect(() => { - const Model = types.identifierNumber - Model.create(1) - }).toThrowError( - `[mobx-state-tree] Identifier types can only be instantiated as direct child of a model type` - ) - }) -} - -{ - const Foo = types.model("Foo", { - id: types.identifier, - name: types.string - }) - - const Bar = types.model("Bar", { - mimi: types.string, - fooRef: types.reference(Foo) - }) - - const Root = types.model("Root", { - foos: types.map(Foo), - bar: Bar - }) - - const root = Root.create({ - foos: {}, - bar: { - mimi: "mimi", - fooRef: "123" - } - }) - - test("try resolve doesn't work #686", () => { - expect(tryResolve(root, "/bar/fooRef")).toBe(undefined) - expect(tryResolve(root, "/bar/fooRef/name")).toBe(undefined) - }) - - test("try resolve shouldn't fail with a complex object node #2071", () => { - const array = types.array(types.number).create([]) - const model = types.model().create({}) - const map = types.map(types.number).create({}) - expect(tryResolve(array, "/boop")).toBeUndefined() - expect(tryResolve(model, "/boop")).toBeUndefined() - expect(tryResolve(map, "/boop")).toBeUndefined() - }) - - test("failing to resolve throws sane errors", () => { - expect(() => { - resolvePath(root, "/bar/mimi/oopsie") - }).toThrow( - "[mobx-state-tree] Could not resolve 'oopsie' in path '/bar/mimi' while resolving '/bar/mimi/oopsie'" - ) - - expect(() => { - resolvePath(root, "/zoomba/moomba") - }).toThrow( - "[mobx-state-tree] Could not resolve 'zoomba' in path '/' while resolving '/zoomba/moomba'" - ) - - expect(() => resolvePath(root, "/bar/fooRef")).toThrow( - "[mobx-state-tree] Failed to resolve reference '123' to type 'Foo' (from node: /bar/fooRef)" - ) - expect(() => resolvePath(root, "/bar/fooRef/name")).toThrow( - "[mobx-state-tree] Failed to resolve reference '123' to type 'Foo' (from node: /bar/fooRef)" - ) - }) -} - -test("it can resolve through references", () => { - const Folder = types.model("Folder", { - type: types.literal("folder"), - name: types.identifier, - children: types.array(types.late((): IAnyComplexType => types.union(Folder, SymLink))) - }) - const SymLink = types.model({ - type: types.literal("link"), - target: types.reference(Folder) - }) - - const root = Folder.create({ - type: "folder", - name: "root", - children: [ - { - type: "folder", - name: "a", - children: [] - }, - { - type: "folder", - name: "b", - children: [ - { - type: "folder", - name: "c", - children: [] - } - ] - }, - { - type: "link", - target: "b" - }, - { - type: "link", - target: "e" - } - ] - }) - - expect(resolvePath(root, "/children/1/children/0").name).toBe("c") - - expect(resolvePath(root, "/children/2/target/children/0").name).toBe("c") - - expect(resolvePath(root, "/children/2/target/children/../children/./0").name).toBe("c") - - expect(() => resolvePath(root, "/children/3/target/children/0").name).toThrow( - "[mobx-state-tree] Failed to resolve reference 'e' to type 'Folder' (from node: /children/3/target)" - ) -}) - -test("#1019", () => { - let calls = 0 - function randomUuid() { - calls++ - let pattern = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" - return pattern.replace(/[xy]/g, function (cc) { - const r = (Math.random() * 16) | 0, - v = cc === "x" ? r : (r & 0x3) | 0x8 - return v.toString(16) - }) - } - - const TOptionalId = types.optional( - types.refinement(types.identifier, (identifier) => - /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/.test(identifier) - ), - randomUuid - ) - - const CommentModel = types.model("CommentModel", { - uid: TOptionalId - }) - - const CommentStore = types - .model("CommentStore", { - items: types.array(CommentModel) - }) - .actions((self) => ({ - test1() { - expect(calls).toBe(0) - const comment = CommentModel.create({}) - expect(calls).toBe(1) - - self.items.push(comment) - const item = resolveIdentifier(CommentModel, self.items, comment.uid) - const item2 = self.items.find((i) => i.uid === comment.uid) - expect(item).toBe(item2) - } - })) - - const c = CommentStore.create({}) - c.test1() -}) - -test("#1019-2", () => { - const Item = types.model({ - id: types.optional(types.identifier, "dummykey") - }) - expect(getIdentifier(Item.create())).toBe("dummykey") - expect(Item.create().id).toBe("dummykey") -}) - -test("identifierAttribute of the type", () => { - const M1 = types.model({}) - expect(M1.identifierAttribute).toBe(undefined) - - const M2 = types.model({ myId: types.identifier }) - expect(M2.identifierAttribute).toBe("myId") - - const M3 = types.model({ myId: types.optional(types.identifier, () => "hi") }) - expect(M3.identifierAttribute).toBe("myId") -}) - -test("items detached from arrays don't corrupt identifierCache", () => { - const Item = types.model("Item", { id: types.identifier }) - const ItemArray = types.model("ItemArray", { items: types.array(Item) }).actions((self) => ({ - removeSecondItemWithDetach() { - detach(self.items[1]) - } - })) - - const smallArray = ItemArray.create({ - items: [{ id: "A" }, { id: "B" }, { id: "C" }, { id: "D" }, { id: "E" }] - }) - expect(resolveIdentifier(Item, smallArray, "E")).toBeDefined() - smallArray.removeSecondItemWithDetach() - expect(smallArray.items.length).toBe(4) - expect(resolveIdentifier(Item, smallArray, "B")).toBeUndefined() - expect(resolveIdentifier(Item, smallArray, "E")).toBeDefined() - - const largeArray = ItemArray.create({ - items: [ - { id: "A" }, - { id: "B" }, - { id: "C" }, - { id: "D" }, - { id: "E" }, - { id: "F" }, - { id: "G" }, - { id: "H" }, - { id: "I" }, - { id: "J" }, - { id: "K" } - ] - }) - expect(resolveIdentifier(Item, largeArray, "K")).toBeDefined() - largeArray.removeSecondItemWithDetach() - expect(largeArray.items.length).toBe(10) - expect(resolveIdentifier(Item, largeArray, "B")).toBeUndefined() - expect(resolveIdentifier(Item, largeArray, "J")).toBeDefined() - // The following expectation was failing in version 5.1.8 and earlier - expect(resolveIdentifier(Item, largeArray, "K")).toBeDefined() -}) diff --git a/packages/mobx-state-tree/__tests__/core/jsonpatch.test.ts b/packages/mobx-state-tree/__tests__/core/jsonpatch.test.ts deleted file mode 100644 index 453e5f4ad..000000000 --- a/packages/mobx-state-tree/__tests__/core/jsonpatch.test.ts +++ /dev/null @@ -1,482 +0,0 @@ -import { - getSnapshot, - unprotect, - recordPatches, - types, - IType, - IJsonPatch, - Instance, - cast, - IAnyModelType, - IMSTMap, - escapeJsonPath, - getPath, - resolvePath, - splitJsonPath, - joinJsonPath -} from "../../src" - -function testPatches( - type: IType, - snapshot: C, - fn: any, - expectedPatches: IJsonPatch[] -) { - const instance = type.create(snapshot) - const baseSnapshot = getSnapshot(instance) - const recorder = recordPatches(instance) - unprotect(instance) - fn(instance) - recorder.stop() - expect(recorder.patches).toEqual(expectedPatches) - const clone = type.create(snapshot) - recorder.replay(clone) - expect(getSnapshot(clone)).toEqual(getSnapshot(instance)) - recorder.undo() - expect(getSnapshot(instance)).toEqual(baseSnapshot) -} -const Node = types.model("Node", { - id: types.identifierNumber, - text: "Hi", - children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) -}) - -test("it should apply simple patch", () => { - testPatches( - Node, - { id: 1 }, - (n: Instance) => { - n.text = "test" - }, - [ - { - op: "replace", - path: "/text", - value: "test" - } - ] - ) -}) - -test("it should apply deep patches to arrays", () => { - testPatches( - Node, - { id: 1, children: [{ id: 2 }] }, - (n: Instance) => { - const children = (n.children as unknown) as Instance[] - children[0].text = "test" // update - children[0] = cast({ id: 2, text: "world" }) // this reconciles; just an update - children[0] = cast({ id: 4, text: "coffee" }) // new object - children[1] = cast({ id: 3, text: "world" }) // addition - children.splice(0, 1) // removal - }, - [ - { - op: "replace", - path: "/children/0/text", - value: "test" - }, - { - op: "replace", - path: "/children/0/text", - value: "world" - }, - { - op: "replace", - path: "/children/0", - value: { - id: 4, - text: "coffee", - children: [] - } - }, - { - op: "add", - path: "/children/1", - value: { - id: 3, - text: "world", - children: [] - } - }, - { - op: "remove", - path: "/children/0" - } - ] - ) -}) - -test("it should apply deep patches to arrays with object instances", () => { - testPatches( - Node, - { id: 1, children: [{ id: 2 }] }, - (n: Instance) => { - const children = (n.children as unknown) as Instance[] - children[0].text = "test" // update - children[0] = Node.create({ id: 2, text: "world" }) // this does not reconcile, new instance is provided - children[0] = Node.create({ id: 4, text: "coffee" }) // new object - }, - [ - { - op: "replace", - path: "/children/0/text", - value: "test" - }, - { - op: "replace", - path: "/children/0", - value: { - id: 2, - text: "world", - children: [] - } - }, - { - op: "replace", - path: "/children/0", - value: { - id: 4, - text: "coffee", - children: [] - } - } - ] - ) -}) - -test("it should apply non flat patches", () => { - testPatches( - Node, - { id: 1 }, - (n: Instance) => { - const children = (n.children as unknown) as Instance[] - children.push( - cast({ - id: 2, - children: [{ id: 4 }, { id: 5, text: "Tea" }] - }) - ) - }, - [ - { - op: "add", - path: "/children/0", - value: { - id: 2, - text: "Hi", - children: [ - { - id: 4, - text: "Hi", - children: [] - }, - { - id: 5, - text: "Tea", - children: [] - } - ] - } - } - ] - ) -}) - -test("it should apply non flat patches with object instances", () => { - testPatches( - Node, - { id: 1 }, - (n: Instance) => { - const children = (n.children as unknown) as Instance[] - children.push( - Node.create({ - id: 2, - children: [{ id: 5, text: "Tea" }] - }) - ) - }, - [ - { - op: "add", - path: "/children/0", - value: { - id: 2, - text: "Hi", - children: [ - { - id: 5, - text: "Tea", - children: [] - } - ] - } - } - ] - ) -}) - -test("it should apply deep patches to maps", () => { - // If user does not transpile const/let to var, trying to call Late' subType - // property getter during map's tryCollectModelTypes() will throw ReferenceError. - // But if it's transpiled to var, then subType will become 'undefined'. - const NodeMap = types.model("NodeMap", { - id: types.identifierNumber, - text: "Hi", - children: types.optional(types.map(types.late((): IAnyModelType => NodeMap)), {}) - }) - testPatches( - NodeMap, - { id: 1, children: { 2: { id: 2 } } }, - (n: Instance) => { - const children = n.children as IMSTMap - children.get("2")!.text = "test" // update - children.put({ id: 2, text: "world" }) // this reconciles; just an update - children.set( - "4", - NodeMap.create({ id: 4, text: "coffee", children: { 23: { id: 23 } } }) - ) // new object - children.put({ id: 3, text: "world", children: { 7: { id: 7 } } }) // addition - children.delete("2") // removal - }, - [ - { - op: "replace", - path: "/children/2/text", - value: "test" - }, - { - op: "replace", - path: "/children/2/text", - value: "world" - }, - { - op: "add", - path: "/children/4", - value: { - children: { - 23: { - children: {}, - id: 23, - text: "Hi" - } - }, - id: 4, - text: "coffee" - } - }, - { - op: "add", - path: "/children/3", - value: { - children: { - 7: { - children: {}, - id: 7, - text: "Hi" - } - }, - id: 3, - text: "world" - } - }, - { - op: "remove", - path: "/children/2" - } - ] - ) -}) - -test("it should apply deep patches to objects", () => { - const NodeObject = types.model("NodeObject", { - id: types.identifierNumber, - text: "Hi", - child: types.maybe(types.late((): IAnyModelType => NodeObject)) - }) - testPatches( - NodeObject, - { id: 1, child: { id: 2 } }, - (n: Instance) => { - n.child!.text = "test" // update - n.child = cast({ id: 2, text: "world" }) // this reconciles; just an update - n.child = NodeObject.create({ id: 2, text: "coffee", child: { id: 23 } }) - n.child = cast({ id: 3, text: "world", child: { id: 7 } }) // addition - n.child = undefined // removal - }, - [ - { - op: "replace", - path: "/child/text", - value: "test" - }, - { - op: "replace", - path: "/child/text", - value: "world" - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 23, - text: "Hi" - }, - id: 2, - text: "coffee" - } - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 7, - text: "Hi" - }, - id: 3, - text: "world" - } - }, - { - op: "replace", - path: "/child", - value: undefined - } - ] - ) -}) - -test("it should correctly split/join json patches", () => { - function isValid(str: string, array: string[], altStr?: string) { - expect(splitJsonPath(str)).toEqual(array) - expect(joinJsonPath(array)).toBe(altStr !== undefined ? altStr : str) - } - - isValid("", []) - isValid("/", [""]) - isValid("//", ["", ""]) - isValid("/a", ["a"]) - isValid("/a/", ["a", ""]) - isValid("/a//", ["a", "", ""]) - isValid(".", ["."]) - isValid("..", [".."]) - isValid("./a", [".", "a"]) - isValid("../a", ["..", "a"]) - isValid("/.a", [".a"]) - isValid("/..a", ["..a"]) - - // rooted relatives are equivalent to plain relatives - isValid("/.", ["."], ".") - isValid("/..", [".."], "..") - isValid("/./a", [".", "a"], "./a") - isValid("/../a", ["..", "a"], "../a") - - function isInvalid(str: string) { - expect(() => { - splitJsonPath(str) - }).toThrow("a json path must be either rooted, empty or relative") - } - - isInvalid("a") - isInvalid("a/") - isInvalid("a//") - isInvalid(".a") - isInvalid(".a/") - isInvalid("..a") - isInvalid("..a/") -}) - -test("it should correctly escape/unescape json patches", () => { - expect(escapeJsonPath("http://example.com")).toBe("http:~1~1example.com") - - const AppStore = types.model({ - items: types.map(types.frozen()) - }) - testPatches( - AppStore, - { items: {} }, - (store: typeof AppStore.Type) => { - store.items.set("with/slash~tilde", 1) - }, - [{ op: "add", path: "/items/with~1slash~0tilde", value: 1 }] - ) -}) - -test("weird keys are handled correctly", () => { - const Store = types.model({ - map: types.map( - types.model({ - model: types.model({ - value: types.string - }) - }) - ) - }) - - const store = Store.create({ - map: { - "": { model: { value: "val1" } }, - "/": { model: { value: "val2" } }, - "~": { model: { value: "val3" } } - } - }) - - { - const target = store.map.get("")!.model - const path = getPath(target) - expect(path).toBe("/map//model") - expect(resolvePath(store, path)).toBe(target) - } - { - const target = store.map.get("/")!.model - const path = getPath(target) - expect(path).toBe("/map/~1/model") - expect(resolvePath(store, path)).toBe(target) - } - { - const target = store.map.get("~")!.model - const path = getPath(target) - expect(path).toBe("/map/~0/model") - expect(resolvePath(store, path)).toBe(target) - } -}) - -test("relativePath with a different base than the root works correctly", () => { - const Store = types.model({ - map: types.map( - types.model({ - model: types.model({ - value: types.string - }) - }) - ) - }) - - const store = Store.create({ - map: { - "1": { model: { value: "val1" } }, - "2": { model: { value: "val2" } } - } - }) - - { - const target = store.map.get("1")!.model - expect(resolvePath(store.map, "./1/model")).toBe(target) - expect(resolvePath(store.map, "../map/1/model")).toBe(target) - // rooted relative should resolve to the given base as root - expect(resolvePath(store.map, "/./1/model")).toBe(target) - expect(resolvePath(store.map, "/../map/1/model")).toBe(target) - } - { - const target = store.map.get("2")!.model - expect(resolvePath(store.map, "./2/model")).toBe(target) - expect(resolvePath(store.map, "../map/2/model")).toBe(target) - // rooted relative should resolve to the given base as root - expect(resolvePath(store.map, "/./2/model")).toBe(target) - expect(resolvePath(store.map, "/../map/2/model")).toBe(target) - } -}) diff --git a/packages/mobx-state-tree/__tests__/core/late.test.ts b/packages/mobx-state-tree/__tests__/core/late.test.ts deleted file mode 100644 index cf1666ae9..000000000 --- a/packages/mobx-state-tree/__tests__/core/late.test.ts +++ /dev/null @@ -1,133 +0,0 @@ -import { types, typecheck, IAnyModelType } from "../../src" - -if (process.env.NODE_ENV !== "production") { - test("it should throw if late doesnt received a function as parameter", () => { - expect(() => { - types.model({ - after: types.late(1 as any) - }) - }).toThrow() - }) -} -test("it should accept a type and infer it correctly", () => { - const Before = types.model({ - after: types.late(() => After) - }) - const After = types.model({ - name: types.maybe(types.string) - }) - expect(() => Before.create({ after: { name: "Hello, it's me." } })).not.toThrow() -}) -test("late should allow circular references", () => { - // TypeScript is'nt smart enough to infer self referencing types. - const Node = types.model({ - childs: types.optional(types.array(types.late((): IAnyModelType => Node)), []) - }) - expect(() => Node.create()).not.toThrow() - expect(() => Node.create({ childs: [{}, { childs: [] }] })).not.toThrow() -}) -test("late should describe correctly circular references", () => { - // TypeScript is'nt smart enough to infer self referencing types. - const Node = types.model("Node", { - childs: types.array(types.late((): IAnyModelType => Node)) - }) - expect(Node.describe()).toEqual("{ childs: late(() => Node)[]? }") -}) -test("should typecheck", () => { - const NodeObject = types.model("NodeObject", { - id: types.identifierNumber, - text: "Hi", - child: types.maybe(types.late((): IAnyModelType => NodeObject)) - }) - const x = NodeObject.create({ id: 1 }) - try { - ;(x as any).child = 3 - ;(x as any).floepie = 3 - } catch (e) { - // ignore, this is about TS - } -}) - -test("typecheck should throw an Error when called at runtime, but not log the error", () => { - const consoleSpy = jest.spyOn(console, "error").mockImplementation(() => {}) - - const NodeObject = types.model("NodeObject", { - id: types.identifierNumber, - text: types.string - }) - - expect(() => { - typecheck(NodeObject, { id: 1, text: 1 } as any) - }).toThrow() - - try { - typecheck(NodeObject, { id: 1, text: 1 } as any) - } catch (error) { - expect(error).toBeDefined() - expect(consoleSpy).not.toHaveBeenCalled() - } -}) - -test("#825, late type checking ", () => { - const Product = types.model({ - details: types.late(() => types.optional(Details, {})) - }) - const Details = types.model({ - name: types.maybe(types.string) - }) - - const p2 = Product.create({}) - const p = Product.create({ details: { name: "bla" } }) -}) - -test("#916 - 0", () => { - const Todo = types.model("Todo", { - title: types.string, - newTodo: types.optional( - types.late((): IAnyModelType => Todo), - {} - ) // N.B. this definition is never instantiateable! - }) -}) - -test("#916 - 1", () => { - const Todo = types.model("Todo", { - title: types.string, - newTodo: types.maybe(types.late((): IAnyModelType => Todo)) - }) - const t = Todo.create({ - title: "Get Coffee" - }) -}) - -test("#916 - 2", () => { - const Todo = types.model("Todo", { - title: types.string, - newTodo: types.maybe(types.late((): IAnyModelType => Todo)) - }) - expect( - Todo.is({ - title: "A", - newTodo: { title: " test" } - }) - ).toBe(true) - expect( - Todo.is({ - title: "A", - newTodo: { title: 7 } - }) - ).toBe(false) -}) - -test("#916 - 3", () => { - const Todo = types.model("Todo", { - title: types.string, - newTodo: types.maybe(types.late((): IAnyModelType => Todo)) - }) - const t = Todo.create({ - title: "Get Coffee", - newTodo: { title: "test" } - }) - - expect(t.newTodo!.title).toBe("test") -}) diff --git a/packages/mobx-state-tree/__tests__/core/lazy.test.ts b/packages/mobx-state-tree/__tests__/core/lazy.test.ts deleted file mode 100644 index 0d38edd48..000000000 --- a/packages/mobx-state-tree/__tests__/core/lazy.test.ts +++ /dev/null @@ -1,111 +0,0 @@ -import { when } from "mobx" -import { getRoot, types } from "../../src" - -interface IRootModel { - shouldLoad: boolean -} - -test("it should load the correct type", async () => { - const LazyModel = types - .model("LazyModel", { - width: types.number, - height: types.number - }) - .views((self) => ({ - get area() { - return self.height * self.width - } - })) - - const Root = types - .model("Root", { - shouldLoad: types.optional(types.boolean, false), - lazyModel: types.lazy("lazy", { - loadType: () => Promise.resolve(LazyModel), - shouldLoadPredicate: (parent) => parent.shouldLoad == true - }) - }) - .actions((self) => ({ - load: () => { - self.shouldLoad = true - } - })) - - const store = Root.create({ - lazyModel: { - width: 3, - height: 2 - } - }) - - expect(store.lazyModel.width).toBe(3) - expect(store.lazyModel.height).toBe(2) - expect(store.lazyModel.area).toBeUndefined() - store.load() - const promise = new Promise((resolve, reject) => { - when( - () => store.lazyModel && store.lazyModel.area !== undefined, - () => resolve(store.lazyModel.area) - ) - - setTimeout(reject, 2000) - }) - - await expect(promise).resolves.toBe(6) -}) - -test("maintains the tree structure when loaded", async () => { - const LazyModel = types - .model("LazyModel", { - width: types.number, - height: types.number - }) - .views((self) => ({ - get area() { - const root = getRoot<{ rootValue: number }>(self) - return self.height * self.width * root.rootValue - } - })) - - const Root = types - .model("Root", { - shouldLoad: types.optional(types.boolean, false), - lazyModel: types.lazy("lazy", { - loadType: () => Promise.resolve(LazyModel), - shouldLoadPredicate: (parent) => parent.shouldLoad == true - }) - }) - .views(() => ({ - get rootValue() { - return 5 - } - })) - .actions((self) => ({ - load: () => { - self.shouldLoad = true - } - })) - - const store = Root.create({ - lazyModel: { - width: 3, - height: 2 - } - }) - - expect(store.lazyModel.width).toBe(3) - expect(store.lazyModel.height).toBe(2) - expect(store.rootValue).toEqual(5) - expect(store.lazyModel.area).toBeUndefined() - store.load() - const promise = new Promise((resolve, reject) => { - when( - () => store.lazyModel && store.lazyModel.area !== undefined, - () => resolve(store.lazyModel.area) - ) - - setTimeout(reject, 2000) - }) - - await expect(promise).resolves.toBe(30) -}) diff --git a/packages/mobx-state-tree/__tests__/core/literal.test.ts b/packages/mobx-state-tree/__tests__/core/literal.test.ts deleted file mode 100644 index 3fd51bd78..000000000 --- a/packages/mobx-state-tree/__tests__/core/literal.test.ts +++ /dev/null @@ -1,50 +0,0 @@ -import { types } from "../../src" - -if (process.env.NODE_ENV !== "production") { - test("it should allow only primitives", () => { - const error = expect(() => { - types.model({ - complexArg: types.literal({ a: 1 } as any) - }) - }).toThrowError("expected primitive as argument") - }) - test("it should fail if not optional and no default provided", () => { - const Factory = types.literal("hello") - expect(() => { - ;(Factory.create as any)() - }).toThrow(/is not assignable to type/) - }) - test("it should throw if a different type is given", () => { - const Factory = types.model("TestFactory", { - shouldBeOne: types.literal(1) - }) - expect(() => { - Factory.create({ shouldBeOne: 2 as any }) - }).toThrow(/is not assignable to type/) - }) -} -test("it should support null type", () => { - const M = types.model({ - nullish: types.null - }) - expect( - M.is({ - nullish: null - }) - ).toBe(true) - expect(M.is({ nullish: undefined })).toBe(false) - expect(M.is({ nullish: 17 })).toBe(false) -}) -test("it should support undefined type", () => { - const M = types.model({ - undefinedish: types.undefined - }) - expect( - M.is({ - undefinedish: undefined - }) - ).toBe(true) - expect(M.is({})).toBe(true) // MWE: disputable, should be false? - expect(M.is({ undefinedish: null })).toBe(false) - expect(M.is({ undefinedish: 17 })).toBe(false) -}) diff --git a/packages/mobx-state-tree/__tests__/core/map.test.ts b/packages/mobx-state-tree/__tests__/core/map.test.ts deleted file mode 100644 index b1f13bfd6..000000000 --- a/packages/mobx-state-tree/__tests__/core/map.test.ts +++ /dev/null @@ -1,592 +0,0 @@ -import { configure } from "mobx" -import { - onSnapshot, - onPatch, - applyPatch, - applySnapshot, - getSnapshot, - types, - unprotect, - isStateTreeNode, - SnapshotOut, - IJsonPatch, - IAnyModelType, - detach -} from "../../src" - -const createTestFactories = () => { - const ItemFactory = types.model({ - to: "world" - }) - const Factory = types.map(ItemFactory) - const PrimitiveMapFactory = types.model({ - boolean: types.map(types.boolean), - string: types.map(types.string), - number: types.map(types.number) - }) - return { Factory, ItemFactory, PrimitiveMapFactory } -} -// === FACTORY TESTS === -test("it should create a factory", () => { - const { Factory } = createTestFactories() - const snapshot = getSnapshot(Factory.create()) - expect(snapshot).toEqual({}) -}) -test("it should succeed if not optional and no default provided", () => { - const Factory = types.map(types.string) - expect(Factory.create().toJSON()).toEqual({}) -}) -test("it should restore the state from the snapshot", () => { - const { Factory } = createTestFactories() - const instance = Factory.create({ hello: { to: "world" } }) - expect(getSnapshot(instance)).toEqual({ hello: { to: "world" } }) - expect(("" + instance).replace(/@\d+/, "@xx")).toBe("[object ObservableMap]") // default toString -}) -// === SNAPSHOT TESTS === -test("it should emit snapshots", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let snapshots: SnapshotOut[] = [] - onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) - doc.set("hello", ItemFactory.create()) - expect(snapshots).toEqual([{ hello: { to: "world" } }]) -}) -test("it should apply snapshots", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applySnapshot(doc, { hello: { to: "universe" } }) - expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) -}) -test("it should return a snapshot", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.set("hello", ItemFactory.create()) - expect(getSnapshot(doc)).toEqual({ hello: { to: "world" } }) -}) -test("it should be the same each time", () => { - const { PrimitiveMapFactory } = createTestFactories() - const data = { - string: { a: "a", b: "" }, - boolean: { a: true, b: false }, - number: { a: 0, b: 42, c: NaN } - } - const doc = PrimitiveMapFactory.create(data) - expect(getSnapshot(doc)).toEqual(data) - applySnapshot(doc, data) - expect(getSnapshot(doc)).toEqual(data) - applySnapshot(doc, data) - expect(getSnapshot(doc)).toEqual(data) -}) -// === PATCHES TESTS === -test("it should emit add patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.set("hello", ItemFactory.create({ to: "universe" })) - expect(patches).toEqual([{ op: "add", path: "/hello", value: { to: "universe" } }]) -}) -test("it should apply an add patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, { op: "add", path: "/hello", value: { to: "universe" } }) - expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) -}) -test("it should emit update patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.set("hello", ItemFactory.create()) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.set("hello", ItemFactory.create({ to: "universe" })) - expect(patches).toEqual([{ op: "replace", path: "/hello", value: { to: "universe" } }]) -}) -test("it should apply an update patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - applyPatch(doc, { op: "replace", path: "/hello", value: { to: "universe" } }) - expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) -}) -test("it should emit remove patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.set("hello", ItemFactory.create()) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.delete("hello") - expect(patches).toEqual([{ op: "remove", path: "/hello" }]) -}) -test("it should apply a remove patch", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - doc.set("hello", ItemFactory.create()) - applyPatch(doc, { op: "remove", path: "/hello" }) - expect(getSnapshot(doc)).toEqual({}) -}) -test("it should apply patches", () => { - const { Factory, ItemFactory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, [ - { op: "add", path: "/hello", value: { to: "mars" } }, - { op: "replace", path: "/hello", value: { to: "universe" } } - ]) - expect(getSnapshot(doc)).toEqual({ hello: { to: "universe" } }) -}) -// === TYPE CHECKS === -test("it should check the type correctly", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - expect(Factory.is(doc)).toEqual(true) - expect(Factory.is([])).toEqual(false) - expect(Factory.is({})).toEqual(true) - expect(Factory.is({ hello: { to: "mars" } })).toEqual(true) - expect(Factory.is({ hello: { wrongKey: true } })).toEqual(true) - expect(Factory.is({ hello: { to: true } })).toEqual(false) -}) -test("it should support identifiers", () => { - configure({ - useProxies: "never" - }) - - const Store = types.model({ - todos: types.optional( - types.map( - types.model({ - id: types.identifier - }) - ), - {} - ) - }) - const store = Store.create() - unprotect(store) - store.todos.set("17", { id: "17" }) - const a = store.todos.get("17") - applySnapshot(store.todos, { "16": { id: "16" }, "17": { id: "17" } }) - expect(a === store.todos.get("17")).toBe(true) // same instance still - expect(store.todos.get("17")!.id).toBe("17") - store.todos.put({ id: "19" }) - expect(store.todos.get("19")!.id).toBe("19") - expect("" + store.todos.get("19")).toBe("AnonymousModel@/todos/19(id: 19)") - if (process.env.NODE_ENV !== "production") { - expect(() => applySnapshot(store.todos, { "17": { id: "18" } })).toThrowError( - "[mobx-state-tree] A map of objects containing an identifier should always store the object under their own identifier. Trying to store key '18', but expected: '17'" - ) - } -}) -test("#184 - types.map().get(key) should not throw if key doesnt exists", () => { - const { Factory } = createTestFactories() - const doc = Factory.create({ - hello: { - to: "world" - } - }) - expect(() => { - doc.get("notexistingkey") - }).not.toThrow() -}) -test("#192 - put should not throw when identifier is a number", () => { - const Todo = types.model("Todo", { todo_id: types.identifierNumber, title: types.string }) - const TodoStore = types - .model("TodoStore", { - todos: types.optional(types.map(Todo), {}) - }) - .actions((self) => { - function addTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { - self.todos.put(todo) - } - return { - addTodo - } - }) - const todoStore = TodoStore.create({}) - expect(() => { - todoStore.addTodo({ - todo_id: 1, - title: "Test" - }) - }).not.toThrow() - if (process.env.NODE_ENV !== "production") { - expect(() => { - todoStore.addTodo({ todo_id: "1", title: "Test" } as any) - }).toThrowError( - 'at path "/todo_id" value `"1"` is not assignable to type: `identifierNumber` (Value is not a valid identifierNumber, expected a number)' - ) - } -}) -test("#192 - map should not mess up keys when putting twice", () => { - const Todo = types.model("Todo", { todo_id: types.identifierNumber, title: types.string }) - const TodoStore = types - .model("TodoStore", { - todos: types.optional(types.map(Todo), {}) - }) - .actions((self) => { - function addTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { - self.todos.put(todo) - } - return { - addTodo - } - }) - const todoStore = TodoStore.create({}) - todoStore.addTodo({ - todo_id: 1, - title: "Test" - }) - expect(getSnapshot(todoStore.todos)).toEqual({ "1": { todo_id: 1, title: "Test" } }) - todoStore.addTodo({ - todo_id: 1, - title: "Test Edited" - }) - expect(getSnapshot(todoStore.todos)).toEqual({ "1": { todo_id: 1, title: "Test Edited" } }) -}) -test("#694 - map.put should return new node", () => { - configure({ - useProxies: "never" - }) - - const Todo = types.model("Todo", { - todo_id: types.identifier, - title: types.string - }) - const TodoStore = types - .model("TodoStore", { - todos: types.map(Todo) - }) - .actions((self) => { - function addAndReturnTodo(todo: typeof Todo.Type | typeof Todo.CreationType) { - return self.todos.put(todo) - } - return { - addAndReturnTodo - } - }) - const todoStore = TodoStore.create({ todos: {} }) - - const addedTodo = todoStore.addAndReturnTodo( - Todo.create({ - todo_id: "1", - title: "Test 1" - }) - ) - - expect(isStateTreeNode(addedTodo)).toEqual(true) - expect(getSnapshot(addedTodo)).toEqual({ todo_id: "1", title: "Test 1" }) - - const editedTodo = todoStore.addAndReturnTodo({ - todo_id: "1", - title: "Test 1 Edited" - }) - expect(isStateTreeNode(editedTodo)).toEqual(true) - expect(getSnapshot(editedTodo)).toEqual({ todo_id: "1", title: "Test 1 Edited" }) - expect(editedTodo).toEqual(addedTodo) - - const addedTodo2 = todoStore.addAndReturnTodo({ - todo_id: "2", - title: "Test 2" - }) - expect(isStateTreeNode(addedTodo2)).toEqual(true) - expect(getSnapshot(addedTodo2)).toEqual({ todo_id: "2", title: "Test 2" }) -}) -test("it should not throw when removing a non existing item from a map", () => { - expect(() => { - const AppModel = types - .model({ - myMap: types.map(types.number) - }) - .actions((self) => { - function something() { - return self.myMap.delete("1020") - } - return { - something - } - }) - const store = AppModel.create() - expect(store.something()).toBe(false) - }).not.toThrow() -}) -test("it should get map keys from reversePatch when deleted an item from a nested map", () => { - const AppModel = types - .model({ - value: types.map(types.map(types.map(types.number))) - }) - .actions((self) => ({ - remove(k: string) { - self.value.delete(k) - } - })) - const store = AppModel.create({ value: { a: { b: { c: 10 } } } }) - onPatch(store, (patch, reversePatch) => { - expect(patch).toEqual({ op: "remove", path: "/value/a" }) - expect(reversePatch).toEqual({ op: "add", path: "/value/a", value: { b: { c: 10 } } }) - }) - store.remove("a") -}) - -test("map expects regular identifiers", () => { - const A = types.model("A", { a: types.identifier }) - const B = types.model("B", { b: types.identifier }) - - // NOTE: we can determine identifier attribute upfront, so no need to wait for error while craetion - expect(() => types.map(types.union(A, B))).toThrow( - `[mobx-state-tree] The objects in a map should all have the same identifier attribute, expected 'a', but child of type 'B' declared attribute 'b' as identifier` - ) -}) - -test("issue #876 - map.put works fine for models with preProcessSnapshot", () => { - const Note = types.model("Item", { - text: types.string - }) - const Item = types - .model("Item", { - id: types.identifier, - title: types.string, - notes: types.array(Note) - }) - .preProcessSnapshot((snapshot) => { - const result = Object.assign({}, snapshot) - if (typeof result.title !== "string") result.title = "" - return result - }) - - const Store = types - .model("Store", { - items: types.optional(types.map(Item), {}) - }) - .actions((self) => ({ - afterCreate() { - self.items.put({ - id: "1", - title: "", - notes: [{ text: "first note" }, { text: "second note" }] - }) - } - })) - - let store!: typeof Store.Type - expect(() => { - store = Store.create({}) - }).not.toThrow() - expect(getSnapshot(store)).toEqual({ - items: { - "1": { - id: "1", - notes: [{ text: "first note" }, { text: "second note" }], - title: "" - } - } - }) -}) - -test("map can resolve late identifiers", () => { - const Late = types.model({ - id: types.identifier, - children: types.map(types.late((): IAnyModelType => Late)) - }) - const snapshot = { - id: "1", - children: { - "2": { - id: "2", - children: {} - } - } - } - expect(() => Late.create(snapshot)).not.toThrow() -}) - -test("get should return value when key is a number", () => { - const Todo = types.model("Todo", { - todo_id: types.identifierNumber, - title: types.string - }) - const TodoStore = types - .model("TodoStore", { - todos: types.optional(types.map(Todo), {}) - }) - .actions((self) => { - function addTodo(aTodo: typeof Todo.Type | typeof Todo.CreationType) { - self.todos.put(aTodo) - } - return { - addTodo - } - }) - const todoStore = TodoStore.create({}) - - const todo = { - todo_id: 1, - title: "Test" - } - - todoStore.addTodo(todo) - expect(todoStore.todos.get(1 as any as string)!.title).toEqual("Test") -}) - -test("numeric keys should work", () => { - const M = types.model({ - id: types.identifier, - title: "test" - }) - const S = types.model({ - mies: types.map(M), - ref: types.maybe(types.reference(M)) - }) - - const s = S.create({ - mies: {} - }) - unprotect(s) - - s.mies.set(7, { id: "7" }) - const i7 = s.mies.get(7)! - expect(i7.title).toBe("test") - expect(s.mies.has("7")).toBeTruthy() - expect(s.mies.has(7 as any as string)).toBeTruthy() - expect(s.mies.get("7")).toBeTruthy() - expect(s.mies.get(7 as any as string)).toBeTruthy() - - s.mies.set("8", { id: "8" }) - expect(s.mies.has("8")).toBeTruthy() - expect(s.mies.has(8 as any as string)).toBeTruthy() - expect(s.mies.get("8")).toBeTruthy() - expect(s.mies.get(8 as any as string)).toBeTruthy() - - expect(Array.from(s.mies.keys())).toEqual(["7", "8"]) - - s.mies.put({ id: "7", title: "coffee" }) - expect(s.mies.size).toBe(2) - expect(s.mies.has("7")).toBeTruthy() - expect(s.mies.has(7 as any as string)).toBeTruthy() - expect(s.mies.get("7")).toBeTruthy() - expect(s.mies.get(7 as any as string)).toBeTruthy() - expect(i7.title).toBe("coffee") - - expect(s.mies.delete(8 as any as string)).toBeTruthy() - expect(s.mies.size).toBe(1) -}) - -describe("#826, adding stuff twice", () => { - const Store = types - .model({ - map: types.optional(types.map(types.boolean), {}) - }) - .actions((self) => ({ - toogleMap: (id: string) => { - self.map.set(id, !self.map.get(id)) - } - })) - - // This one pass fine 👍 - test("Toogling once shouldn't throw", () => { - const store = Store.create({}) - expect(() => { - store.toogleMap("1") - }).not.toThrow() - }) - - // This one throws with 'Not a child 1' error 👎 - test("Toogling twice shouldn't throw", () => { - const store = Store.create({}) - expect(() => { - store.toogleMap("1") - store.toogleMap("1") - }).not.toThrow() - }) -}) - -test("#751 restore from snapshot should work", () => { - const Submodel = types.model("Submodel", { - id: types.identifierNumber - }) - - const Model = types.model("Model", { - map: types.map(Submodel) - }) - - const server = Model.create({ map: {} }) - - // We add an item with a number id - unprotect(server) - server.map.set(1 as any as string, { id: 1 }) - - // We can access it using a number - expect(server.map.get(1 as any as string)!.id).toBe(1) - - // But if we get a snapshot... - const snapshot = getSnapshot(server) - // And apply it back... - const browser = Model.create(snapshot) - - // We can access it using a string - expect(server.map.get("1")!.id).toBe(1) - - // And as number - expect(server.map.get(1 as any as string)!.id).toBe(1) - - expect(server.map.size).toBe(1) -}) - -test("#1173 - detaching a map should not eliminate its children", () => { - const M = types.model({}) - const AM = types.map(M) - const Store = types.model({ items: AM }) - const s = Store.create({ items: { x: {}, y: {}, z: {} } }) - const n0 = s.items.get("x") - - unprotect(s) - - const detachedItems = detach(s.items) - expect(s.items).not.toBe(detachedItems) - expect(s.items.size).toBe(0) - expect(detachedItems.size).toBe(3) - expect(detachedItems.get("x")).toBe(n0) -}) - -test("#1131 - put with optional identifier", () => { - const Test = types.model({ - id: types.optional(types.identifier, () => Math.random().toString(36).substr(2)), - value: "hi" - }) - - const myMap = types.map(Test).create() - unprotect(myMap) - const val = myMap.put({}) - expect(val.id).toBeTruthy() - expect(val.value).toBe("hi") -}) - -/** - * This test exercises the TypeScript types fo `MSTMap`, to ensure that our typings stay consistent. In PR #2072, - * we changed from accepting `[string, any][] | IKeyValueMap | Map | undefined,` in `initialdata` - * to accepting `IObservableMapInitialValues | undefined,`. - * - * This test demonstrates backwards compatibility for the change, and will let us know if anything changes and breaks - * if we ever update those types as well, or if MobX changes the exported `IObservableMapInitialValues` type. - * - * It looks like `[string, any][]` and `Map` are actually not supported, so we just test the `IKeyValueMap` and `undefined` cases - * for now. See https://github.com/mobxjs/mobx-state-tree/pull/2072#issuecomment-1747482100 - */ -describe("#2072 - IObservableMapInitialValues types should work correctly", () => { - it("should accept IKeyValueMap", () => { - const initialData = { - "1": "Tyler", - "2": "Jamon" - } - - const mapInstance = types.map(types.string).create(initialData) - expect(mapInstance.size).toBe(2) - }) - it("should accept undefined", () => { - const mapInstance = types.map(types.string).create(undefined) - expect(mapInstance.size).toBe(0) - }) -}) diff --git a/packages/mobx-state-tree/__tests__/core/model.test.ts b/packages/mobx-state-tree/__tests__/core/model.test.ts deleted file mode 100644 index fe131bacd..000000000 --- a/packages/mobx-state-tree/__tests__/core/model.test.ts +++ /dev/null @@ -1,426 +0,0 @@ -import { applySnapshot, getSnapshot, types } from "../../src" -import { Hook } from "../../src/internal" - -test("it should call preProcessSnapshot with the correct argument", () => { - const onSnapshot = jest.fn((snapshot: any) => { - return { - val: snapshot.val + 1 - } - }) - - const Model = types - .model({ - val: types.number - }) - .preProcessSnapshot(onSnapshot) - - const model = Model.create({ val: 0 }) - applySnapshot(model, { val: 1 }) - expect(onSnapshot).lastCalledWith({ val: 1 }) -}) -describe("Model instantiation", () => { - describe("Model name", () => { - test("Providing a string as the first argument should set it as the model's name.", () => { - const Model = types.model("Name", {}) - - expect(Model.name).toBe("Name") - }) - test("Providing an empty string as the first argument should set it as the model's name.", () => { - const Model = types.model("", {}) - - expect(Model.name).toBe("") - }) - describe("Providing a non-string argument as the first argument should set the model's name as 'AnonymousModel'.", () => { - const testCases = [ - {}, - null, - undefined, - 1, - true, - [], - function () {}, - new Date(), - /a/, - new Map(), - new Set(), - Symbol(), - new Error(), - NaN, - Infinity - ] - - testCases.forEach((testCase) => { - test(`Providing ${JSON.stringify( - testCase - )} as the first argument should set the model's name as 'AnonymousModel'.`, () => { - const Model = types.model(testCase as any) - - expect(Model.name).toBe("AnonymousModel") - }) - }) - }) - }) - describe("Model properties", () => { - test("Providing a string as the first argument and an object as the second argument should use the object's properties in the model.", () => { - const Model = types.model("name", { - prop1: "prop1", - prop2: 2 - }) - - expect(Model.properties).toHaveProperty("prop1") - expect(Model.properties).toHaveProperty("prop2") - }) - test("Providing an object as the first argument should parse and use its properties.", () => { - const Model = types.model({ - prop1: "prop1", - prop2: 2 - }) - - expect(Model.properties).toHaveProperty("prop1") - expect(Model.properties).toHaveProperty("prop2") - }) - test("Providing a string as the first argument and a falsy value as the second argument should result in an empty set of properties.", () => { - const Model = types.model("name", null as any) - - expect(Model.properties).toEqual({}) - }) - }) - describe("Model identifier", () => { - test("If no identifier attribute is provided, the identifierAttribute should be undefined.", () => { - const Model = types.model("name", {}) - - expect(Model.identifierAttribute).toBeUndefined() - }) - test("If an identifier attribute is provided, the identifierAttribute should be set for the object.", () => { - const Model = types.model("name", { - id: types.identifier - }) - - expect(Model.identifierAttribute).toBe("id") - }) - test("If an identifier attribute has already been provided, an error should be thrown when attempting to provide a second one.", () => { - expect(() => { - types.model("name", { - id: types.identifier, - id2: types.identifier - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Cannot define property 'id2' as object identifier, property 'id' is already defined as identifier property"` - ) - }) - }) - describe("Edge case behavior", () => { - describe("when we provide no arguments to the function", () => { - test("the model will be named AnonymousModel", () => { - const Model = types.model() - - expect(Model.name).toBe("AnonymousModel") - }) - test("the model will have no properties", () => { - const Model = types.model() - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({}) - }) - }) - test("the model will have no properties", () => { - const Model = types.model() - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({}) - }) - if (process.env.NODE_ENV !== "production") { - test("it should not throw an error", () => { - expect(() => { - types.model() - }).not.toThrow() - }) - } - }) - describe("when we provide an invalid name value, but a valid property object", () => { - if (process.env.NODE_ENV === "production") { - test("the model will be named AnonymousModel", () => { - const Model = types.model(null as any, { - prop1: "prop1", - prop2: 2 - }) - - expect(Model.name).toBe("AnonymousModel") - }) - test("the model will have no properties", () => { - const Model = types.model(null as any, { - prop1: "prop1", - prop2: 2 - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({}) - }) - } else { - test("it should complain about invalid name", () => { - expect(() => { - types.model(null as any, { - prop1: "prop1", - prop2: 2 - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Model creation failed. First argument must be a string when two arguments are provided"` - ) - }) - } - }) - describe("when we provide three arguments to the function", () => { - test("the model gets the correct name", () => { - // @ts-ignore - const Model = types.model("name", {}, {}) - - expect(Model.name).toBe("name") - }) - test("the model gets the correct properties", () => { - const Model = types.model( - "name", - { - prop1: "prop1", - prop2: 2 - }, - // @ts-ignore - {} - ) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - prop1: "prop1", - prop2: 2 - }) - }) - }) - - describe("When a model has duplicate key in actions or views", () => { - test("it should show friendly message", () => { - const UserModel = types - .model("UserModel", { - id: types.identifier, - name: types.string - }) - .views((user) => ({ - get name() { - return user.name - } - })) - - expect(() => - UserModel.create({ - id: "chakri", - name: "Subramanya Chakravarthy" - }) - ).toThrow("[mobx-state-tree] name property is declared twice") - }) - }) -}) -describe("Model properties objects", () => { - describe("when a user names a property the same as an MST lifecycle hook", () => { - test("it throws an error", () => { - const hookValues = Object.values(Hook) - - hookValues.forEach((hook) => { - expect(() => { - types.model({ - [hook]: types.string - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Hook '${hook}' was defined as property. Hooks should be defined as part of the actions"` - ) - }) - }) - }) - describe("when a user attempts to define a property with the get keyword", () => { - test("it throws an error", () => { - expect(() => { - types.model({ - get foo() { - return "bar" - } - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Getters are not supported as properties. Please use views instead"` - ) - }) - }) - describe("when a user attempts to define a property with null as the value", () => { - test("it throws an error", () => { - expect(() => { - types.model({ - foo: null as any - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean \`types.maybe(someType)\`?"` - ) - }) - }) - describe("when a user attempts to define a property with undefined as the value", () => { - test("it throws an error", () => { - expect(() => { - types.model({ - foo: undefined as any - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean \`types.maybe(someType)\`?"` - ) - }) - }) - describe("when a user defines a property using a primitive value (not null or undefined)", () => { - describe("and the primitive value is a string", () => { - test("it converts a string to an optional string", () => { - const Model = types.model({ - foo: "bar" - }) - - const modelDescription = Model.describe() - expect(modelDescription).toBe("{ foo: string? }") - }) - test("it uses the primitive value as the default value", () => { - const Model = types.model({ - foo: "bar" - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: "bar" - }) - }) - }) - describe("and the primitive value is a number", () => { - test("it converts a number to an optional number", () => { - const Model = types.model({ - foo: 1 - }) - - const modelDescription = Model.describe() - expect(modelDescription).toBe("{ foo: number? }") - }) - test("it uses the primitive value as the default value", () => { - const Model = types.model({ - foo: 1 - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: 1 - }) - }) - }) - describe("and the primitive value is a boolean", () => { - test("it converts a boolean to an optional boolean", () => { - const Model = types.model({ - foo: true - }) - - const modelDescription = Model.describe() - expect(modelDescription).toBe("{ foo: boolean? }") - }) - test("it uses the primitive value as the default value", () => { - const Model = types.model({ - foo: true - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: true - }) - }) - }) - describe("and the primitive value is a date", () => { - test("it converts a date to an optional date", () => { - const Model = types.model({ - foo: new Date() - }) - - const modelDescription = Model.describe() - expect(modelDescription).toBe("{ foo: Date? }") - }) - test("it sets a default value with the date in unix milliseconds timestamp", () => { - const date = new Date("2023-07-24T04:26:04.701Z") - const Model = types.model({ - foo: date - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: 1690172764701 - }) - }) - }) - }) - describe("when a user defines a property using a complex type", () => { - describe('and that type is "types.map"', () => { - test("it sets the default value to an empty map", () => { - const Model = types.model({ - foo: types.map(types.string) - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: {} - }) - }) - }) - describe('and that type is "types.array"', () => { - test("it sets the default value to an empty array", () => { - const Model = types.model({ - foo: types.array(types.string) - }) - - const modelSnapshot = getSnapshot(Model.create()) - expect(modelSnapshot).toEqual({ - foo: [] - }) - }) - }) - describe("and that type is another model", () => { - test("it sets the default value to the default of that model", () => { - const Todo = types.model({ - task: types.optional(types.string, "test") - }) - - const TodoStore = types.model("TodoStore", { - todo1: types.optional(Todo, () => Todo.create()) - }) - - const modelSnapshot = getSnapshot(TodoStore.create()) - expect(modelSnapshot).toEqual({ - todo1: { - task: "test" - } - }) - }) - }) - }) - describe("when a user defines a property using a function", () => { - if (process.env.NODE_ENV !== "production") { - test("it throws an error when not in production", () => { - expect(() => { - // @ts-ignore - types.model({ - foo: () => "bar" - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Invalid type definition for property 'foo', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?"` - ) - }) - } - }) - describe("when a user defins a property using a plain JavaScript object", () => { - if (process.env.NODE_ENV !== "production") { - test("it throws an error when not in production", () => { - expect(() => { - // @ts-ignore - types.model({ - foo: {} - }) - }).toThrowErrorMatchingInlineSnapshot( - `"[mobx-state-tree] Invalid type definition for property 'foo', it looks like you passed an object. Try passing another model type or a types.frozen."` - ) - }) - } - }) -}) diff --git a/packages/mobx-state-tree/__tests__/core/name.test.ts b/packages/mobx-state-tree/__tests__/core/name.test.ts deleted file mode 100644 index a647bba93..000000000 --- a/packages/mobx-state-tree/__tests__/core/name.test.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { types } from "../../src" -import { getDebugName } from "mobx" - -test("it should have a debug name", () => { - const Model = types.model("Name") - - const model = Model.create() - const array = types.array(Model).create() - const map = types.map(Model).create() - - expect(getDebugName(model)).toBe("Name") - expect(getDebugName(array)).toBe("Name[]") - expect(getDebugName(map)).toBe("Map") -}) diff --git a/packages/mobx-state-tree/__tests__/core/node.test.ts b/packages/mobx-state-tree/__tests__/core/node.test.ts deleted file mode 100644 index 79fbeea40..000000000 --- a/packages/mobx-state-tree/__tests__/core/node.test.ts +++ /dev/null @@ -1,455 +0,0 @@ -import { - getPath, - getSnapshot, - getParent, - hasParent, - getRoot, - getIdentifier, - getPathParts, - isAlive, - clone, - getType, - getChildType, - recordActions, - recordPatches, - types, - destroy, - unprotect, - hasParentOfType, - getParentOfType, - detach, - getNodeId -} from "../../src" - -import { autorun, configure } from "mobx" - -// getParent -test("it should resolve to the parent instance", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(getParent(row)).toEqual(doc.rows) -}) -// hasParent -test("it should check for parent instance", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(hasParent(row)).toEqual(true) -}) -test("it should check for parent instance (unbound)", () => { - const Row = types.model({ - article_id: 0 - }) - const row = Row.create() - expect(hasParent(row)).toEqual(false) -}) -// getParentOfType -test("it should resolve to the given parent instance", () => { - configure({ - useProxies: "never" - }) - - const Cell = types.model({}) - const Row = types.model({ - cells: types.optional(types.array(Cell), []) - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create({ - rows: [ - { - cells: [{}] - } - ] - }) - expect(getParentOfType(doc.rows[0].cells[0], Document)).toEqual(doc) -}) -test("it should throw if there is not parent of type", () => { - const Cell = types.model({}) - const Row = types.model({ - cells: types.optional(types.array(Cell), []) - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const row = Row.create({ - cells: [{}] - }) - expect(() => getParentOfType(row.cells[0], Document)).toThrowError( - "[mobx-state-tree] Failed to find the parent of AnonymousModel@/cells/0 of a given type" - ) -}) -// hasParentOfType -test("it should check for parent instance of given type", () => { - const Cell = types.model({}) - const Row = types.model({ - cells: types.optional(types.array(Cell), []) - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create({ - rows: [ - { - cells: [{}] - } - ] - }) - expect(hasParentOfType(doc.rows[0].cells[0], Document)).toEqual(true) -}) -test("it should check for parent instance of given type (unbound)", () => { - const Cell = types.model({}) - const Row = types.model({ - cells: types.optional(types.array(Cell), []) - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const row = Row.create({ - cells: [{}] - }) - expect(hasParentOfType(row.cells[0], Document)).toEqual(false) -}) -// getRoot -test("it should resolve to the root of an object", () => { - const Row = types.model("Row", { - article_id: 0 - }) - const Document = types.model("Document", { - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(getRoot(row)).toBe(doc) -}) -// getIdentifier -test("it should resolve to the identifier of the object", () => { - const Document = types.model("Document", { - id: types.identifier - }) - const doc = Document.create({ - id: "document_1" - }) - // get identifier of object - expect(getIdentifier(doc)).toBe("document_1") -}) -// getPath -test("it should resolve the path of an object", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(getPath(row)).toEqual("/rows/0") -}) -// getPathParts -test("it should resolve the path of an object", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(getPathParts(row)).toEqual(["rows", "0"]) -}) -test("it should resolve parents", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(hasParent(row)).toBe(true) // array - expect(hasParent(row, 2)).toBe(true) // row - expect(hasParent(row, 3)).toBe(false) - expect(getParent(row) === doc.rows).toBe(true) // array - expect(getParent(row, 2) === doc).toBe(true) // row - expect(() => getParent(row, 3)).toThrowError( - "[mobx-state-tree] Failed to find the parent of AnonymousModel@/rows/0 at depth 3" - ) -}) -// clone -test("it should clone a node", () => { - configure({ - useProxies: "never" - }) - - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - const cloned = clone(doc) - expect(doc).toEqual(cloned) - expect(getSnapshot(doc)).toEqual(getSnapshot(cloned)) -}) -test("it should be possible to clone a dead object", () => { - configure({ - useProxies: "never" - }) - - const Task = types.model("Task", { - x: types.string - }) - const a = Task.create({ x: "a" }) - const store = types - .model({ - todos: types.optional(types.array(Task), []) - }) - .create({ - todos: [a] - }) - unprotect(store) - expect(store.todos.slice()).toEqual([a]) - expect(isAlive(a)).toBe(true) - store.todos.splice(0, 1) - expect(isAlive(a)).toBe(false) - const a2 = clone(a) - store.todos.splice(0, 0, a2) - expect(store.todos[0].x).toBe("a") -}) -// getModelFactory -test("it should return the model factory", () => { - const Document = types.model({ - customer_id: 0 - }) - const doc = Document.create() - expect(getType(doc)).toEqual(Document) -}) -// getChildModelFactory -test("it should return the child model factory", () => { - const Row = types.model({ - article_id: 0 - }) - const ArrayOfRow = types.optional(types.array(Row), []) - const Document = types.model({ - rows: ArrayOfRow - }) - const doc = Document.create() - expect(getChildType(doc, "rows")).toEqual(ArrayOfRow) -}) -test("a node can exists only once in a tree", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - rows: types.optional(types.array(Row), []), - foos: types.optional(types.array(Row), []) - }) - const doc = Document.create() - unprotect(doc) - const row = Row.create() - doc.rows.push(row) - expect(() => { - doc.foos.push(row) - }).toThrow( - "[mobx-state-tree] Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '/foos/0', but it lives already at '/rows/0'" - ) -}) -test("make sure array filter works properly", () => { - const Row = types.model({ - done: false - }) - const Document = types - .model({ - rows: types.optional(types.array(Row), []) - }) - .actions((self) => { - function clearDone() { - self.rows.filter((row) => row.done === true).forEach(destroy) - } - return { - clearDone - } - }) - const doc = Document.create() - unprotect(doc) - const a = Row.create({ done: true }) - const b = Row.create({ done: false }) - doc.rows.push(a) - doc.rows.push(b) - doc.clearDone() - expect(getSnapshot(doc)).toEqual({ rows: [{ done: false }] }) -}) -// === RECORD PATCHES === -test("it can record and replay patches", () => { - const Row = types.model({ - article_id: 0 - }) - const Document = types.model({ - customer_id: 0, - rows: types.optional(types.array(Row), []) - }) - const source = Document.create() - unprotect(source) - const target = Document.create() - const recorder = recordPatches(source) - source.customer_id = 1 - source.rows.push(Row.create({ article_id: 1 })) - recorder.replay(target) - expect(getSnapshot(source)).toEqual(getSnapshot(target)) -}) -// === RECORD ACTIONS === -test("it can record and replay actions", () => { - const Row = types - .model({ - article_id: 0 - }) - .actions((self) => { - function setArticle(article_id: number) { - self.article_id = article_id - } - return { - setArticle - } - }) - const Document = types - .model({ - customer_id: 0, - rows: types.optional(types.array(Row), []) - }) - .actions((self) => { - function setCustomer(customer_id: number) { - self.customer_id = customer_id - } - function addRow() { - self.rows.push(Row.create()) - } - return { - setCustomer, - addRow - } - }) - const source = Document.create() - const target = Document.create() - const recorder = recordActions(source) - source.setCustomer(1) - source.addRow() - source.rows[0].setArticle(1) - recorder.replay(target) - expect(getSnapshot(source)).toEqual(getSnapshot(target)) -}) - -test("Liveliness issue #683", () => { - const User = types.model({ id: types.identifierNumber, name: types.string }) - - const Users = types - .model({ - list: types.map(User) - }) - .actions((self) => ({ - put(aUser: typeof User.CreationType | typeof User.Type) { - // if (self.has(user.id)) detach(self.get(user.id)); - self.list.put(aUser) - }, - get(id: string) { - return self.list.get(id) - }, - has(id: string) { - return self.list.has(id) - } - })) - - const users = Users.create({ - list: { - 1: { name: "Name", id: 1 } - } - }) - const user = users.get("1") - expect(user!.name).toBe("Name") - - users.put({ id: 1, name: "NameX" }) - expect(user!.name).toBe("NameX") - expect(users.get("1")!.name).toBe("NameX") -}) - -test("triggers on changing paths - 1", () => { - const Todo = types.model({ - title: types.string - }) - const App = types - .model({ - todos: types.array(Todo) - }) - .actions((self) => ({ - do(fn: () => void) { - fn() - } - })) - - const t1 = Todo.create({ title: "t1 " }) - const t2 = Todo.create({ title: "t2 " }) - - const app = App.create({ - todos: [t1] - }) - - const events: string[] = [] - const d1 = autorun(() => { - events.push("t1@" + getPath(t1)) - }) - const d2 = autorun(() => { - events.push("t2@" + getPath(t2)) - }) - - expect(events.splice(0)).toEqual(["t1@/todos/0", "t2@"]) - app.do(() => { - app.todos.unshift(t2) - }) - expect(events.splice(0)).toEqual(["t2@/todos/0", "t1@/todos/1"]) - app.do(() => { - detach(t2) - }) - expect(events.splice(0)).toEqual(["t1@/todos/0", "t2@"]) - - app.do(() => { - app.todos.splice(0) - }) - expect(events.splice(0)).toEqual(["t1@"]) -}) - -test("getNodeId works", () => { - const M = types.model({}) - const m1 = M.create() - const m2 = M.create() - const m1Id = getNodeId(m1) - const m2Id = getNodeId(m2) - expect(m1Id).toBeGreaterThan(0) - expect(m2Id).toBe(m1Id + 1) -}) diff --git a/packages/mobx-state-tree/__tests__/core/object.test.ts b/packages/mobx-state-tree/__tests__/core/object.test.ts deleted file mode 100644 index 810152298..000000000 --- a/packages/mobx-state-tree/__tests__/core/object.test.ts +++ /dev/null @@ -1,1196 +0,0 @@ -import { - destroy, - detach, - onSnapshot, - onPatch, - onAction, - applyPatch, - applyAction, - applySnapshot, - getSnapshot, - unprotect, - types, - setLivelinessChecking, - getParent, - SnapshotOut, - IJsonPatch, - ISerializedActionCall, - isAlive, - cast, - resolveIdentifier -} from "../../src" - -import { autorun, reaction, observable, configure, getDebugName } from "mobx" - -const createTestFactories = () => { - const Factory = types - .model({ - to: "world" - }) - .actions((self) => { - function setTo(to: string) { - self.to = to - } - return { - setTo - } - }) - const ComputedFactory = types - .model({ - width: 100, - height: 200 - }) - .views((self) => ({ - get area() { - return self.width * self.height - } - })) - const ComputedFactory2 = types - .model({ - props: types.map(types.number) - }) - .views((self) => ({ - get area() { - return self.props.get("width")! * self.props.get("height")! - } - })) - .actions((self) => { - function setWidth(value: number) { - self.props.set("width", value) - } - function setHeight(value: number) { - self.props.set("height", value) - } - return { - setWidth, - setHeight - } - }) - const BoxFactory = types.model({ - width: 0, - height: 0 - }) - const ColorFactory = types.model({ - color: "#FFFFFF" - }) - return { Factory, ComputedFactory, ComputedFactory2, BoxFactory, ColorFactory } -} - -const createFactoryWithChildren = () => { - const File = types - .model("File", { - name: types.string - }) - .actions((self) => ({ - rename(value: string) { - self.name = value - } - })) - - const Folder = types - .model("Folder", { - name: types.string, - files: types.array(File) - }) - .actions((self) => ({ - rename(value: string) { - self.name = value - } - })) - return Folder -} -// === FACTORY TESTS === -test("it should create a factory", () => { - const { Factory } = createTestFactories() - const instance = Factory.create() - const snapshot = getSnapshot(instance) - expect(snapshot).toEqual({ to: "world" }) - expect(getSnapshot(Factory.create())).toEqual({ to: "world" }) // toJSON is there as shortcut for getSnapshot(), primarily for debugging convenience - expect(Factory.create().toString()).toEqual("AnonymousModel@") -}) -test("it should restore the state from the snapshot", () => { - const { Factory } = createTestFactories() - expect(getSnapshot(Factory.create({ to: "universe" }))).toEqual({ to: "universe" }) -}) -// === SNAPSHOT TESTS === -test("it should emit snapshots", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let snapshots: SnapshotOut[] = [] - onSnapshot(doc, (snapshot) => snapshots.push(snapshot)) - doc.to = "universe" - expect(snapshots).toEqual([{ to: "universe" }]) -}) - -test("it should emit snapshots for children", () => { - const Factory = createFactoryWithChildren() - const folder = Factory.create({ - name: "Photos to sort", - files: [ - { - name: "Photo1" - }, - { - name: "Photo2" - } - ] - }) - let snapshotsP: SnapshotOut[] = [] - let snapshotsC: SnapshotOut[] = [] - onSnapshot(folder, (snapshot) => snapshotsP.push(snapshot)) - folder.rename("Vacation photos") - expect(snapshotsP[0]).toEqual({ - name: "Vacation photos", - files: [{ name: "Photo1" }, { name: "Photo2" }] - }) - - onSnapshot(folder.files[0], (snapshot) => snapshotsC.push(snapshot)) - folder.files[0].rename("01-arrival") - expect(snapshotsP[1]).toEqual({ - name: "Vacation photos", - files: [{ name: "01-arrival" }, { name: "Photo2" }] - }) - expect(snapshotsC[0]).toEqual({ name: "01-arrival" }) - - folder.files[1].rename("02-hotel") - expect(snapshotsP[2]).toEqual({ - name: "Vacation photos", - files: [{ name: "01-arrival" }, { name: "02-hotel" }] - }) - expect(snapshotsP.length).toBe(3) - expect(snapshotsC.length).toBe(1) -}) - -test("it should apply snapshots", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - applySnapshot(doc, { to: "universe" }) - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -test("it should apply and accept null value for types.maybe(complexType)", () => { - const Item = types.model("Item", { - value: types.string - }) - const Model = types.model("Model", { - item: types.maybe(Item) - }) - const myModel = Model.create() - applySnapshot(myModel, { item: { value: "something" } }) - applySnapshot(myModel, { item: undefined }) - expect(getSnapshot(myModel)).toEqual({ item: undefined }) -}) -test("it should apply and accept null value for types.maybeNull(complexType)", () => { - const Item = types.model("Item", { - value: types.string - }) - const Model = types.model("Model", { - item: types.maybeNull(Item) - }) - const myModel = Model.create() - applySnapshot(myModel, { item: { value: "something" } }) - applySnapshot(myModel, { item: null }) - expect(getSnapshot(myModel)).toEqual({ item: null }) -}) -test("it should return a snapshot", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - expect(getSnapshot(doc)).toEqual({ to: "world" }) -}) -// === PATCHES TESTS === -test("it should emit patches", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - doc.to = "universe" - expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) -}) -test("it should apply a patch", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, { op: "replace", path: "/to", value: "universe" }) - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -test("it should apply patches", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - applyPatch(doc, [ - { op: "replace", path: "/to", value: "mars" }, - { op: "replace", path: "/to", value: "universe" } - ]) - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -test("it should stop listening to patches patches", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - unprotect(doc) - let patches: IJsonPatch[] = [] - let disposer = onPatch(doc, (patch) => patches.push(patch)) - doc.to = "universe" - disposer() - doc.to = "mweststrate" - expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) -}) -// === ACTIONS TESTS === -test("it should call actions correctly", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - doc.setTo("universe") - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -test("it should emit action calls", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - let actions: ISerializedActionCall[] = [] - onAction(doc, (action) => actions.push(action)) - doc.setTo("universe") - expect(actions).toEqual([{ name: "setTo", path: "", args: ["universe"] }]) -}) -test("it should apply action call", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - applyAction(doc, { name: "setTo", path: "", args: ["universe"] }) - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -test("it should apply actions calls", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - applyAction(doc, [ - { name: "setTo", path: "", args: ["mars"] }, - { name: "setTo", path: "", args: ["universe"] } - ]) - expect(getSnapshot(doc)).toEqual({ to: "universe" }) -}) -// === COMPUTED VALUES === -test("it should have computed properties", () => { - const { ComputedFactory } = createTestFactories() - const doc = ComputedFactory.create() - unprotect(doc) - doc.width = 3 - doc.height = 2 - expect(doc.area).toEqual(6) -}) - -test("it should throw if a replaced object is read or written to", () => { - const Todo = types - .model("Todo", { - title: "test", - arr: types.array(types.string), - map: types.map(types.string), - sub: types.optional( - types - .model("Sub", { - title: "test2" - }) - .actions((self) => ({ - fn2() {} - })), - {} - ) - }) - .actions((self) => ({ - fn() { - self.sub.fn2() - } - })) - const Store = types.model("Store", { - todo: Todo - }) - const data = { - title: "alive", - arr: ["arr0"], - map: { mapkey0: "mapval0" }, - sub: { title: "title" } - } - const s = Store.create({ todo: { ...data, title: "dead" } }) - unprotect(s) - - const deadArr = s.todo.arr - s.todo.arr = cast(data.arr) - - const deadMap = s.todo.map - s.todo.map = cast(data.map) - - const deadSub = s.todo.sub - s.todo.sub = cast(data.sub) - - const deadTodo = s.todo - s.todo = Todo.create(data) - - expect(s.todo.title).toBe("alive") - - setLivelinessChecking("error") - - function getError(obj: any, path: string, subpath: string, action: string) { - return `You are trying to read or write to an object that is no longer part of a state tree. (Object type: '${getDebugName( - obj - )}', Path upon death: '${path}', Subpath: '${subpath}', Action: '${action}'). Either detach nodes first, or don't use objects after removing / replacing them in the tree.` - } - - // dead todo - expect(() => { - deadTodo.fn() - }).toThrow(getError(deadTodo, "/todo", "", "/todo.fn()")) - expect(() => { - // tslint:disable-next-line:no-unused-expression - deadTodo.title - }).toThrow(getError(deadTodo, "/todo", "title", "")) - expect(() => { - deadTodo.title = "5" - }).toThrow(getError(deadTodo, "/todo", "title", "")) - - expect(() => { - // tslint:disable-next-line:no-unused-expression - deadTodo.arr[0] - }).toThrow(getError(deadTodo, "/todo", "arr", "")) - expect(() => { - deadTodo.arr.push("arr1") - }).toThrow(getError(deadTodo, "/todo", "arr", "")) - - expect(() => { - deadTodo.map.get("mapkey0") - }).toThrow(getError(deadTodo, "/todo", "map", "")) - expect(() => { - deadTodo.map.set("mapkey1", "val") - }).toThrow(getError(deadTodo, "/todo", "map", "")) - - expect(() => { - deadTodo.sub.fn2() - }).toThrow(getError(deadTodo, "/todo", "sub", "")) - expect(() => { - // tslint:disable-next-line:no-unused-expression - deadTodo.sub.title - }).toThrow(getError(deadTodo, "/todo", "sub", "")) - expect(() => { - deadTodo.sub.title = "hi" - }).toThrow(getError(deadTodo, "/todo", "sub", "")) - - // dead array - expect(() => { - // tslint:disable-next-line:no-unused-expression - deadArr[0] - }).toThrow(getError(deadArr, "/todo/arr", "0", "")) - expect(() => { - deadArr[0] = "hi" - }).toThrow(getError(deadArr, "/todo/arr", "0", "")) - expect(() => { - deadArr.push("hi") - }).toThrow(getError(deadArr, "/todo/arr", "1", "")) - - // dead map - expect(() => { - deadMap.get("mapkey0") - }).toThrow(getError(deadMap, "/todo/map", "mapkey0", "")) - expect(() => { - deadMap.set("mapkey0", "val") - }).toThrow(getError(deadMap, "/todo/map", "mapkey0", "")) - - // dead subobj - expect(() => { - deadSub.fn2() - }).toThrow(getError(deadSub, "/todo/sub", "", "/todo/sub.fn2()")) - expect(() => { - // tslint:disable-next-line:no-unused-expression - deadSub.title - }).toThrow(getError(deadSub, "/todo/sub", "title", "")) - expect(() => { - deadSub.title = "ho" - }).toThrow(getError(deadSub, "/todo/sub", "title", "")) -}) - -test("it should warn if a replaced object is read or written to", () => { - const Todo = types - .model("Todo", { - title: "test" - }) - .actions((self) => { - function fn() {} - return { - fn - } - }) - const Store = types.model("Store", { - todo: Todo - }) - const s = Store.create({ - todo: { title: "3" } - }) - unprotect(s) - const todo = s.todo - s.todo = Todo.create({ title: "4" }) - expect(s.todo.title).toBe("4") - - // try reading old todo - setLivelinessChecking("error") - const error = - "You are trying to read or write to an object that is no longer part of a state tree" - expect(() => todo.fn()).toThrow(error) - expect(() => todo.title).toThrow(error) - unprotect(todo) - expect(() => { - todo.title = "5" - }).toThrow(error) -}) - -// === COMPOSE FACTORY === -test("it should compose factories", () => { - const { BoxFactory, ColorFactory } = createTestFactories() - const ComposedFactory = types.compose(BoxFactory, ColorFactory) - expect(getSnapshot(ComposedFactory.create())).toEqual({ width: 0, height: 0, color: "#FFFFFF" }) -}) -test("it should compose factories with computed properties", () => { - const { ComputedFactory2, ColorFactory } = createTestFactories() - const ComposedFactory = types.compose(ColorFactory, ComputedFactory2) - const store = ComposedFactory.create({ props: { width: 100, height: 200 } }) - expect(getSnapshot(store)).toEqual({ props: { width: 100, height: 200 }, color: "#FFFFFF" }) - expect(store.area).toBe(20000) - expect(typeof store.setWidth).toBe("function") - expect(typeof store.setHeight).toBe("function") -}) -test("it should compose multiple types with computed properties", () => { - const { ComputedFactory2, ColorFactory } = createTestFactories() - const ComposedFactory = types.compose(ColorFactory, ComputedFactory2) - const store = ComposedFactory.create({ props: { width: 100, height: 200 } }) - expect(getSnapshot(store)).toEqual({ props: { width: 100, height: 200 }, color: "#FFFFFF" }) - expect(store.area).toBe(20000) - expect(typeof store.setWidth).toBe("function") - expect(typeof store.setHeight).toBe("function") -}) -test("methods get overridden by compose", () => { - const A = types - .model({ - count: types.optional(types.number, 0) - }) - .actions((self) => { - function increment() { - self.count += 1 - } - return { - increment - } - }) - const B = A.actions((self) => ({ - increment() { - self.count += 10 - } - })) - const store = B.create() - expect(getSnapshot(store)).toEqual({ count: 0 }) - expect(store.count).toBe(0) - store.increment() - expect(store.count).toBe(10) -}) -test("compose should add new props", () => { - const A = types.model({ - count: types.optional(types.number, 0) - }) - const B = A.props({ - called: types.optional(types.number, 0) - }) - const store = B.create() - expect(getSnapshot(store)).toEqual({ count: 0, called: 0 }) - expect(store.count).toBe(0) -}) -test("models should expose their actions to be used in a composable way", () => { - const A = types - .model({ - count: types.optional(types.number, 0) - }) - .actions((self) => { - function increment() { - self.count += 1 - } - return { - increment - } - }) - const B = A.props({ - called: types.optional(types.number, 0) - }).actions((self) => { - const baseIncrement = self.increment - return { - increment() { - baseIncrement() - self.called += 1 - } - } - }) - const store = B.create() - expect(getSnapshot(store)).toEqual({ count: 0, called: 0 }) - expect(store.count).toBe(0) - store.increment() - expect(store.count).toBe(1) - expect(store.called).toBe(1) -}) -test("compose should be overwrite", () => { - const A = types - .model({ - name: "", - alias: "" - }) - .views((self) => ({ - get displayName() { - return self.alias || self.name - } - })) - const B = A.props({ - type: "" - }).views((self) => ({ - get displayName() { - return self.alias || self.name + self.type - } - })) - const storeA = A.create({ name: "nameA", alias: "aliasA" }) - const storeB = B.create({ name: "nameB", alias: "aliasB", type: "typeB" }) - const storeC = B.create({ name: "nameC", type: "typeC" }) - expect(storeA.displayName).toBe("aliasA") - expect(storeB.displayName).toBe("aliasB") - expect(storeC.displayName).toBe("nameCtypeC") -}) -// === TYPE CHECKS === -test("it should check the type correctly", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - expect(Factory.is(doc)).toEqual(true) - expect(Factory.is([])).toEqual(false) - expect(Factory.is({})).toEqual(true) - expect(Factory.is({ to: "mars" })).toEqual(true) - expect(Factory.is({ wrongKey: true })).toEqual(true) - expect(Factory.is({ to: 3 })).toEqual(false) -}) - -if (process.env.NODE_ENV !== "production") { - test("complex map / array values are optional by default", () => { - expect( - types - .model({ - todo: types.model({}) - }) - .is({}) - ).toBe(false) - expect(() => - types - .model({ - todo: types.model({}) - }) - .create({} as any) - ).toThrow() - expect( - types - .model({ - todo: types.array(types.string) - }) - .is({}) - ).toBe(true) // TBD: or true? - expect( - getSnapshot( - types - .model({ - todo: types.array(types.string) - }) - .create({}) - ) - ).toEqual({ todo: [] }) - expect( - types - .model({ - todo: types.map(types.string) - }) - .is({}) - ).toBe(true) - expect( - getSnapshot( - types - .model({ - todo: types.map(types.string) - }) - .create({}) - ) - ).toEqual({ todo: {} }) - }) -} -// === VIEW FUNCTIONS === -test("view functions should be tracked", () => { - const model = types - .model({ - x: 3 - }) - .views((self) => ({ - doubler() { - return self.x * 2 - } - })) - .create() - unprotect(model) - const values: number[] = [] - const d = autorun(() => { - values.push(model.doubler()) - }) - model.x = 7 - expect(values).toEqual([6, 14]) -}) -test("view functions should not be allowed to change state", () => { - const model = types - .model({ - x: 3 - }) - .views((self) => ({ - doubler() { - self.x *= 2 - } - })) - .actions((self) => { - function anotherDoubler() { - self.x *= 2 - } - return { - anotherDoubler - } - }) - .create() - expect(() => model.doubler()).toThrow() - model.anotherDoubler() - expect(model.x).toBe(6) -}) -test("it should consider primitives as proposed defaults", () => { - const now = new Date() - const Todo = types.model({ - id: 0, - name: "Hello world", - done: false, - createdAt: now - }) - const doc = Todo.create() - expect(getSnapshot(doc)).toEqual({ - id: 0, - name: "Hello world", - done: false, - createdAt: now.getTime() - }) -}) -test("it should throw if a non-primitive value is provided and no default can be created", () => { - expect(() => { - types.model({ - complex: { - a: 1, - b: 2 - } as any - }) - }).toThrow() -}) -if (process.env.NODE_ENV !== "production") { - test("it should not be possible to remove a node from a parent if it is required, see ", () => { - const A = types.model("A", { x: 3 }) - const B = types.model("B", { a: A }) - const b = B.create({ a: { x: 7 } }) - unprotect(b) - expect(() => { - detach(b.a) - }).toThrowError(/Error while converting `undefined` to `A`/) - expect(() => { - destroy(b.a) - }).toThrowError(/Error while converting `undefined` to `A`/) - }) - test("it should be possible to remove a node from a parent if it is defined as type maybe ", () => { - const A = types.model("A", { x: 3 }) - const B = types.model("B", { a: types.maybe(A) }) - const b = B.create({ a: { x: 7 } }) - unprotect(b) - expect(() => { - const a = b.a! - detach(a) - destroy(a) - }).not.toThrow() - expect(b.a).toBe(undefined) - expect(getSnapshot(b).a).toBe(undefined) - }) - test("it should be possible to remove a node from a parent if it is defined as type maybeNull ", () => { - const A = types.model("A", { x: 3 }) - const B = types.model("B", { a: types.maybeNull(A) }) - const b = B.create({ a: { x: 7 } }) - unprotect(b) - expect(() => { - const a = b.a! - detach(a) - destroy(a) - }).not.toThrow() - expect(b.a).toBe(null) - expect(getSnapshot(b).a).toBe(null) - }) -} -test("it should be possible to share states between views and actions using enhance", () => { - const A = types.model({}).extend((self) => { - const localState = observable.box(3) - return { - views: { - get x() { - return localState.get() - } - }, - actions: { - setX(value: number) { - localState.set(value) - } - } - } - }) - let x = 0 - let a = A.create() - const d = reaction( - () => a.x, - (v) => { - x = v - } - ) - a.setX(7) - expect(a.x).toBe(7) - expect(x).toBe(7) - d() -}) -test("It should throw if any other key is returned from extend", () => { - const A = types.model({}).extend(() => ({ stuff() {} } as any)) - expect(() => A.create()).toThrowError(/stuff/) -}) - -test("782, TS + compose", () => { - const User = types.model("User", { - id: types.identifier, - name: types.maybe(types.string), - avatar: types.maybe(types.string) - }) - - const user = User.create({ id: "someId" }) -}) - -test("961 - model creating should not change snapshot", () => { - const M = types.model({ foo: 1 }) - const o = {} - - const m = M.create(o) - expect(o).toEqual({}) - expect(getSnapshot(m)).toEqual({ foo: 1 }) -}) - -if (process.env.NODE_ENV === "development") - test("beautiful errors", () => { - expect(() => { - types.model("User", { x: (types.identifier as any)() }) - }).toThrow("types.identifier is not a function") - expect(() => { - types.model("User", { x: { bla: true } as any }) - }).toThrow( - "Invalid type definition for property 'x', it looks like you passed an object. Try passing another model type or a types.frozen" - ) - expect(() => { - types.model("User", { x: function () {} as any }) - }).toThrow( - "Invalid type definition for property 'x', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?" - ) - }) - -test("#967 - changing values in afterCreate/afterAttach when node is instantiated from view", () => { - const Answer = types - .model("Answer", { - title: types.string, - selected: false - }) - .actions((self) => ({ - toggle() { - self.selected = !self.selected - } - })) - const Question = types - .model("Question", { title: types.string, answers: types.array(Answer) }) - .views((self) => ({ - get brokenView() { - // this should not be allowed - // MWE: disabled, MobX 6 no longer forbids this - // expect(() => { - // self.answers[0].toggle() - // }).toThrow() - return 0 - } - })) - .actions((self) => ({ - afterCreate() { - // we should allow changes even when inside a computed property when done inside afterCreate/afterAttach - self.answers[0].toggle() - // but not further computed changes - expect(self.brokenView).toBe(0) - }, - afterAttach() { - // we should allow changes even when inside a computed property when done inside afterCreate/afterAttach - self.answers[0].toggle() - expect(self.brokenView).toBe(0) - } - })) - - const Product = types - .model("Product", { - questions: types.array(Question) - }) - .views((self) => ({ - get selectedAnswers() { - const result = [] - for (const question of self.questions) { - result.push(question.answers.find((a) => a.selected)) - } - return result - } - })) - - const product = Product.create({ - questions: [ - { title: "Q 0", answers: [{ title: "A 0.0" }, { title: "A 0.1" }] }, - { title: "Q 1", answers: [{ title: "A 1.0" }, { title: "A 1.1" }] } - ] - }) - - // tslint:disable-next-line:no-unused-expression - product.selectedAnswers -}) - -test("#993-1 - after attach should have a parent when accesing a reference directly", () => { - const L4 = types - .model("Todo", { - id: types.identifier, - finished: false - }) - .actions((self) => ({ - afterAttach() { - expect(getParent(self)).toBeTruthy() - } - })) - - const L3 = types.model({ l4: L4 }).actions((self) => ({ - afterAttach() { - expect(getParent(self)).toBeTruthy() - } - })) - - const L2 = types - .model({ - l3: L3 - }) - .actions((self) => ({ - afterAttach() { - expect(getParent(self)).toBeTruthy() - } - })) - - const L1 = types - .model({ - l2: L2, - selected: types.reference(L4) - }) - .actions((self) => ({ - afterAttach() { - throw fail("should never be called") - } - })) - - const createL1 = () => - L1.create({ - l2: { - l3: { - l4: { - id: "11124091-11c1-4dda-b2ed-7dd6323491a5" - } - } - }, - selected: "11124091-11c1-4dda-b2ed-7dd6323491a5" - }) - - // test 1, real child first - { - const l1 = createL1() - - const a = l1.l2.l3.l4 - const b = l1.selected - } - - // test 2, reference first - { - const l1 = createL1() - - const a = l1.selected - const b = l1.l2.l3.l4 - } -}) - -test("#993-2 - references should have a parent even when the parent has not been accessed before", () => { - const events: string[] = [] - - const L4 = types - .model("Todo", { - id: types.identifier, - finished: false - }) - .actions((self) => ({ - toggle() { - self.finished = !self.finished - }, - afterCreate() { - events.push("l4-ac") - }, - afterAttach() { - events.push("l4-at") - } - })) - - const L3 = types.model({ l4: L4 }).actions((self) => ({ - afterCreate() { - events.push("l3-ac") - }, - afterAttach() { - events.push("l3-at") - } - })) - - const L2 = types - .model({ - l3: L3 - }) - .actions((self) => ({ - afterCreate() { - events.push("l2-ac") - }, - afterAttach() { - events.push("l2-at") - } - })) - - const L1 = types - .model({ - l2: L2, - selected: types.reference(L4) - }) - .actions((self) => ({ - afterCreate() { - events.push("l1-ac") - }, - afterAttach() { - events.push("l1-at") - } - })) - - const createL1 = () => - L1.create({ - l2: { - l3: { - l4: { - id: "11124091-11c1-4dda-b2ed-7dd6323491a5" - } - } - }, - selected: "11124091-11c1-4dda-b2ed-7dd6323491a5" - }) - - const expectedEvents = [ - "l1-ac", - "l2-ac", - "l2-at", - "l3-ac", - "l3-at", - "l4-ac", - "l4-at", - "onSnapshot", - "-", - "onSnapshot" - ] - - // test 1, real child first - { - const l1 = createL1() - onSnapshot(l1, () => { - events.push("onSnapshot") - }) - - l1.l2.l3.l4.toggle() - events.push("-") - l1.selected.toggle() - expect(events).toEqual(expectedEvents) - } - - const expectedEvents2 = [ - "l1-ac", - "l4-ac", - "l3-ac", - "l2-ac", - "l2-at", - "l3-at", - "l4-at", - "onSnapshot", - "-", - "onSnapshot" - ] - - // test 2, reference first - // the order of hooks is different but they are all called - events.length = 0 - { - const l1 = createL1() - onSnapshot(l1, () => { - events.push("onSnapshot") - }) - - l1.selected.toggle() - events.push("-") - l1.l2.l3.l4.toggle() - expect(events).toEqual(expectedEvents2) - } - - // test 3, reference get parent should be available from the beginning and all the way to the root - { - const rootL1 = createL1() - const l4 = rootL1.selected - const l3 = getParent(l4) - expect(l3).toBeTruthy() - const l2 = getParent(l3) - expect(l2).toBeTruthy() - const l1 = getParent(l2) - expect(l1).toBeTruthy() - - expect(l1).toBe(rootL1) - expect(l2).toBe(rootL1.l2) - expect(l3).toBe(rootL1.l2.l3) - expect(l4).toBe(rootL1.l2.l3.l4) - } -}) - -test("it should emit patches when applySnapshot is used", () => { - const { Factory } = createTestFactories() - const doc = Factory.create() - let patches: IJsonPatch[] = [] - onPatch(doc, (patch) => patches.push(patch)) - applySnapshot(doc, { ...getSnapshot(doc), to: "universe" }) - expect(patches).toEqual([{ op: "replace", path: "/to", value: "universe" }]) -}) - -test("isAlive must be reactive", () => { - const Todo = types.model({ text: types.string }) - const TodoStore = types.model({ - todos: types.array(Todo), - todo: types.maybe(Todo) - }) - - const store = TodoStore.create({ - todos: [{ text: "1" }, { text: "2" }], - todo: { text: "3" } - }) - unprotect(store) - - const t1 = store.todos[0]! - const t2 = store.todos[1]! - const t3 = store.todo! - - let calls = 0 - const r1 = reaction( - () => isAlive(t1), - (v) => { - expect(v).toBe(false) - calls++ - } - ) - const r2 = reaction( - () => isAlive(t2), - (v) => { - expect(v).toBe(false) - calls++ - } - ) - const r3 = reaction( - () => isAlive(t3), - (v) => { - expect(v).toBe(false) - calls++ - } - ) - - try { - store.todos = cast([]) - store.todo = undefined - - expect(calls).toBe(3) - } finally { - r1() - r2() - r3() - } -}) - -test("#1112 - identifier cache should be cleared for unaccessed wrapped objects", () => { - const mock1 = [ - { id: "1", name: "Kate" }, - { id: "2", name: "John" } - ] - const mock2 = [ - { id: "3", name: "Andrew" }, - { id: "2", name: "John" } - ] - - const mock1_2 = mock1.map((i, index) => ({ text: `Text${index}`, entity: i })) - const mock2_2 = mock2.map((i, index) => ({ text: `Text${index}`, entity: i })) - - const Entity = types.model({ - id: types.identifier, - name: types.string - }) - - const Wrapper = types.model({ - text: types.string, - entity: Entity - }) - - const Store = types - .model({ - list: types.optional(types.array(Wrapper), []), - selectedId: 2 - }) - .views((self) => ({ - get selectedEntity() { - return resolveIdentifier(Entity, self, self.selectedId) - } - })) - - const store = Store.create() - unprotect(store) - - store.list.replace(mock1_2) - store.list.replace(mock2_2) - - expect(store.selectedEntity!.id).toBe("2") -}) - -test("#1173 - detaching a model should not screw it", () => { - const AM = types.model({ x: 5 }) - const Store = types.model({ item: types.maybe(AM) }) - const s = Store.create({ item: { x: 6 } }) - const n0 = s.item - - unprotect(s) - - const detachedItem = detach(s.item!) - expect(s.item).not.toBe(detachedItem) - expect(s.item).toBe(undefined) - expect(detachedItem.x).toBe(6) - expect(detachedItem).toBe(n0) -}) - -test("#1702 - should not throw with useProxies: 'ifavailable'", () => { - configure({ - useProxies: "ifavailable" - }) - - const M = types.model({ x: 5 }).views((self) => ({ - get y() { - return self.x - } - })) - - expect(() => { - M.create({}) - }).not.toThrow() -}) diff --git a/packages/mobx-state-tree/__tests__/core/optimizations.test.ts b/packages/mobx-state-tree/__tests__/core/optimizations.test.ts deleted file mode 100644 index f3f40396e..000000000 --- a/packages/mobx-state-tree/__tests__/core/optimizations.test.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { getSnapshot, applySnapshot, unprotect, types } from "../../src" - -test("it should avoid processing patch if is exactly the current one in applySnapshot", () => { - const Model = types.model({ - a: types.number, - b: types.string - }) - const store = Model.create({ a: 1, b: "hello" }) - const snapshot = getSnapshot(store) - applySnapshot(store, snapshot) - expect(getSnapshot(store)).toBe(snapshot) // no new snapshot emitted -}) -test("it should avoid processing patch if is exactly the current one in reconcile", () => { - const Model = types.model({ - a: types.number, - b: types.string - }) - const RootModel = types.model({ - a: Model - }) - const store = RootModel.create({ a: { a: 1, b: "hello" } }) - unprotect(store) - // NOTE: snapshots are not equal after property access anymore, - // so we test initial and actual ones separately - const snapshot = getSnapshot(store) - expect(getSnapshot(store)).toEqual(snapshot) - - store.a = snapshot.a - // check whether reconciliation works on initial values - expect(getSnapshot(store)).toEqual(snapshot) - - // access property to initialize observable instance - expect(getSnapshot(store.a)).toEqual(snapshot.a) - - // check whether initializing instance does not cause snapshot invalidation - const actualSnapshot = getSnapshot(store) - expect(actualSnapshot.a).toBe(snapshot.a) -}) diff --git a/packages/mobx-state-tree/__tests__/core/optional-extension.test.ts b/packages/mobx-state-tree/__tests__/core/optional-extension.test.ts deleted file mode 100644 index 014cdd02d..000000000 --- a/packages/mobx-state-tree/__tests__/core/optional-extension.test.ts +++ /dev/null @@ -1,329 +0,0 @@ -import { getSnapshot, types, unprotect } from "../../src" - -describe("null as default", () => { - describe("basic tests", () => { - const M = types.model({ - x: types.optional(types.number, 1, [null]), - y: types.optional(types.number, () => 2, [null]) - }) - - test("with optional values, then assigned values", () => { - const m = M.create({ - x: null, - y: null - }) - unprotect(m) - - expect(m.x).toBe(1) - expect(m.y).toBe(2) - - expect(getSnapshot(m)).toEqual({ - x: 1, - y: 2 - }) - - m.x = 10 - m.y = 20 - expect(m.x).toBe(10) - expect(m.y).toBe(20) - - expect(getSnapshot(m)).toEqual({ - x: 10, - y: 20 - }) - }) - - test("with given values, then assigned optional values", () => { - const m = M.create({ - x: 10, - y: 20 - }) - unprotect(m) - - expect(m.x).toBe(10) - expect(m.y).toBe(20) - - expect(getSnapshot(m)).toEqual({ - x: 10, - y: 20 - }) - - m.x = null as any - m.y = null as any - expect(m.x).toBe(1) - expect(m.y).toBe(2) - - expect(getSnapshot(m)).toEqual({ - x: 1, - y: 2 - }) - }) - }) - - test("when the underlying type accepts undefined it should be ok", () => { - const M = types.model({ - a: types.optional(types.union(types.undefined, types.number), undefined, [null]), - b: types.optional(types.union(types.undefined, types.number), 5, [null]) - }) - - { - const m = M.create({ - a: null, - b: null - }) - expect(m.a).toBe(undefined) - expect(m.b).toBe(5) - expect(getSnapshot(m)).toEqual({ - a: undefined, - b: 5 - }) - } - - { - const m = M.create({ - a: 10, - b: 20 - }) - expect(m.a).toBe(10) - expect(m.b).toBe(20) - expect(getSnapshot(m)).toEqual({ - a: 10, - b: 20 - }) - } - - { - const m = M.create({ - a: undefined, - b: undefined - }) - expect(m.a).toBe(undefined) - expect(m.b).toBe(undefined) - expect(getSnapshot(m)).toEqual({ - a: undefined, - b: undefined - }) - } - }) - - test("when the underlying type does not accept undefined, then undefined should throw", () => { - const M = types.model({ - a: types.optional(types.number, 5, [null]), - b: types.optional(types.number, 6, [null]) - }) - - { - const m = M.create({ - a: null, - b: null - }) - expect(m.a).toBe(5) - expect(m.b).toBe(6) - } - - if (process.env.NODE_ENV !== "production") { - expect(() => { - M.create({ - a: null, - b: undefined as any // undefined is not valid - }) - }).toThrowError("value `undefined` is not assignable to type: `number`") - - expect(() => { - M.create({ - a: null - // b: null missing, but should be there - } as any) - }).toThrowError("value `undefined` is not assignable to type: `number`") - } - }) -}) - -describe("'empty' or false as default", () => { - describe("basic tests", () => { - const M = types.model({ - x: types.optional(types.number, 1, ["empty", false]), - y: types.optional(types.number, () => 2, ["empty", false]) - }) - - test("with optional values, then assigned values", () => { - const m = M.create({ - x: "empty", - y: false - }) - unprotect(m) - - expect(m.x).toBe(1) - expect(m.y).toBe(2) - - expect(getSnapshot(m)).toEqual({ - x: 1, - y: 2 - }) - - m.x = 10 - m.y = 20 - expect(m.x).toBe(10) - expect(m.y).toBe(20) - - expect(getSnapshot(m)).toEqual({ - x: 10, - y: 20 - }) - }) - - test("with given values, then assigned 'empty'", () => { - const m = M.create({ - x: 10, - y: 20 - }) - unprotect(m) - - expect(m.x).toBe(10) - expect(m.y).toBe(20) - - expect(getSnapshot(m)).toEqual({ - x: 10, - y: 20 - }) - - m.x = "empty" as any - m.y = false as any - expect(m.x).toBe(1) - expect(m.y).toBe(2) - - expect(getSnapshot(m)).toEqual({ - x: 1, - y: 2 - }) - }) - }) - - test("when the underlying type accepts undefined it should be ok", () => { - const M = types.model({ - a: types.optional(types.union(types.undefined, types.number), undefined, [ - "empty", - false - ]), - b: types.optional(types.union(types.undefined, types.number), 5, ["empty", false]) - }) - - { - const m = M.create({ - a: "empty", - b: false - }) - expect(m.a).toBe(undefined) - expect(m.b).toBe(5) - expect(getSnapshot(m)).toEqual({ - a: undefined, - b: 5 - }) - } - - { - const m = M.create({ - a: 10, - b: 20 - }) - expect(m.a).toBe(10) - expect(m.b).toBe(20) - expect(getSnapshot(m)).toEqual({ - a: 10, - b: 20 - }) - } - - { - const m = M.create({ - a: undefined, - b: undefined - }) - expect(m.a).toBe(undefined) - expect(m.b).toBe(undefined) - expect(getSnapshot(m)).toEqual({ - a: undefined, - b: undefined - }) - } - }) - - test("when the underlying type does not accept undefined, then undefined should throw", () => { - const M = types.model({ - a: types.optional(types.number, 5, ["empty", false]), - b: types.optional(types.number, 6, ["empty", false]) - }) - - { - const m = M.create({ - a: "empty", - b: false - }) - expect(m.a).toBe(5) - expect(m.b).toBe(6) - } - - if (process.env.NODE_ENV !== "production") { - expect(() => { - M.create({ - a: undefined as any, - b: undefined as any - }) - }).toThrowError("value `undefined` is not assignable to type: `number`") - } - }) -}) - -test("cached snapshots should be ok when using default values", () => { - const M = types.model({ x: 5, y: 6 }) - const Store = types.model({ - deep: types.model({ - a: types.optional(types.undefined, undefined), - b: types.optional(types.undefined, undefined, ["empty"]), - c: types.optional(types.number, 5), - d: types.optional(types.number, 5, ["empty"]), - - a2: types.optional(types.undefined, () => undefined), - b2: types.optional(types.undefined, () => undefined, ["empty"]), - c2: types.optional(types.number, () => 5), - d2: types.optional(types.number, () => 5, ["empty"]), - - a3: types.optional(M, { y: 20 }), - b3: types.optional(M, { y: 20 }, ["empty"]), - c3: types.optional(M, () => M.create({ y: 20 })), - d3: types.optional(M, () => M.create({ y: 20 }), ["empty"]), - e3: types.optional(M, () => ({ y: 20 })), - f3: types.optional(M, () => ({ y: 20 }), ["empty"]) - }) - }) - - const s = Store.create({ - deep: { - b: "empty", - d: "empty", - b2: "empty", - d2: "empty", - b3: "empty", - d3: "empty", - f3: "empty" - } - }) - expect(getSnapshot(s)).toEqual({ - deep: { - a: undefined, - b: undefined, - c: 5, - d: 5, - a2: undefined, - b2: undefined, - c2: 5, - d2: 5, - a3: { x: 5, y: 20 }, - b3: { x: 5, y: 20 }, - c3: { x: 5, y: 20 }, - d3: { x: 5, y: 20 }, - e3: { x: 5, y: 20 }, - f3: { x: 5, y: 20 } - } - }) -}) diff --git a/packages/mobx-state-tree/__tests__/core/optional.test.ts b/packages/mobx-state-tree/__tests__/core/optional.test.ts deleted file mode 100644 index 2aac79e25..000000000 --- a/packages/mobx-state-tree/__tests__/core/optional.test.ts +++ /dev/null @@ -1,148 +0,0 @@ -import { getSnapshot, types, unprotect, applySnapshot, cast } from "../../src" - -test("it should provide a default value, if no snapshot is provided", () => { - const Row = types.model({ - name: "", - quantity: 0 - }) - const Factory = types.model({ - rows: types.optional(types.array(Row), [{ name: "test" }]) - }) - const doc = Factory.create() - expect(getSnapshot(doc)).toEqual({ rows: [{ name: "test", quantity: 0 }] }) -}) - -test("it should use the snapshot if provided", () => { - const Row = types.model({ - name: "", - quantity: 0 - }) - const Factory = types.model({ - rows: types.optional(types.array(Row), [{ name: "test" }]) - }) - const doc = Factory.create({ rows: [{ name: "snapshot", quantity: 0 }] }) - expect(getSnapshot(doc)).toEqual({ rows: [{ name: "snapshot", quantity: 0 }] }) -}) - -if (process.env.NODE_ENV !== "production") { - test("it should throw if default value is invalid snapshot", () => { - const Row = types.model({ - name: types.string, - quantity: types.number - }) - const error = expect(() => { - types.model({ - rows: types.optional(types.array(Row), [{}] as any) - }) - }).toThrow() - }) - - test("it should throw bouncing errors from its sub-type", () => { - const Row = types.model({ - name: types.string, - quantity: types.number - }) - const RowList = types.optional(types.array(Row), []) - const error = expect(() => { - RowList.create([ - { name: "a", quantity: 1 }, - { name: "b", quantity: "x" } - ] as any) - }).toThrow() - }) -} - -test("it should accept a function to provide dynamic values", () => { - let defaultValue = 1 - const Factory = types.model({ - a: types.optional(types.number, () => defaultValue) - }) - expect(getSnapshot(Factory.create())).toEqual({ a: 1 }) - defaultValue = 2 - expect(getSnapshot(Factory.create())).toEqual({ a: 2 }) - defaultValue = "hello world!" as any - if (process.env.NODE_ENV !== "production") { - expect(() => Factory.create()).toThrowError( - `[mobx-state-tree] Error while converting \`"hello world!"\` to \`number\`:\n\n value \`"hello world!"\` is not assignable to type: \`number\` (Value is not a number).` - ) - } -}) - -test("Values should reset to default if omitted in snapshot", () => { - const Store = types.model({ - todo: types.model({ - id: types.identifier, - done: false, - title: "test", - thing: types.frozen({}) - }) - }) - const store = Store.create({ todo: { id: "2" } }) - unprotect(store) - store.todo.done = true - expect(store.todo.done).toBe(true) - store.todo = cast({ title: "stuff", id: "2" }) - expect(store.todo.title).toBe("stuff") - expect(store.todo.done).toBe(false) -}) - -test("optional frozen should fallback to default value if snapshot is undefined", () => { - const Store = types.model({ thing: types.frozen({}) }) - const store = Store.create({ - thing: null - }) - - expect(store.thing).toBeNull() - applySnapshot(store, {}) - expect(store.thing).toBeDefined() - expect(store.thing).toEqual({}) -}) - -test("an instance is not a valid default value, snapshot or function that creates instance must be used", () => { - const Row = types.model("Row", { - name: "", - quantity: 0 - }) - - // passing a node directly, without a generator function - expect(() => { - types.model({ rows: types.optional(types.array(Row), types.array(Row).create()) }) - }).toThrow( - "default value cannot be an instance, pass a snapshot or a function that creates an instance/snapshot instead" - ) - - // an alike node but created from a different yet equivalent type - const e = expect(() => { - const Factory = types.model({ - rows: types.optional(types.array(Row), () => types.array(Row).create()) - }) - // we need to create the node for it to throw, since generator functions are typechecked when nodes are created - // tslint:disable-next-line:no-unused-expression - Factory.create() - }) - if (process.env.NODE_ENV === "production") { - e.not.toThrow() - } else { - e.toThrow("Error while converting <> to `Row[]`") - } - - { - // a node created on a generator function of the exact same type - const RowArray = types.array(Row) - const Factory = types.model("Factory", { - rows: types.optional(RowArray, () => RowArray.create()) - }) - const doc = Factory.create() - expect(getSnapshot(doc)).toEqual({ rows: [] }) - } -}) - -test("undefined can work as a missing value", () => { - const M = types.model({ x: types.union(types.undefined, types.number) }) - const m1 = M.create({ x: 5 }) - expect(m1.x).toBe(5) - const m2 = M.create({ x: undefined }) - expect(m2.x).toBe(undefined) - const m3 = M.create({}) // is ok as well (even in TS) - expect(m3.x).toBe(undefined) -}) diff --git a/packages/mobx-state-tree/__tests__/core/parent-properties.test.ts b/packages/mobx-state-tree/__tests__/core/parent-properties.test.ts deleted file mode 100644 index de8e8b9da..000000000 --- a/packages/mobx-state-tree/__tests__/core/parent-properties.test.ts +++ /dev/null @@ -1,127 +0,0 @@ -import { types, getEnv, getParent, getPath, cast, Instance } from "../../src" - -const ChildModel = types - .model("Child", { - parentPropertyIsNullAfterCreate: false, - parentEnvIsNullAfterCreate: false, - parentPropertyIsNullAfterAttach: false - }) - .views((self) => { - return { - get parent(): IParentModelInstance { - return getParent(self) - } - } - }) - .actions((self) => ({ - afterCreate() { - self.parentPropertyIsNullAfterCreate = typeof self.parent.fetch === "undefined" - self.parentEnvIsNullAfterCreate = typeof getEnv(self.parent).fetch === "undefined" - }, - afterAttach() { - self.parentPropertyIsNullAfterAttach = typeof self.parent.fetch === "undefined" - } - })) - -const ParentModel = types - .model("Parent", { - child: types.optional(ChildModel, {}) - }) - .views((self) => ({ - get fetch() { - return getEnv(self).fetch - } - })) - -interface IParentModelInstance extends Instance {} - -// NOTE: parents are now always created before children; -// moreover, we do not actually have actions hash during object-node creation -test("Parent property have value during child's afterCreate() event", () => { - const mockFetcher = () => Promise.resolve(true) - const parent = ParentModel.create({}, { fetch: mockFetcher }) - // Because the child is created before the parent creation is finished, this one will yield `true` (the .fetch view is still undefined) - expect(parent.child.parentPropertyIsNullAfterCreate).toBe(false) - // ... but, the env is available - expect(parent.child.parentEnvIsNullAfterCreate).toBe(false) -}) -test("Parent property has value during child's afterAttach() event", () => { - const mockFetcher = () => Promise.resolve(true) - const parent = ParentModel.create({}, { fetch: mockFetcher }) - expect(parent.child.parentPropertyIsNullAfterAttach).toBe(false) -}) - -test("#917", () => { - const SubTodo = types - .model("SubTodo", { - id: types.optional(types.number, () => Math.random()), - title: types.string, - finished: false - }) - .views((self) => ({ - get path() { - return getPath(self) - } - })) - .actions((self) => ({ - toggle() { - self.finished = !self.finished - } - })) - - const Todo = types - .model("Todo", { - id: types.optional(types.number, () => Math.random()), - title: types.string, - finished: false, - subTodos: types.array(SubTodo) - }) - .views((self) => ({ - get path() { - return getPath(self) - } - })) - .actions((self) => ({ - toggle() { - self.finished = !self.finished - } - })) - - const TodoStore = types - .model("TodoStore", { - todos: types.array(Todo) - }) - .views((self) => ({ - get unfinishedTodoCount() { - return self.todos.filter((todo) => !todo.finished).length - } - })) - .actions((self) => ({ - addTodo(title: string) { - self.todos.push({ - title, - subTodos: [ - { - title - } - ] - }) - } - })) - - const store2 = TodoStore.create({ - todos: [ - Todo.create({ - title: "get Coffee", - subTodos: [ - SubTodo.create({ - title: "test" - }) - ] - }) - ] - }) - - expect(store2.todos[0].path).toBe("/todos/0") - expect(store2.todos[0].subTodos[0].path).toBe("/todos/0/subTodos/0") -}) diff --git a/packages/mobx-state-tree/__tests__/core/pointer.test.ts b/packages/mobx-state-tree/__tests__/core/pointer.test.ts deleted file mode 100644 index 7ddb66268..000000000 --- a/packages/mobx-state-tree/__tests__/core/pointer.test.ts +++ /dev/null @@ -1,85 +0,0 @@ -import { types, unprotect, IAnyModelType, castToReferenceSnapshot } from "../../src" - -function Pointer(Model: IT) { - return types.model("PointerOf" + Model.name, { - value: types.maybe(types.reference(Model)) - }) -} -const Todo = types.model("Todo", { - id: types.identifier, - name: types.string -}) -test("it should allow array of pointer objects", () => { - const TodoPointer = Pointer(Todo) - const AppStore = types.model("AppStore", { - todos: types.array(Todo), - selected: types.optional(types.array(TodoPointer), []) - }) - const store = AppStore.create({ - todos: [ - { id: "1", name: "Hello" }, - { id: "2", name: "World" } - ], - selected: [] - }) - unprotect(store) - const ref = TodoPointer.create({ value: castToReferenceSnapshot(store.todos[0]) }) // Fails because store.todos does not belongs to the same tree - store.selected.push(ref) - expect(store.selected[0].value).toBe(store.todos[0]) -}) -test("it should allow array of pointer objects - 2", () => { - const TodoPointer = Pointer(Todo) - const AppStore = types.model({ - todos: types.array(Todo), - selected: types.optional(types.array(TodoPointer), []) - }) - const store = AppStore.create({ - todos: [ - { id: "1", name: "Hello" }, - { id: "2", name: "World" } - ], - selected: [] - }) - unprotect(store) - const ref = TodoPointer.create() - store.selected.push(ref) - ref.value = store.todos[0] - expect(store.selected[0].value).toBe(store.todos[0]) -}) -test("it should allow array of pointer objects - 3", () => { - const TodoPointer = Pointer(Todo) - const AppStore = types.model({ - todos: types.array(Todo), - selected: types.optional(types.array(TodoPointer), []) - }) - const store = AppStore.create({ - todos: [ - { id: "1", name: "Hello" }, - { id: "2", name: "World" } - ], - selected: [] - }) - unprotect(store) - const ref = TodoPointer.create({ value: castToReferenceSnapshot(store.todos[0]) }) - store.selected.push(ref) - expect(store.selected[0].value).toBe(store.todos[0]) -}) -test("it should allow array of pointer objects - 4", () => { - const TodoPointer = Pointer(Todo) - const AppStore = types.model({ - todos: types.array(Todo), - selected: types.optional(types.array(TodoPointer), []) - }) - const store = AppStore.create({ - todos: [ - { id: "1", name: "Hello" }, - { id: "2", name: "World" } - ], - selected: [] - }) - unprotect(store) - const ref = TodoPointer.create() // Fails because ref is required - store.selected.push(ref) - ref.value = store.todos[0] - expect(ref.value).toBe(store.todos[0]) -}) diff --git a/packages/mobx-state-tree/__tests__/core/primitives.test.ts b/packages/mobx-state-tree/__tests__/core/primitives.test.ts deleted file mode 100644 index 1d3abb77b..000000000 --- a/packages/mobx-state-tree/__tests__/core/primitives.test.ts +++ /dev/null @@ -1,107 +0,0 @@ -import { isFinite, isFloat, isInteger } from "../../src/utils" -import { types, applySnapshot, getSnapshot } from "../../src" - -test("Date instance can be reused", () => { - const Model = types.model({ - a: types.model({ - b: types.string - }), - c: types.Date // types.string -> types.Date - }) - const Store = types - .model({ - one: Model, - index: types.array(Model) - }) - .actions((self) => { - function set(one: typeof Model.Type) { - self.one = one - } - function push(model: typeof Model.Type) { - self.index.push(model) - } - return { - set, - push - } - }) - const object = { a: { b: "string" }, c: new Date() } // string -> date (number) - const instance = Store.create({ - one: object, - index: [object] - }) - instance.set(object) - expect(() => instance.push(object)).not.toThrow() - expect(instance.one.c).toBe(object.c) - expect(instance.index[0].c).toBe(object.c) -}) -test("Date can be rehydrated using unix timestamp", () => { - const time = new Date() - const newTime = 6813823163 - const Factory = types.model({ - date: types.optional(types.Date, () => time) - }) - const store = Factory.create() - expect(store.date.getTime()).toBe(time.getTime()) - applySnapshot(store, { date: newTime }) - expect(store.date.getTime()).toBe(newTime) - expect(getSnapshot(store).date).toBe(newTime) -}) - -test("check isInteger", () => { - expect(isInteger(5)).toBe(true) - expect(isInteger(-5)).toBe(true) - expect(isInteger(5.2)).toBe(false) -}) - -test("Default inference for integers is 'number'", () => { - const A = types.model({ - x: 3 - }) - expect( - A.is({ - x: 2.5 - }) - ).toBe(true) -}) - -test("check isFloat", () => { - expect(isFloat(3.14)).toBe(true) - expect(isFloat(-2.5)).toBe(true) - expect(isFloat(Infinity)).toBe(true) - expect(isFloat(10)).toBe(false) - expect(isFloat(0)).toBe(false) - expect(isFloat("3.14")).toBe(false) - expect(isFloat(null)).toBe(false) - expect(isFloat(undefined)).toBe(false) - expect(isFloat(NaN)).toBe(false) -}) - -test("check isFinite", () => { - expect(isFinite(3.14)).toBe(true) - expect(isFinite(-2.5)).toBe(true) - expect(isFinite(10)).toBe(true) - expect(isFinite(0)).toBe(true) - expect(isFinite("3.14")).toBe(false) - expect(isFinite(null)).toBe(false) - expect(isFinite(undefined)).toBe(false) - expect(isFinite(NaN)).toBe(false) - expect(isFinite(Infinity)).toBe(false) -}) - -if (process.env.NODE_ENV !== "production") { - test("Passing non integer to types.integer", () => { - const Size = types.model({ - width: types.integer, - height: 20 - }) - - expect(() => { - const size = Size.create({ width: 10 }) - }).not.toThrow() - - expect(() => { - const size = Size.create({ width: 10.5 }) - }).toThrow() - }) -} diff --git a/packages/mobx-state-tree/__tests__/core/protect.test.ts b/packages/mobx-state-tree/__tests__/core/protect.test.ts deleted file mode 100644 index 81bbc5bcb..000000000 --- a/packages/mobx-state-tree/__tests__/core/protect.test.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { protect, unprotect, applySnapshot, types, isProtected, getParent, cast } from "../../src" - -const Todo = types - .model("Todo", { - title: "" - }) - .actions((self) => { - function setTitle(newTitle: string) { - self.title = newTitle - } - return { - setTitle - } - }) -const Store = types.model("Store", { - todos: types.array(Todo) -}) -function createTestStore() { - return Store.create({ - todos: [{ title: "Get coffee" }, { title: "Get biscuit" }] - }) -} -test("it should be possible to protect an object", () => { - const store = createTestStore() - unprotect(store) - store.todos[1].title = "A" - protect(store) - expect(() => { - store.todos[0].title = "B" - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." - ) - expect(store.todos[1].title).toBe("A") - expect(store.todos[0].title).toBe("Get coffee") - store.todos[0].setTitle("B") - expect(store.todos[0].title).toBe("B") -}) -test("protect should protect against any update", () => { - const store = createTestStore() - expect( - // apply Snapshot / patch are currently allowed, even outside protected mode - () => { - applySnapshot(store, { todos: [{ title: "Get tea" }] }) - } - ).not.toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@', the object is protected and can only be modified by using an action." - ) - expect(() => { - store.todos.push({ title: "test" }) - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo[]@/todos', the object is protected and can only be modified by using an action." - ) - expect(() => { - store.todos[0].title = "test" - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." - ) -}) -test("protect should also protect children", () => { - const store = createTestStore() - expect(() => { - store.todos[0].title = "B" - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." - ) - store.todos[0].setTitle("B") - expect(store.todos[0].title).toBe("B") -}) -test("unprotected mode should be lost when attaching children", () => { - const store = Store.create({ todos: [] }) - const t1 = Todo.create({ title: "hello" }) - unprotect(t1) - expect(isProtected(t1)).toBe(false) - expect(isProtected(store)).toBe(true) - t1.title = "world" // ok - unprotect(store) - store.todos.push(t1) - protect(store) - expect(isProtected(t1)).toBe(true) - expect(isProtected(store)).toBe(true) - expect(() => { - t1.title = "B" - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@/todos/0', the object is protected and can only be modified by using an action." - ) - store.todos[0].setTitle("C") - expect(store.todos[0].title).toBe("C") -}) -test("protected mode should be inherited when attaching children", () => { - const store = Store.create({ todos: [] }) - unprotect(store) - const t1 = Todo.create({ title: "hello" }) - expect(isProtected(t1)).toBe(true) - expect(isProtected(store)).toBe(false) - expect(() => { - t1.title = "B" - }).toThrowError( - "[mobx-state-tree] Cannot modify 'Todo@', the object is protected and can only be modified by using an action." - ) - store.todos.push(t1) - t1.title = "world" // ok, now unprotected - expect(isProtected(t1)).toBe(false) - expect(isProtected(store)).toBe(false) - expect(store.todos[0].title).toBe("world") -}) -test("action cannot modify parent", () => { - const Child = types - .model("Child", { - x: 2 - }) - .actions((self) => ({ - setParentX() { - getParent(self).x += 1 - } - })) - const Parent = types.model("Parent", { - x: 3, - child: Child - }) - const p = Parent.create({ child: {} }) - expect(() => p.child.setParentX()).toThrowError( - "[mobx-state-tree] Cannot modify 'Parent@', the object is protected and can only be modified by using an action." - ) -}) diff --git a/packages/mobx-state-tree/__tests__/core/recordPatches.test.ts b/packages/mobx-state-tree/__tests__/core/recordPatches.test.ts deleted file mode 100644 index f269dc36b..000000000 --- a/packages/mobx-state-tree/__tests__/core/recordPatches.test.ts +++ /dev/null @@ -1,353 +0,0 @@ -import { - getSnapshot, - unprotect, - recordPatches, - types, - IType, - IJsonPatch, - Instance, - cast, - IAnyModelType, - IMSTMap -} from "../../src" - -function testPatches( - type: IType, - snapshot: C, - fn: any, - expectedPatches: IJsonPatch[], - expectedInversePatches: IJsonPatch[] -) { - const instance = type.create(snapshot) - const baseSnapshot = getSnapshot(instance) - const recorder = recordPatches(instance) - unprotect(instance) - fn(instance) - recorder.stop() - expect(recorder.patches).toEqual(expectedPatches) - expect(recorder.inversePatches).toEqual(expectedInversePatches) - const clone = type.create(snapshot) - recorder.replay(clone) - expect(getSnapshot(clone)).toEqual(getSnapshot(instance)) - recorder.undo() - expect(getSnapshot(instance)).toEqual(baseSnapshot) -} -const Node = types.model("Node", { - id: types.identifierNumber, - text: "Hi", - children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) -}) - -test("it should apply simple patch", () => { - testPatches( - Node, - { id: 1 }, - (n: Instance) => { - n.text = "test" - }, - [ - { - op: "replace", - path: "/text", - value: "test" - } - ], - [ - { - op: "replace", - path: "/text", - value: "Hi" - } - ] - ) -}) - -test("it should apply deep patches to arrays", () => { - testPatches( - Node, - { id: 1, children: [{ id: 2 }] }, - (n: Instance) => { - const children = n.children as unknown as Instance[] - children[0].text = "test" // update - children[0] = cast({ id: 2, text: "world" }) // this reconciles; just an update - children[0] = cast({ id: 4, text: "coffee" }) // new object - children[1] = cast({ id: 3, text: "world" }) // addition - children.splice(0, 1) // removal - }, - [ - { - op: "replace", - path: "/children/0/text", - value: "test" - }, - { - op: "replace", - path: "/children/0/text", - value: "world" - }, - { - op: "replace", - path: "/children/0", - value: { - id: 4, - text: "coffee", - children: [] - } - }, - { - op: "add", - path: "/children/1", - value: { - id: 3, - text: "world", - children: [] - } - }, - { - op: "remove", - path: "/children/0" - } - ], - [ - { - op: "replace", - path: "/children/0/text", - value: "Hi" - }, - { - op: "replace", - path: "/children/0/text", - value: "test" - }, - { - op: "replace", - path: "/children/0", - value: { - children: [], - id: 2, - text: "world" - } - }, - { - op: "remove", - path: "/children/1" - }, - { - op: "add", - path: "/children/0", - value: { - children: [], - id: 4, - text: "coffee" - } - } - ] - ) -}) - -test("it should apply deep patches to maps", () => { - const NodeMap = types.model("NodeMap", { - id: types.identifierNumber, - text: "Hi", - children: types.optional(types.map(types.late((): IAnyModelType => NodeMap)), {}) - }) - testPatches( - NodeMap, - { id: 1, children: { 2: { id: 2 } } }, - (n: Instance) => { - const children = n.children as IMSTMap - children.get("2")!.text = "test" // update - children.put({ id: 2, text: "world" }) // this reconciles; just an update - children.set( - "4", - NodeMap.create({ id: 4, text: "coffee", children: { 23: { id: 23 } } }) - ) // new object - children.put({ id: 3, text: "world", children: { 7: { id: 7 } } }) // addition - children.delete("2") // removal - }, - [ - { - op: "replace", - path: "/children/2/text", - value: "test" - }, - { - op: "replace", - path: "/children/2/text", - value: "world" - }, - { - op: "add", - path: "/children/4", - value: { - children: { - 23: { - children: {}, - id: 23, - text: "Hi" - } - }, - id: 4, - text: "coffee" - } - }, - { - op: "add", - path: "/children/3", - value: { - children: { - 7: { - children: {}, - id: 7, - text: "Hi" - } - }, - id: 3, - text: "world" - } - }, - { - op: "remove", - path: "/children/2" - } - ], - [ - { - op: "replace", - path: "/children/2/text", - value: "Hi" - }, - { - op: "replace", - path: "/children/2/text", - value: "test" - }, - { - op: "remove", - path: "/children/4" - }, - { - op: "remove", - path: "/children/3" - }, - { - op: "add", - path: "/children/2", - value: { - children: {}, - id: 2, - text: "world" - } - } - ] - ) -}) - -test("it should apply deep patches to objects", () => { - const NodeObject = types.model("NodeObject", { - id: types.identifierNumber, - text: "Hi", - child: types.maybe(types.late((): IAnyModelType => NodeObject)) - }) - testPatches( - NodeObject, - { id: 1, child: { id: 2 } }, - (n: Instance) => { - n.child!.text = "test" // update - n.child = cast({ id: 2, text: "world" }) // this reconciles; just an update - n.child = NodeObject.create({ id: 2, text: "coffee", child: { id: 23 } }) - n.child = cast({ id: 3, text: "world", child: { id: 7 } }) // addition - n.child = undefined // removal - }, - [ - { - op: "replace", - path: "/child/text", - value: "test" - }, - { - op: "replace", - path: "/child/text", - value: "world" - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 23, - text: "Hi" - }, - id: 2, - text: "coffee" - } - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 7, - text: "Hi" - }, - id: 3, - text: "world" - } - }, - { - op: "replace", - path: "/child", - value: undefined - } - ], - [ - { - op: "replace", - path: "/child/text", - value: "Hi" - }, - { - op: "replace", - path: "/child/text", - value: "test" - }, - { - op: "replace", - path: "/child", - value: { - child: undefined, - id: 2, - text: "world" - } - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 23, - text: "Hi" - }, - id: 2, - text: "coffee" - } - }, - { - op: "replace", - path: "/child", - value: { - child: { - child: undefined, - id: 7, - text: "Hi" - }, - id: 3, - text: "world" - } - } - ] - ) -}) diff --git a/packages/mobx-state-tree/__tests__/core/reference-custom.test.ts b/packages/mobx-state-tree/__tests__/core/reference-custom.test.ts deleted file mode 100644 index 5d165ddb6..000000000 --- a/packages/mobx-state-tree/__tests__/core/reference-custom.test.ts +++ /dev/null @@ -1,253 +0,0 @@ -import { reaction, when, values } from "mobx" -import { - types, - recordPatches, - getSnapshot, - applySnapshot, - applyPatch, - unprotect, - getRoot, - onSnapshot, - flow, - Instance, - resolveIdentifier -} from "../../src" - -test("it should support custom references - basics", () => { - const User = types.model({ - id: types.identifier, - name: types.string - }) - const UserByNameReference = types.maybeNull( - types.reference(User, { - // given an identifier, find the user - get(identifier, parent): any { - return ( - (parent as Instance)!.users.find((u) => u.name === identifier) || - null - ) - }, - // given a user, produce the identifier that should be stored - set(value) { - return value.name - } - }) - ) - const Store = types.model({ - users: types.array(User), - selection: UserByNameReference - }) - const s = Store.create({ - users: [ - { id: "1", name: "Michel" }, - { id: "2", name: "Mattia" } - ], - selection: "Mattia" - }) - unprotect(s) - expect(s.selection!.name).toBe("Mattia") - expect(s.selection === s.users[1]).toBe(true) - expect(getSnapshot(s).selection).toBe("Mattia") - s.selection = s.users[0] - expect(s.selection!.name).toBe("Michel") - expect(s.selection === s.users[0]).toBe(true) - expect(getSnapshot(s).selection).toBe("Michel") - s.selection = null - expect(getSnapshot(s).selection).toBe(null) - applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Mattia" })) - expect(s.selection).toBe(s.users[1]) - applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Unknown" })) - expect(s.selection).toBe(null) -}) - -test("it should support custom references - adv", () => { - const User = types.model({ - id: types.identifier, - name: types.string - }) - const NameReference = types.reference(User, { - get(identifier, parent): any { - if (identifier === null) return null - const users = values(getRoot>(parent!).users) - return users.filter((u) => u.name === identifier)[0] || null - }, - set(value) { - return value ? value.name : "" - } - }) - const Store = types.model({ - users: types.map(User), - selection: NameReference - }) - const s = Store.create({ - users: { - "1": { id: "1", name: "Michel" }, - "2": { id: "2", name: "Mattia" } - }, - selection: "Mattia" - }) - unprotect(s) - expect(s.selection.name).toBe("Mattia") - expect(s.selection === s.users.get("2")).toBe(true) - expect(getSnapshot(s).selection).toBe("Mattia") - const p = recordPatches(s) - const r: any[] = [] - onSnapshot(s, r.push.bind(r)) - const ids: (string | null)[] = [] - reaction( - () => s.selection, - (selection) => { - ids.push(selection ? selection.id : null) - } - ) - s.selection = s.users.get("1")! - expect(s.selection.name).toBe("Michel") - expect(s.selection === s.users.get("1")).toBe(true) - expect(getSnapshot(s).selection).toBe("Michel") - applySnapshot(s, Object.assign({}, getSnapshot(s), { selection: "Mattia" })) - expect(s.selection).toBe(s.users.get("2")) - applyPatch(s, { op: "replace", path: "/selection", value: "Michel" }) - expect(s.selection).toBe(s.users.get("1")) - s.users.delete("1") - expect(s.selection).toBe(null) - s.users.put({ id: "3", name: "Michel" }) - expect(s.selection.id).toBe("3") - expect(ids).toMatchSnapshot() - expect(r).toMatchSnapshot() - expect(p.patches).toMatchSnapshot() - expect(p.inversePatches).toMatchSnapshot() -}) - -test("it should support dynamic loading", (done) => { - const events: string[] = [] - const User = types.model({ - name: types.string, - age: 0 - }) - const UserByNameReference = types.maybe( - types.reference(User, { - get(identifier: string, parent): any { - return (parent as Instance).getOrLoadUser(identifier) - }, - set(value) { - return value.name - } - }) - ) - const Store = types - .model({ - users: types.array(User), - selection: UserByNameReference - }) - .actions((self) => ({ - loadUser: flow(function* loadUser(name: string) { - events.push("loading " + name) - self.users.push({ name }) - yield new Promise((resolve) => { - setTimeout(resolve, 200) - }) - events.push("loaded " + name) - const user = (self.users.find((u) => u.name === name)!.age = name.length * 3) // wonderful! - }) - })) - .views((self) => ({ - // Important: a view so that the reference will automatically react to the reference being changed! - getOrLoadUser(name: string) { - const user = self.users.find((u) => u.name === name) || null - if (!user) { - /* - TODO: this is ugly, but workaround the idea that views should be side effect free. - We need a more elegant solution.. - */ - setImmediate(() => self.loadUser(name)) - } - return user - } - })) - const s = Store.create({ - users: [], - selection: "Mattia" - }) - unprotect(s) - expect(events).toEqual([]) - expect(s.users.length).toBe(0) - expect(s.selection).toBe(null) - when( - () => s.users.length === 1 && s.users[0].age === 18 && s.users[0].name === "Mattia", - () => { - expect(s.selection).toBe(s.users[0]) - expect(events).toEqual(["loading Mattia", "loaded Mattia"]) - done() - } - ) -}) - -test("custom reference / safe custom reference to another store works", () => { - const Todo = types.model({ id: types.identifier }) - const TodoStore = types.model({ todos: types.array(Todo) }) - const OtherStore = types.model({ - todoRef: types.maybe( - types.reference(Todo, { - get(id) { - const node = resolveIdentifier(Todo, todos, id) - if (!node) { - throw new Error("Invalid ref") - } - return node - }, - set(value) { - return value.id - } - }) - ), - safeRef: types.safeReference(Todo, { - get(id) { - const node = resolveIdentifier(Todo, todos, id) - if (!node) { - throw new Error("Invalid ref") - } - return node - }, - set(value) { - return value.id - } - }) - }) - const todos = TodoStore.create({ - todos: [{ id: "1" }, { id: "2" }, { id: "3" }] - }) - unprotect(todos) - - // from a snapshot - const otherStore = OtherStore.create({ - todoRef: "1", - safeRef: "1" - }) - unprotect(otherStore) - expect(otherStore.todoRef!.id).toBe("1") - expect(otherStore.safeRef!.id).toBe("1") - - // assigning an id - otherStore.todoRef = "2" as any - otherStore.safeRef = "2" as any - expect(otherStore.todoRef!.id).toBe("2") - expect(otherStore.safeRef!.id).toBe("2") - - // assigning a node directly - otherStore.todoRef = todos.todos[2] - otherStore.safeRef = todos.todos[2] - expect(otherStore.todoRef!.id).toBe("3") - expect(otherStore.safeRef!.id).toBe("3") - - // getting the snapshot - expect(getSnapshot(otherStore)).toEqual({ - todoRef: "3", - safeRef: "3" - }) - - // the removed node should throw on standard refs access - // and be set to undefined on safe ones - todos.todos.splice(2, 1) - expect(() => otherStore.todoRef).toThrow("Invalid ref") - expect(otherStore.safeRef).toBe(undefined) -}) diff --git a/packages/mobx-state-tree/__tests__/core/reference-onInvalidated.test.ts b/packages/mobx-state-tree/__tests__/core/reference-onInvalidated.test.ts deleted file mode 100644 index 4310e1914..000000000 --- a/packages/mobx-state-tree/__tests__/core/reference-onInvalidated.test.ts +++ /dev/null @@ -1,492 +0,0 @@ -import { - types, - OnReferenceInvalidated, - Instance, - ReferenceIdentifier, - IAnyStateTreeNode, - unprotect, - OnReferenceInvalidatedEvent, - getSnapshot, - applySnapshot, - clone, - destroy -} from "../../src" - -const Todo = types.model({ id: types.identifier }) - -const createSnapshot = (partialSnapshot: any) => ({ - todos: [{ id: "1" }, { id: "2" }, { id: "3" }, { id: "4" }], - ...partialSnapshot -}) - -const createStore = ( - partialSnapshot: any, - onInvalidated?: OnReferenceInvalidated>, - customRef = false -) => { - const refOptions = { - onInvalidated, - get(identifier: ReferenceIdentifier, parent: IAnyStateTreeNode | null) { - return (parent as Instance).todos.find((t) => t.id === identifier) - }, - set(value: Instance): ReferenceIdentifier { - return value.id - } - } - - if (!customRef) { - // @ts-ignore - delete refOptions.get - // @ts-ignore - delete refOptions.set - } - - const Store = types.model({ - todos: types.array(Todo), - onInv: types.maybe(types.reference(Todo, refOptions as any)), - single: types.safeReference(Todo), - deep: types.optional( - types.model({ - single: types.safeReference(Todo) - }), - {} - ), - arr: types.array(types.safeReference(Todo)), - map: types.map(types.safeReference(Todo)) - }) - - const s = Store.create(createSnapshot(partialSnapshot)) - unprotect(s) - return s -} - -for (const customRef of [false, true]) { - describe(`onInvalidated - customRef: ${customRef}`, () => { - test("from snapshot without accessing the referenced node", () => { - let ev: OnReferenceInvalidatedEvent> | undefined - let oldRefId!: string - let calls = 0 - const onInv: OnReferenceInvalidated> = (ev1) => { - calls++ - oldRefId = ev1.invalidTarget!.id - expect(ev1.invalidId).toBe(oldRefId) - ev = ev1 - ev1.removeRef() - } - const store = createStore({ onInv: "1" }, onInv) - - expect(calls).toBe(0) - store.todos.splice(0, 1) - expect(calls).toBe(1) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("1") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - - store.onInv = store.todos[0] - expect(calls).toBe(1) - store.todos.splice(0, 1) - expect(calls).toBe(2) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("2") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - }) - - test("applying snapshot without accesing the referenced node", () => { - let ev: OnReferenceInvalidatedEvent> | undefined - let oldRefId!: string - let calls = 0 - const onInv: OnReferenceInvalidated> = (ev1) => { - calls++ - oldRefId = ev1.invalidTarget!.id - expect(ev1.invalidId).toBe(oldRefId) - ev = ev1 - ev1.removeRef() - } - const store = createStore({}, onInv) - expect(calls).toBe(0) - applySnapshot(store, createSnapshot({ onInv: "1" })) - expect(calls).toBe(0) - store.todos.splice(0, 1) - expect(calls).toBe(1) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("1") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - - store.onInv = store.todos[0] - expect(calls).toBe(1) - store.todos.splice(0, 1) - expect(calls).toBe(2) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("2") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - }) - - test("runtime change", () => { - let ev: OnReferenceInvalidatedEvent> | undefined - let oldRefId!: string - let calls = 0 - const onInv: OnReferenceInvalidated> = (ev1) => { - calls++ - oldRefId = ev1.invalidTarget!.id - expect(ev1.invalidId).toBe(oldRefId) - ev = ev1 - ev1.removeRef() - } - const store = createStore({}, onInv) - - expect(calls).toBe(0) - store.onInv = store.todos[1] - expect(calls).toBe(0) - store.onInv = store.todos[0] - expect(calls).toBe(0) - store.todos.remove(store.todos[0]) - expect(calls).toBe(1) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("1") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - - store.onInv = store.todos[0] - expect(calls).toBe(1) - store.todos.remove(store.todos[0]) - expect(calls).toBe(2) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("2") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - }) - - test("replacing ref", () => { - let ev: OnReferenceInvalidatedEvent> | undefined - let oldRefId!: string - let calls = 0 - const onInv: OnReferenceInvalidated> = (ev1) => { - calls++ - oldRefId = ev1.invalidTarget!.id - expect(ev1.invalidId).toBe(oldRefId) - ev = ev1 - ev1.replaceRef(store.todos[1]) - } - const store = createStore({}, onInv) - - expect(calls).toBe(0) - store.onInv = store.todos[0] - expect(calls).toBe(0) - store.todos.remove(store.todos[0]) - expect(calls).toBe(1) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("1") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv!.id).toBe("2") - expect(getSnapshot(store).onInv).toBe("2") - }) - - test("cloning works", () => { - let ev: OnReferenceInvalidatedEvent> | undefined - let oldRefId!: string - let calls = 0 - const onInv: OnReferenceInvalidated> = (ev1) => { - calls++ - oldRefId = ev1.invalidTarget!.id - expect(ev1.invalidId).toBe(oldRefId) - ev = ev1 - ev1.removeRef() - } - const store1 = createStore({}, onInv) - - expect(calls).toBe(0) - store1.onInv = store1.todos[0] - expect(calls).toBe(0) - - const store = clone(store1) - unprotect(store) - expect(calls).toBe(0) - store.onInv = store.todos[0] - expect(calls).toBe(0) - store.todos.remove(store.todos[0]) - expect(calls).toBe(1) - expect(ev!.parent).toBe(store) - expect(oldRefId).toBe("1") - expect(ev!.removeRef).toBeTruthy() - expect(ev!.replaceRef).toBeTruthy() - expect(store.onInv).toBe(undefined) - expect(getSnapshot(store).onInv).toBeUndefined() - // make sure other ref stil points to the right one - expect(store1.onInv).toBe(store1.todos[0]) - }) - }) -} - -describe("safeReference", () => { - test("model property", () => { - const store = createStore({}) - expect(store.single).toBeUndefined() - store.single = store.todos[0] - expect(store.single).toBe(store.todos[0]) - store.todos.remove(store.todos[0]) - expect(store.single).toBeUndefined() - }) - - test("deep model property", () => { - const store = createStore({}) - expect(store.deep.single).toBeUndefined() - store.deep.single = store.todos[0] - expect(store.deep.single).toBe(store.todos[0]) - store.todos.remove(store.todos[0]) - expect(store.deep.single).toBeUndefined() - }) - - test("array child", () => { - const store = createStore({}) - expect(store.arr.length).toBe(0) - - store.arr.push(store.todos[0]) - store.arr.push(store.todos[2]) - expect(store.arr.length).toBe(2) - expect(store.arr[0]!.id).toBe("1") - expect(store.arr[1]!.id).toBe("3") - - store.todos.splice(0, 1) - expect(store.arr.length).toBe(1) - expect(store.arr[0]!.id).toBe("3") - }) - - test("map child", () => { - const store = createStore({}) - expect(store.map.size).toBe(0) - - store.map.set("a", store.todos[0]) - store.map.set("c", store.todos[2]) - expect(store.map.size).toBe(2) - expect(store.map.get("a")!.id).toBe("1") - expect(store.map.get("c")!.id).toBe("3") - - store.todos.splice(0, 1) - expect(store.map.size).toBe(1) - expect(store.map.get("c")!.id).toBe("3") - }) - - test("invalid references in a snapshot should be removed", () => { - const store = createStore({ single: "100", arr: ["100", "1"], map: { a: "100", b: "1" } }) - expect(store.single).toBeUndefined() - expect(store.arr.length).toBe(1) - expect(store.arr[0]!.id).toBe("1") - expect(store.map.size).toBe(1) - expect(store.map.get("b")!.id).toBe("1") - - // check reassignation still works - store.single = store.todos[0] - expect(store.single).toBe(store.todos[0]) - store.todos.remove(store.todos[0]) - expect(store.single).toBeUndefined() - }) - - test("setting it to an invalid id and then accessing it should still result in an error", () => { - const store = createStore({}) - store.single = "100" as any - expect(() => { - const s = store.single - }).toThrow("Failed to resolve reference") - }) -}) - -test("#1115 - safe reference doesn't become invalidated when the reference has never been acessed", () => { - const MyRefModel = types.model("MyRefModel", { - id: types.identifier - }) - - const SafeRef = types.model("SafeRef", { - ref: types.safeReference(MyRefModel) - }) - - const RootModel = types - .model("RootModel", { - mapOfRef: types.map(MyRefModel), - arrayOfSafeRef: types.array(SafeRef) - }) - .actions((self) => ({ - deleteSqr(id: string) { - self.mapOfRef.delete(id) - } - })) - - const rootModel = RootModel.create({ - mapOfRef: { - sqr1: { - id: "sqr1" - }, - sqr2: { - id: "sqr2" - } - }, - arrayOfSafeRef: [ - { - ref: "sqr2" - }, - { - ref: "sqr1" - }, - { - ref: "sqr2" - } - ] - }) - - expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ - { - ref: "sqr2" - }, - { - ref: "sqr1" - }, - { - ref: "sqr2" - } - ]) - - rootModel.deleteSqr("sqr1") - expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ - { - ref: "sqr2" - }, - { - ref: undefined - }, - { - ref: "sqr2" - } - ]) - - rootModel.deleteSqr("sqr2") - expect(getSnapshot(rootModel.arrayOfSafeRef)).toEqual([ - { - ref: undefined - }, - { - ref: undefined - }, - { - ref: undefined - } - ]) -}) - -describe("safeReference with acceptsUndefined: false", () => { - const MyRefModel = types.model("MyRefModel", { - id: types.identifier - }) - - const SafeRef = types.safeReference(MyRefModel, { acceptsUndefined: false }) - - it("removes invalidates items from map/array", () => { - const Store = types.model({ - todos: types.array(MyRefModel), - arr: types.array(SafeRef), - map: types.map(SafeRef) - }) - - const store = Store.create({ - todos: [{ id: "1" }, { id: "2" }], - arr: ["1", "2"], - map: { - a1: "1", - a2: "2" - } - }) - unprotect(store) - - // just to check TS is happy with this - const arr: Instance[] = store.arr - - store.todos.splice(0, 1) - expect(store.arr.length).toBe(1) - expect(store.map.size).toBe(1) - }) - - if (process.env.NODE_ENV !== "production") { - it("throws when a model property is invalidated", () => { - const Store = types.model({ - todos: types.array(MyRefModel), - single: SafeRef - }) - - const store = Store.create({ - todos: [{ id: "1" }, { id: "2" }], - single: "1" - }) - unprotect(store) - - expect(() => { - store.todos.splice(0, 1) - }).toThrow("value `undefined` is not assignable to type") - }) - - it("does not accept undefined in the array", () => { - const Store = types.model({ - todos: types.array(MyRefModel), - arr: types.array(SafeRef) - }) - - expect(() => - Store.create({ - todos: [{ id: "1" }, { id: "2" }], - arr: ["1", undefined as any] - }) - ).toThrow("value `undefined` is not assignable to type") - }) - - it("does not accept undefined in the map", () => { - const Store = types.model({ - todos: types.array(MyRefModel), - map: types.map(SafeRef) - }) - - expect(() => - Store.create({ - todos: [{ id: "1" }, { id: "2" }], - map: { - a1: "1", - a2: undefined as any - } - }) - ).toThrow("value `undefined` is not assignable to type") - }) - } -}) - -test("#1275 - removing an object from a map should result in the snapshot of references being modified", () => { - const Item = types.model({ - id: types.identifier - }) - - const Root = types.model({ - items: types.map(Item), - refs: types.array(types.safeReference(Item)) - }) - - const thing = Root.create({ - items: { aa: { id: "a" }, bb: { id: "b" }, cc: { id: "c" } }, - refs: ["a", "b", "c"] - }) - unprotect(thing) - - destroy(thing.items.get("bb")!) - expect(getSnapshot(thing.refs)).toEqual(["a", "c"]) -}) diff --git a/packages/mobx-state-tree/__tests__/core/reference.test.ts b/packages/mobx-state-tree/__tests__/core/reference.test.ts deleted file mode 100644 index aaebfc95b..000000000 --- a/packages/mobx-state-tree/__tests__/core/reference.test.ts +++ /dev/null @@ -1,1115 +0,0 @@ -import { reaction, autorun, isObservable, configure } from "mobx" -import { - types, - getSnapshot, - applySnapshot, - onPatch, - applyPatch, - unprotect, - detach, - resolveIdentifier, - getRoot, - cast, - SnapshotOut, - IAnyModelType, - Instance, - SnapshotOrInstance, - isAlive, - destroy, - castToReferenceSnapshot, - tryReference, - isValidReference, - isStateTreeNode, - addDisposer -} from "../../src" - -test("it should support prefixed paths in maps", () => { - const User = types.model({ - id: types.identifier, - name: types.string - }) - const UserStore = types.model({ - user: types.reference(User), - users: types.map(User) - }) - const store = UserStore.create({ - user: "17", - users: { - "17": { id: "17", name: "Michel" }, - "18": { id: "18", name: "Veria" } - } - }) - unprotect(store) - expect(store.users.get("17")!.name).toBe("Michel") - expect(store.users.get("18")!.name).toBe("Veria") - expect(store.user.name).toBe("Michel") - store.user = store.users.get("18")! - expect(store.user.name).toBe("Veria") - store.users.get("18")!.name = "Noa" - expect(store.user.name).toBe("Noa") - expect(getSnapshot(store)).toEqual({ - user: "18", - users: { "17": { id: "17", name: "Michel" }, "18": { id: "18", name: "Noa" } } - } as SnapshotOut) -}) - -test("it should support prefixed paths in arrays", () => { - const User = types.model({ - id: types.identifier, - name: types.string - }) - const UserStore = types.model({ - user: types.reference(User), - users: types.array(User) - }) - const store = UserStore.create({ - user: "17", - users: [ - { id: "17", name: "Michel" }, - { id: "18", name: "Veria" } - ] - }) - unprotect(store) - expect(store.users[0].name).toBe("Michel") - expect(store.users[1].name).toBe("Veria") - expect(store.user.name).toBe("Michel") - store.user = store.users[1] - expect(store.user.name).toBe("Veria") - store.users[1].name = "Noa" - expect(store.user.name).toBe("Noa") - expect(getSnapshot(store)).toEqual({ - user: "18", - users: [ - { id: "17", name: "Michel" }, - { id: "18", name: "Noa" } - ] - } as SnapshotOut) -}) - -if (process.env.NODE_ENV !== "production") { - test("identifiers are required", () => { - const Todo = types.model({ - id: types.identifier - }) - expect(Todo.is({})).toBe(false) - expect(Todo.is({ id: "x" })).toBe(true) - expect(() => (Todo.create as any)()).toThrowError( - " `undefined` is not assignable to type: `identifier` (Value is not a valid identifier, expected a string)" - ) - }) - - test("identifiers cannot be modified", () => { - const Todo = types.model({ - id: types.identifier - }) - const todo = Todo.create({ id: "x" }) - unprotect(todo) - expect(() => (todo.id = "stuff")).toThrowError( - "[mobx-state-tree] Tried to change identifier from 'x' to 'stuff'. Changing identifiers is not allowed." - ) - expect(() => applySnapshot(todo, { id: "stuff" })).toThrowError( - "[mobx-state-tree] Tried to change identifier from 'x' to 'stuff'. Changing identifiers is not allowed." - ) - }) -} - -test("it should resolve refs during creation, when using path", () => { - const values: number[] = [] - const Book = types.model({ - id: types.identifier, - price: types.number - }) - const BookEntry = types - .model({ - book: types.reference(Book) - }) - .views((self) => ({ - get price() { - return self.book.price * 2 - } - })) - const Store = types.model({ - books: types.array(Book), - entries: types.optional(types.array(BookEntry), []) - }) - const s = Store.create({ - books: [{ id: "3", price: 2 }] - }) - unprotect(s) - reaction( - () => s.entries.reduce((a, e) => a + e.price, 0), - (v) => values.push(v) - ) - s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) - expect(s.entries[0].price).toBe(4) - expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) - const entry = BookEntry.create({ book: castToReferenceSnapshot(s.books[0]) }) // N.B. ref is initially not resolvable! - s.entries.push(entry) - expect(s.entries[1].price).toBe(4) - expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(8) - expect(values).toEqual([4, 8]) -}) - -test("it should resolve refs over late types", () => { - const Book = types.model({ - id: types.identifier, - price: types.number - }) - const BookEntry = types - .model({ - book: types.reference(types.late(() => Book)) - }) - .views((self) => ({ - get price() { - return self.book.price * 2 - } - })) - const Store = types.model({ - books: types.array(Book), - entries: types.array(BookEntry) - }) - const s = Store.create({ - books: [{ id: "3", price: 2 }] - }) - unprotect(s) - s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) - expect(s.entries[0].price).toBe(4) - expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) -}) - -test("it should resolve refs during creation, when using generic reference", () => { - const values: number[] = [] - const Book = types.model({ - id: types.identifier, - price: types.number - }) - const BookEntry = types - .model({ - book: types.reference(Book) - }) - .views((self) => ({ - get price() { - return self.book.price * 2 - } - })) - const Store = types.model({ - books: types.array(Book), - entries: types.optional(types.array(BookEntry), []) - }) - const s = Store.create({ - books: [{ id: "3", price: 2 }] - }) - unprotect(s) - reaction( - () => s.entries.reduce((a, e) => a + e.price, 0), - (v) => values.push(v) - ) - s.entries.push({ book: castToReferenceSnapshot(s.books[0]) }) - expect(s.entries[0].price).toBe(4) - expect(s.entries.reduce((a, e) => a + e.price, 0)).toBe(4) - const entry = BookEntry.create({ book: castToReferenceSnapshot(s.books[0]) }) // can refer to book, even when not part of tree yet - expect(getSnapshot(entry)).toEqual({ book: "3" }) - s.entries.push(entry) - expect(values).toEqual([4, 8]) -}) - -test("identifiers should support subtypes of types.string and types.number", () => { - const M = types.model({ - id: types.refinement(types.identifierNumber, (n) => n > 5) - }) - expect(M.is({})).toBe(false) - expect(M.is({ id: "test" })).toBe(false) - expect(M.is({ id: "6" })).toBe(false) - expect(M.is({ id: "4" })).toBe(false) - expect(M.is({ id: 6 })).toBe(true) - expect(M.is({ id: 4 })).toBe(false) - - const S = types.model({ - mies: types.map(M), - ref: types.reference(M) - }) - const s = S.create({ mies: { "7": { id: 7 } }, ref: "7" }) - expect(s.mies.get("7")).toBeTruthy() - expect(s.ref).toBe(s.mies.get("7")) -}) - -test("string identifiers should not accept numbers", () => { - const F = types.model({ - id: types.identifier - }) - expect(F.is({ id: "4" })).toBe(true) - expect(F.is({ id: 4 })).toBe(false) - const F2 = types.model({ - id: types.identifier - }) - expect(F2.is({ id: "4" })).toBe(true) - expect(F2.is({ id: 4 })).toBe(false) -}) - -test("122 - identifiers should support numbers as well", () => { - const F = types.model({ - id: types.identifierNumber - }) - expect( - F.create({ - id: 3 - }).id - ).toBe(3) - - expect(F.is({ id: 4 })).toBe(true) - expect(F.is({ id: "4" })).toBe(false) - expect(F.is({ id: "bla" })).toBe(false) -}) - -test("self reference with a late type", () => { - const Book = types.model("Book", { - id: types.identifier, - genre: types.string, - reference: types.reference(types.late((): IAnyModelType => Book)) - }) - const Store = types - .model("Store", { - books: types.array(Book) - }) - .actions((self) => { - function addBook(book: SnapshotOrInstance) { - self.books.push(book) - } - return { - addBook - } - }) - const s = Store.create({ - books: [{ id: "1", genre: "thriller", reference: "" }] - }) - const book2 = Book.create({ - id: "2", - genre: "romance", - reference: castToReferenceSnapshot(s.books[0]) - }) - s.addBook(book2) - expect((s.books[1].reference as Instance).genre).toBe("thriller") -}) - -test("when applying a snapshot, reference should resolve correctly if value added after", () => { - const Box = types.model({ - id: types.identifierNumber, - name: types.string - }) - const Factory = types.model({ - selected: types.reference(Box), - boxes: types.array(Box) - }) - expect(() => - Factory.create({ - selected: 1, - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ] - }) - ).not.toThrow() -}) - -test("it should fail when reference snapshot is ambiguous", () => { - const Box = types.model("Box", { - id: types.identifierNumber, - name: types.string - }) - const Arrow = types.model("Arrow", { - id: types.identifierNumber, - name: types.string - }) - const BoxOrArrow = types.union(Box, Arrow) - const Factory = types.model({ - selected: types.reference(BoxOrArrow), - boxes: types.array(Box), - arrows: types.array(Arrow) - }) - const store = Factory.create({ - selected: 2, - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ], - arrows: [{ id: 2, name: "arrow" }] - }) - expect(() => { - // tslint:disable-next-line:no-unused-expression - store.selected // store.boxes[1] // throws because it can't know if you mean a box or an arrow! - }).toThrowError( - "[mobx-state-tree] Cannot resolve a reference to type '(Box | Arrow)' with id: '2' unambigously, there are multiple candidates: /boxes/1, /arrows/0" - ) - unprotect(store) - // first update the reference, than create a new matching item! Ref becomes ambigous now... - store.selected = 1 as any // valid assignment - expect(store.selected).toBe(store.boxes[0]) // unambigous identifier - let err!: Error - autorun(() => store.selected, { - onError(e) { - err = e - } - }) - expect(store.selected).toBe(store.boxes[0]) // unambigous identifier - store.arrows.push({ id: 1, name: "oops" }) - expect(err.message).toBe( - "[mobx-state-tree] Cannot resolve a reference to type '(Box | Arrow)' with id: '1' unambigously, there are multiple candidates: /boxes/0, /arrows/1" - ) -}) - -test("it should support array of references", () => { - const Box = types.model({ - id: types.identifierNumber, - name: types.string - }) - const Factory = types.model({ - selected: types.array(types.reference(Box)), - boxes: types.array(Box) - }) - const store = Factory.create({ - selected: [], - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ] - }) - unprotect(store) - expect(() => { - store.selected.push(store.boxes[0]) - }).not.toThrow() - expect(getSnapshot(store.selected)).toEqual([1]) - expect(() => { - store.selected.push(store.boxes[1]) - }).not.toThrow() - expect(getSnapshot(store.selected)).toEqual([1, 2]) -}) - -test("it should restore array of references from snapshot", () => { - const Box = types.model({ - id: types.identifierNumber, - name: types.string - }) - const Factory = types.model({ - selected: types.array(types.reference(Box)), - boxes: types.array(Box) - }) - const store = Factory.create({ - selected: [1, 2], - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ] - }) - unprotect(store) - expect(store.selected[0] === store.boxes[0]).toEqual(true) - expect(store.selected[1] === store.boxes[1]).toEqual(true) -}) - -test("it should support map of references", () => { - const Box = types.model({ - id: types.identifierNumber, - name: types.string - }) - const Factory = types.model({ - selected: types.map(types.reference(Box)), - boxes: types.array(Box) - }) - const store = Factory.create({ - selected: {}, - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ] - }) - unprotect(store) - expect(() => { - store.selected.set("from", store.boxes[0]) - }).not.toThrow() - expect(getSnapshot(store.selected)).toEqual({ from: 1 }) - expect(() => { - store.selected.set("to", store.boxes[1]) - }).not.toThrow() - expect(getSnapshot(store.selected)).toEqual({ from: 1, to: 2 }) -}) - -test("it should restore map of references from snapshot", () => { - const Box = types.model({ - id: types.identifierNumber, - name: types.string - }) - const Factory = types.model({ - selected: types.map(types.reference(Box)), - boxes: types.array(Box) - }) - const store = Factory.create({ - selected: { from: 1, to: 2 }, - boxes: [ - { id: 1, name: "hello" }, - { id: 2, name: "world" } - ] - }) - unprotect(store) - expect(store.selected.get("from") === store.boxes[0]).toEqual(true) - expect(store.selected.get("to") === store.boxes[1]).toEqual(true) -}) - -test("it should support relative lookups", () => { - const Node = types.model({ - id: types.identifierNumber, - children: types.optional(types.array(types.late((): IAnyModelType => Node)), []) - }) - const root = Node.create({ - id: 1, - children: [ - { - id: 2, - children: [ - { - id: 4 - } - ] - }, - { - id: 3 - } - ] - }) - unprotect(root) - expect(getSnapshot(root)).toEqual({ - id: 1, - children: [ - { id: 2, children: [{ id: 4, children: [] }] }, - { id: 3, children: [] } - ] - }) - expect(resolveIdentifier(Node, root, 1)).toBe(root) - expect(resolveIdentifier(Node, root, 4)).toBe(root.children[0].children[0]) - expect(resolveIdentifier(Node, root.children[0].children[0], 3)).toBe(root.children[1]) - const n2 = detach(root.children[0]) - unprotect(n2) - expect(resolveIdentifier(Node, n2, 2)).toBe(n2) - expect(resolveIdentifier(Node, root, 2)).toBe(undefined) - expect(resolveIdentifier(Node, root, 4)).toBe(undefined) - expect(resolveIdentifier(Node, n2, 3)).toBe(undefined) - expect(resolveIdentifier(Node, n2, 4)).toBe(n2.children[0]) - expect(resolveIdentifier(Node, n2.children[0], 2)).toBe(n2) - const n5 = Node.create({ id: 5 }) - expect(resolveIdentifier(Node, n5, 4)).toBe(undefined) - n2.children.push(n5) - expect(resolveIdentifier(Node, n5, 4)).toBe(n2.children[0]) - expect(resolveIdentifier(Node, n2.children[0], 5)).toBe(n5) -}) - -test("References are non-nullable by default", () => { - const Todo = types.model({ - id: types.identifierNumber - }) - const Store = types.model({ - todo: types.maybe(Todo), - ref: types.reference(Todo), - maybeRef: types.maybe(types.reference(Todo)) - }) - expect(Store.is({})).toBe(false) - expect(Store.is({ ref: 3 })).toBe(true) - expect(Store.is({ ref: null })).toBe(false) - expect(Store.is({ ref: undefined })).toBe(false) - expect(Store.is({ ref: 3, maybeRef: 3 })).toBe(true) - expect(Store.is({ ref: 3, maybeRef: undefined })).toBe(true) - let store = Store.create({ - todo: { id: 3 }, - ref: 3 - }) - expect(store.ref).toBe(store.todo) - expect(store.maybeRef).toBe(undefined) - store = Store.create({ - todo: { id: 3 }, - ref: 4 - }) - unprotect(store) - if (process.env.NODE_ENV !== "production") { - expect(store.maybeRef).toBe(undefined) - expect(() => store.ref).toThrow( - "[mobx-state-tree] Failed to resolve reference '4' to type 'AnonymousModel' (from node: /ref)" - ) - store.maybeRef = 3 as any // valid assignment - expect(store.maybeRef).toBe(store.todo) - store.maybeRef = 4 as any // valid assignment - expect(() => store.maybeRef).toThrow( - "[mobx-state-tree] Failed to resolve reference '4' to type 'AnonymousModel' (from node: /maybeRef)" - ) - store.maybeRef = undefined - expect(store.maybeRef).toBe(undefined) - expect(() => ((store as any).ref = undefined)).toThrow(/Error while converting/) - } -}) - -test("References are described properly", () => { - const Todo = types.model({ - id: types.identifierNumber - }) - const Store = types.model({ - todo: types.maybe(Todo), - ref: types.reference(Todo), - maybeRef: types.maybe(types.reference(Todo)) - }) - expect(Store.describe()).toBe( - "{ todo: ({ id: identifierNumber } | undefined?); ref: reference(AnonymousModel); maybeRef: (reference(AnonymousModel) | undefined?) }" - ) -}) - -test("References in recursive structures", () => { - const Folder = types.model("Folder", { - id: types.identifierNumber, - name: types.string, - files: types.array(types.string) - }) - const Tree = types - .model("Tree", { - // sadly, this becomes any, and further untypeable... - children: types.array(types.late((): IAnyModelType => Tree)), - data: types.maybeNull(types.reference(Folder)) - }) - .actions((self) => { - function addFolder(data: SnapshotOrInstance) { - const folder3 = Folder.create(data) - getRoot(self).putFolderHelper(folder3) - self.children.push( - Tree.create({ data: castToReferenceSnapshot(folder3), children: [] }) - ) - } - return { addFolder } - }) - - const Storage = types - .model("Storage", { - objects: types.map(Folder), - tree: Tree - }) - .actions((self) => ({ - putFolderHelper(aFolder: SnapshotOrInstance) { - self.objects.put(aFolder) - } - })) - const store = Storage.create({ objects: {}, tree: { children: [], data: null } }) - const folder = { id: 1, name: "Folder 1", files: ["a.jpg", "b.jpg"] } - store.tree.addFolder(folder) - expect(getSnapshot(store)).toEqual({ - objects: { - "1": { - files: ["a.jpg", "b.jpg"], - id: 1, - name: "Folder 1" - } - }, - tree: { - children: [ - { - children: [], - data: 1 - } - ], - data: null - } - }) - expect(store.objects.get("1")).toBe(store.tree.children[0].data) - const folder2 = { id: 2, name: "Folder 2", files: ["c.jpg", "d.jpg"] } - store.tree.children[0].addFolder(folder2) - expect(getSnapshot(store)).toEqual({ - objects: { - "1": { - files: ["a.jpg", "b.jpg"], - id: 1, - name: "Folder 1" - }, - "2": { - files: ["c.jpg", "d.jpg"], - id: 2, - name: "Folder 2" - } - }, - tree: { - children: [ - { - children: [ - { - children: [], - data: 2 - } - ], - data: 1 - } - ], - data: null - } - }) - expect(store.objects.get("1")).toBe(store.tree.children[0].data) - expect(store.objects.get("2")).toBe(store.tree.children[0].children[0].data) -}) - -test("it should applyPatch references in array", () => { - const Item = types.model("Item", { - id: types.identifier, - name: types.string - }) - const Folder = types - .model("Folder", { - id: types.identifier, - objects: types.map(Item), - hovers: types.array(types.reference(Item)) - }) - .actions((self) => { - function addObject(anItem: typeof Item.Type) { - self.objects.put(anItem) - } - function addHover(anItem: typeof Item.Type) { - self.hovers.push(anItem) - } - function removeHover(anItem: typeof Item.Type) { - self.hovers.remove(anItem) - } - return { - addObject, - addHover, - removeHover - } - }) - const folder = Folder.create({ id: "folder 1", objects: {}, hovers: [] }) - folder.addObject({ id: "item 1", name: "item name 1" }) - const item = folder.objects.get("item 1")! - const snapshot = getSnapshot(folder) - const newStore = Folder.create(snapshot) - onPatch(folder, (data) => { - applyPatch(newStore, data) - }) - folder.addHover(item) - expect(getSnapshot(newStore)).toEqual({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: ["item 1"] - }) - folder.removeHover(item) - expect(getSnapshot(newStore)).toEqual({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: [] - }) -}) - -test("it should applySnapshot references in array", () => { - const Item = types.model("Item", { - id: types.identifier, - name: types.string - }) - const Folder = types.model("Folder", { - id: types.identifier, - objects: types.map(Item), - hovers: types.array(types.reference(Item)) - }) - const folder = Folder.create({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: ["item 1"] - }) - const snapshot = JSON.parse(JSON.stringify(getSnapshot(folder))) - expect(snapshot).toEqual({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: ["item 1"] - }) - snapshot.hovers = [] - applySnapshot(folder, snapshot) - expect(getSnapshot(folder)).toEqual({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: [] - }) - snapshot.hovers = ["item 1"] - applySnapshot(folder, snapshot) - expect(getSnapshot(folder)).toEqual({ - id: "folder 1", - objects: { - "item 1": { - id: "item 1", - name: "item name 1" - } - }, - hovers: ["item 1"] - }) -}) - -test("array of references should work fine", () => { - const B = types.model("Block", { id: types.identifier }) - const S = types - .model("Store", { - blocks: types.array(B), - blockRefs: types.array(types.reference(B)) - }) - .actions((self) => { - return { - order() { - const res = self.blockRefs.slice() - self.blockRefs.replace([res[1], res[0]]) - } - } - }) - const a = S.create({ blocks: [{ id: "1" }, { id: "2" }], blockRefs: ["1", "2"] }) - a.order() - expect(a.blocks[0].id).toBe("1") - expect(a.blockRefs[0].id).toBe("2") -}) - -test("should serialize references correctly", () => { - const M = types.model({ - id: types.identifierNumber - }) - const S = types.model({ - mies: types.map(M), - ref: types.maybe(types.reference(M)) - }) - - const s = S.create({ - mies: { - 7: { - id: 7 - } - } - }) - unprotect(s) - - expect(Array.from(s.mies.keys())).toEqual(["7"]) - expect(s.mies.get("7")!.id).toBe(7) - expect(s.mies.get(7 as any)).toBe(s.mies.get("7")) // maps automatically normalizes the key - - s.mies.put({ - id: 8 - }) - expect(Array.from(s.mies.keys())).toEqual(["7", "8"]) - - s.ref = 8 as any - expect(s.ref!.id).toBe(8) // resolved from number - expect(getSnapshot(s).ref).toBe(8) // ref serialized as number - - s.ref = "7" as any // resolved from string - expect(s.ref!.id).toBe(7) // resolved from string - expect(getSnapshot(s).ref).toBe("7") // ref serialized as string (number would be ok as well) - - s.ref = s.mies.get("8")! - expect(s.ref.id).toBe(8) // resolved from instance - expect(getSnapshot(s).ref).toBe(8) // ref serialized as number - - s.ref = "9" as any // unresolvable - expect(getSnapshot(s).ref).toBe("9") // snapshot preserved as it was unresolvable - - s.mies.set(9 as any, { - id: 9 - }) - expect(Array.from(s.mies.keys())).toEqual(["7", "8", "9"]) - expect(s.mies.get("9")!.id).toBe(9) - expect(getSnapshot(s).ref).toBe("9") // ref serialized as string (number would be ok as well) -}) - -test("#1052 - Reference returns destroyed model after subtree replacing", () => { - const Todo = types.model("Todo", { - id: types.identifierNumber, - title: types.string - }) - - const Todos = types.model("Todos", { - items: types.array(Todo) - }) - - const Store = types - .model("Store", { - todos: Todos, - last: types.maybe(types.reference(Todo)), - lastWithId: types.maybe(types.reference(Todo)), - counter: -1 - }) - .actions((self) => ({ - load() { - self.counter++ - self.todos = Todos.create({ - items: [ - { id: 1, title: "Get Coffee " + self.counter }, - { id: 2, title: "Write simpler code " + self.counter } - ] - }) - }, - select(todo: Instance) { - self.last = todo - self.lastWithId = todo.id as any - } - })) - - const store = Store.create({ todos: {} }) - store.load() - - expect(store.last).toBe(undefined) - expect(store.lastWithId).toBe(undefined) - - const reactionFn = jest.fn() - const reactionDisposer = reaction(() => store.last, reactionFn) - const reactionFn2 = jest.fn() - const reactionDisposer2 = reaction(() => store.lastWithId, reactionFn2) - - try { - store.select(store.todos.items[0]) - - expect(isAlive(store.last!)).toBe(true) - expect(isObservable(store.last)).toBe(true) - expect(reactionFn).toHaveBeenCalledTimes(1) - expect(store.last!.title).toBe("Get Coffee 0") - - expect(isAlive(store.lastWithId!)).toBe(true) - expect(isObservable(store.lastWithId)).toBe(true) - expect(reactionFn2).toHaveBeenCalledTimes(1) - expect(store.lastWithId!.title).toBe("Get Coffee 0") - - store.load() - - expect(isAlive(store.last!)).toBe(true) - expect(isObservable(store.last)).toBe(true) - expect(reactionFn).toHaveBeenCalledTimes(2) - expect(store.last!.title).toBe("Get Coffee 1") - - expect(isAlive(store.lastWithId!)).toBe(true) - expect(isObservable(store.lastWithId)).toBe(true) - expect(reactionFn2).toHaveBeenCalledTimes(2) - expect(store.lastWithId!.title).toBe("Get Coffee 1") - } finally { - reactionDisposer() - reactionDisposer2() - } -}) - -test("#1080 - does not crash trying to resolve a reference to a destroyed+recreated model", () => { - configure({ - useProxies: "never" - }) - - const Branch = types.model("Branch", { - id: types.identifierNumber, - name: types.string - }) - - const User = types.model("User", { - id: types.identifierNumber, - email: types.maybeNull(types.string), - branches: types.maybeNull(types.array(Branch)) - }) - - const BranchStore = types - .model("BranchStore", { - activeBranch: types.maybeNull(types.reference(Branch)) - }) - .actions((self) => ({ - setActiveBranch(branchId: any) { - self.activeBranch = branchId - } - })) - - const RootStore = types - .model("RootStore", { - user: types.maybeNull(User), - branchStore: types.maybeNull(BranchStore) - }) - .actions((self) => ({ - setUser(snapshot: typeof userSnapshot) { - self.user = cast(snapshot) - }, - setBranchStore(snapshot: typeof branchStoreSnapshot) { - self.branchStore = cast(snapshot) - }, - destroyUser() { - destroy(self.user!) - }, - destroyBranchStore() { - destroy(self.branchStore!) - } - })) - - const userSnapshot = { - id: 1, - email: "test@test.com", - branches: [ - { - id: 1, - name: "Branch 1" - }, - { - id: 2, - name: "Branch 2" - } - ] - } - - const branchStoreSnapshot = {} - const rootStore = RootStore.create({ user: userSnapshot, branchStore: branchStoreSnapshot }) - - rootStore.branchStore!.setActiveBranch(1) - expect(rootStore.branchStore!.activeBranch).toEqual({ - id: 1, - name: "Branch 1" - }) - - rootStore.destroyUser() - rootStore.destroyBranchStore() - - rootStore.setUser(userSnapshot) - rootStore.setBranchStore(branchStoreSnapshot) - - rootStore.branchStore!.setActiveBranch(2) - expect(rootStore.branchStore!.activeBranch).toEqual({ - id: 2, - name: "Branch 2" - }) -}) - -test("tryReference / isValidReference", () => { - const Todo = types.model({ id: types.identifier }) - - const TodoStore = types - .model({ - todos: types.array(Todo), - ref1: types.maybe(types.reference(Todo)), - ref2: types.maybeNull(types.reference(Todo)), - ref3: types.maybe(types.reference(Todo)) - }) - .actions((self) => ({ - clearRef3() { - self.ref3 = undefined - }, - afterCreate() { - addDisposer( - self, - reaction( - () => isValidReference(() => self.ref3), - (valid) => { - if (!valid) { - this.clearRef3() - } - }, - { fireImmediately: true } - ) - ) - } - })) - - const store = TodoStore.create({ - todos: [{ id: "1" }, { id: "2" }, { id: "3" }] - }) - - expect(tryReference(() => store.ref1)).toBeUndefined() - expect(tryReference(() => store.ref2)).toBeUndefined() - expect(isValidReference(() => store.ref1)).toBe(false) - expect(isValidReference(() => store.ref2)).toBe(false) - - unprotect(store) - store.ref1 = store.todos[0] - store.ref2 = store.todos[1] - store.ref3 = store.todos[2] - - expect(isStateTreeNode(store.ref1)).toBe(true) - expect(isStateTreeNode(store.ref2)).toBe(true) - - expect(tryReference(() => store.ref1)).toBeDefined() - expect(tryReference(() => store.ref2)).toBeDefined() - expect(isValidReference(() => store.ref1)).toBe(true) - expect(isValidReference(() => store.ref2)).toBe(true) - - store.todos = cast([]) - - expect(tryReference(() => store.ref1)).toBeUndefined() - expect(tryReference(() => store.ref2)).toBeUndefined() - expect(isValidReference(() => store.ref1)).toBe(false) - expect(isValidReference(() => store.ref2)).toBe(false) - - // the reaction should have triggered and set this to undefined - expect(store.ref3).toBe(undefined) - - expect(() => tryReference(() => 5 as any)).toThrowError( - "The reference to be checked is not one of node, null or undefined" - ) - expect(() => isValidReference(() => 5 as any)).toThrowError( - "The reference to be checked is not one of node, null or undefined" - ) -}) - -test("#1162 - reference to union", () => { - const M1 = types.model({ id: types.identifier, type: types.string, sum: types.string }) - const M2 = types.model({ - id: types.identifier, - type: types.string, - data: types.string - }) - const AnyModel = types.union( - { - dispatcher(snapshot) { - switch (snapshot.type) { - case "type1": - return M1 - case "type2": - return M2 - default: - throw new Error() - } - } - }, - M1, - M2 - ) - - const Store = types.model({ - arr: types.array(AnyModel), - selected: types.reference(AnyModel) - }) - - const s = Store.create({ - selected: "num1", - arr: [ - { id: "num1", type: "type1", sum: "1" }, - { id: "num2", type: "type1", sum: "2" }, - { id: "num3", type: "type2", data: "3" } - ] - }) - unprotect(s) - - expect(s.selected.id).toBe("num1") - expect(s.selected.type).toBe("type1") - expect((s.selected as Instance).sum).toBe("1") - - s.selected = "num2" as any - expect(s.selected.id).toBe("num2") - expect(s.selected.type).toBe("type1") - expect((s.selected as Instance).sum).toBe("2") - - s.selected = "num3" as any - expect(s.selected.id).toBe("num3") - expect(s.selected.type).toBe("type2") - expect((s.selected as Instance).data).toBe("3") -}) diff --git a/packages/mobx-state-tree/__tests__/core/refinement.test.ts b/packages/mobx-state-tree/__tests__/core/refinement.test.ts deleted file mode 100644 index 921a7bb21..000000000 --- a/packages/mobx-state-tree/__tests__/core/refinement.test.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { getSnapshot, types } from "../../src" - -test("it should allow if type and predicate is correct", () => { - const Factory = types.model({ - number: types.refinement( - "positive number", - types.optional(types.number, 0), - (s) => typeof s === "number" && s >= 0 - ) - }) - const doc = Factory.create({ number: 42 }) - expect(getSnapshot(doc)).toEqual({ number: 42 }) -}) -if (process.env.NODE_ENV !== "production") { - test("it should throw if a correct type with failing predicate is given", () => { - const Factory = types.model({ - number: types.refinement( - "positive number", - types.optional(types.number, 0), - (s) => typeof s === "number" && s >= 0 - ) - }) - expect(() => { - Factory.create({ number: "givenStringInstead" } as any) - }).toThrowError( - `[mobx-state-tree] Error while converting \`{\"number\":\"givenStringInstead\"}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`\"givenStringInstead\"\` is not assignable to type: \`positive number\` (Value is not a number).` - ) - expect(() => { - Factory.create({ number: -4 }) - }).toThrowError( - `[mobx-state-tree] Error while converting \`{\"number\":-4}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`-4\` is not assignable to type: \`positive number\` (Value does not respect the refinement predicate).` - ) - }) - test("it should throw custom error message with failing predicate is given", () => { - const Factory = types.model({ - number: types.refinement( - types.optional(types.number, 0), - (s) => typeof s === "number" && s >= 0, - (s) => "A positive number was expected" - ) - }) - expect(() => { - Factory.create({ number: "givenStringInstead" } as any) - }).toThrowError( - `[mobx-state-tree] Error while converting \`{\"number\":\"givenStringInstead\"}\` to \`AnonymousModel\`:\n\n at path \"/number\" value \`\"givenStringInstead\"\` is not assignable to type: \`number\` (Value is not a number).` - ) - expect(() => { - Factory.create({ number: -4 }) - }).toThrowError( - `[mobx-state-tree] Error while converting \`{\"number\":-4}\` to \`AnonymousModel\`:\n\n at path "/number" value \`-4\` is not assignable to type: \`number\` (A positive number was expected).` - ) - }) -} diff --git a/packages/mobx-state-tree/__tests__/core/reflection.test.ts b/packages/mobx-state-tree/__tests__/core/reflection.test.ts deleted file mode 100644 index cb9efc476..000000000 --- a/packages/mobx-state-tree/__tests__/core/reflection.test.ts +++ /dev/null @@ -1,244 +0,0 @@ -import { - types, - getMembers, - getPropertyMembers, - IAnyStateTreeNode, - getType, - IAnyModelType, - IModelReflectionData, - IModelReflectionPropertiesData, - flow -} from "../../src" - -const User = types.model("User", { - id: types.identifier, - name: types.string -}) - -const Model = types - .model({ - isPerson: false, - users: types.optional(types.map(User), {}), - dogs: types.array(User), - user: types.maybe(types.late(() => User)) - }) - .volatile((self) => ({ - volatileProperty: { propName: "halo" } - })) - .actions((self) => { - function actionName() { - return 1 - } - return { - actionName, - generatorAction: flow(function* generatorAction() { - const promise = new Promise((resolve) => { - resolve(true) - }) - yield promise - }) - } - }) - .views((self) => ({ - get viewName() { - return 1 - } - })) - -function expectPropertyMembersToMatchMembers( - propertyMembers: IModelReflectionPropertiesData, - members: IModelReflectionData -) { - expect(propertyMembers).toEqual({ - name: members.name, - properties: members.properties - }) -} - -test("reflection - model", () => { - const node = Model.create() - const reflection = getMembers(node) - expect(reflection.name).toBe("AnonymousModel") - expect(reflection.actions.includes("actionName")).toBe(true) - expect(reflection.flowActions.includes("generatorAction")).toBe(true) - expect(reflection.views.includes("viewName")).toBe(true) - expect(reflection.volatile.includes("volatileProperty")).toBe(true) - expect(!!reflection.properties.users).toBe(true) - expect(!!reflection.properties.isPerson).toBe(true) - - const typeReflection = getPropertyMembers(Model) - expectPropertyMembersToMatchMembers(typeReflection, reflection) - const reflection2 = getPropertyMembers(node) - expectPropertyMembersToMatchMembers(reflection2, reflection) -}) -test("reflection - map", () => { - const node = Model.create({ - users: { "1": { id: "1", name: "Test" } } - }) - const node2 = node.users.get("1")! - const reflection = getMembers(node2) - expect(reflection.name).toBe("User") - expect(!!reflection.properties.id).toBe(true) - expect(!!reflection.properties.name).toBe(true) - - const typeReflection = getPropertyMembers(getType(node2) as IAnyModelType) - expectPropertyMembersToMatchMembers(typeReflection, reflection) - const reflection2 = getPropertyMembers(node2) - expectPropertyMembersToMatchMembers(reflection2, reflection) -}) -test("reflection - array", () => { - const node = Model.create({ - dogs: [{ id: "1", name: "Test" }] - }) - const node2 = node.dogs[0] - const reflection = getMembers(node2) - expect(!!reflection.properties.id).toBe(true) - expect(!!reflection.properties.name).toBe(true) - - const typeReflection = getPropertyMembers(getType(node2) as IAnyModelType) - expectPropertyMembersToMatchMembers(typeReflection, reflection) - const reflection2 = getPropertyMembers(node2) - expectPropertyMembersToMatchMembers(reflection2, reflection) -}) -test("reflection - late", () => { - const node = Model.create({ - user: { id: "5", name: "Test" } - }) - const empty: IAnyStateTreeNode = {} - const reflection = getMembers(node.user || empty) - const keys = Object.keys(reflection.properties || {}) - expect(keys.includes("name")).toBe(true) - expect(reflection.properties.name.describe()).toBe("string") -}) -if (process.env.NODE_ENV !== "production") { - test("reflection - throw on non model node for getMembers", () => { - const node = Model.create({ - users: { "1": { id: "1", name: "Test" } } - }) - expect(() => (node.users ? getMembers(node.users) : {})).toThrowError() - }) - - test("reflection - throw on non model type/node for getMembers", () => { - expect(() => getPropertyMembers(types.array(types.number) as any)).toThrowError() - - const node = Model.create({ - users: { "1": { id: "1", name: "Test" } } - }) - expect(() => getPropertyMembers(node.users)).toThrowError() - }) -} -test("reflection - can retrieve property names", () => { - const node = Model.create() - const reflection = getMembers(node) - const keys = Object.keys(reflection.properties) - expect(keys.includes("users")).toBe(true) - expect(keys.includes("isPerson")).toBe(true) -}) -test("reflection - property contains type", () => { - const TestModel = types.model({ - string: types.string, - optional: false - }) - const node = TestModel.create({ - string: "hello" - }) - const reflection = getMembers(node) - expect(reflection.properties.string).toBe(types.string) - expect(reflection.properties.optional).toMatchObject(types.optional(types.boolean, false)) -}) -test("reflection - members chained", () => { - const ChainedModel = types - .model({ - isPerson: false - }) - .actions((self) => { - return { - actionName() { - return 1 - } - } - }) - .actions((self) => { - return { - anotherAction() { - return 1 - } - } - }) - .views((self) => ({ - get viewName() { - return 1 - } - })) - .views((self) => ({ - anotherView(prop: string) { - return 1 - } - })) - const node = ChainedModel.create() - const reflection = getMembers(node) - const keys = Object.keys(reflection.properties || {}) - expect(keys.includes("isPerson")).toBe(true) - expect(reflection.actions.includes("actionName")).toBe(true) - expect(reflection.actions.includes("anotherAction")).toBe(true) - expect(reflection.views.includes("viewName")).toBe(true) - expect(reflection.views.includes("anotherView")).toBe(true) -}) -test("reflection - conditionals respected", () => { - let swap = true - const ConditionalModel = types - .model({ - isPerson: false - }) - .actions((self) => ({ - actionName0() { - return 1 - } - })) - .actions((self): { actionName1(): number } | { actionName2(): number } => { - if (swap) { - return { - actionName1() { - return 1 - } - } - } else { - return { - actionName2() { - return 1 - } - } - } - }) - .views((self) => { - if (swap) { - return { - get view1() { - return 1 - } - } - } else { - return { - get view2() { - return 1 - } - } - } - }) - // swap true - const node = ConditionalModel.create() - const reflection = getMembers(node) - expect(reflection.actions.includes("actionName0")).toBe(true) - expect(reflection.actions.includes("actionName1")).toBe(true) - expect(reflection.actions.includes("actionName2")).toBe(false) - expect(reflection.views.includes("view1")).toBe(true) - expect(reflection.views.includes("view2")).toBe(false) - swap = false - const node2 = ConditionalModel.create() - const reflection2 = getMembers(node2) - expect(reflection.actions.includes("actionName0")).toBe(true) - expect(reflection2.actions.includes("actionName1")).toBe(false) - expect(reflection2.actions.includes("actionName2")).toBe(true) - expect(reflection2.views.includes("view1")).toBe(false) - expect(reflection2.views.includes("view2")).toBe(true) -}) diff --git a/packages/mobx-state-tree/__tests__/core/snapshotProcessor.test.ts b/packages/mobx-state-tree/__tests__/core/snapshotProcessor.test.ts deleted file mode 100644 index 2d41c11ff..000000000 --- a/packages/mobx-state-tree/__tests__/core/snapshotProcessor.test.ts +++ /dev/null @@ -1,808 +0,0 @@ -import { - types, - getSnapshot, - unprotect, - cast, - detach, - clone, - SnapshotIn, - getNodeId -} from "../../src" - -describe("snapshotProcessor", () => { - describe("over a model type", () => { - const M = types.model({ - x: types.string - }) - - test("no processors", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, {}) - }) - const model = Model.create({ m: { x: "hi" } }) - unprotect(model) - expect(model.m.x).toBe("hi") - expect(getSnapshot(model).m.x).toBe("hi") - // reconciliation - model.m = { x: "ho" } - expect(model.m.x).toBe("ho") - expect(getSnapshot(model).m.x).toBe("ho") - }) - - test("pre processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: { x: number }) { - return { - ...sn, - x: String(sn.x) - } - } - }) - }) - const model = Model.create({ m: { x: 5 } }) - unprotect(model) - expect(model.m.x).toBe("5") - expect(getSnapshot(model).m.x).toBe("5") - // reconciliation - model.m = cast({ x: 6 }) - expect(model.m.x).toBe("6") - expect(getSnapshot(model).m.x).toBe("6") - }) - - test("post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - postProcessor(sn): { x: number } { - return { - ...sn, - x: Number(sn.x) - } - } - }) - }) - const model = Model.create({ - m: { x: "5" } - }) - unprotect(model) - expect(model.m.x).toBe("5") - expect(getSnapshot(model).m.x).toBe(5) - // reconciliation - model.m = cast({ x: "6" }) - expect(model.m.x).toBe("6") - expect(getSnapshot(model).m.x).toBe(6) - }) - - test("pre and post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: { x: number }) { - return { - ...sn, - x: String(sn.x) - } - }, - postProcessor(sn): { x: number } { - return { - ...sn, - x: Number(sn.x) - } - } - }) - }) - const model = Model.create({ - m: { x: 5 } - }) - unprotect(model) - expect(model.m.x).toBe("5") - expect(getSnapshot(model).m.x).toBe(5) - // reconciliation - model.m = cast({ x: 6 }) - expect(model.m.x).toBe("6") - expect(getSnapshot(model).m.x).toBe(6) - // cloning - expect(getSnapshot(clone(model.m)).x).toBe(6) - }) - }) - - describe("over a literal type", () => { - const M = types.string - - test("no processors", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, {}) - }) - const model = Model.create({ m: "hi" }) - unprotect(model) - expect(model.m).toBe("hi") - expect(getSnapshot(model).m).toBe("hi") - // reconciliation - model.m = "ho" - expect(model.m).toBe("ho") - expect(getSnapshot(model).m).toBe("ho") - }) - - test("pre processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: number) { - return String(sn) - } - }) - }) - const model = Model.create({ m: 5 }) - unprotect(model) - expect(model.m).toBe("5") - expect(getSnapshot(model).m).toBe("5") - // reconciliation - model.m = 6 as any - expect(model.m).toBe("6") - expect(getSnapshot(model).m).toBe("6") - }) - - test("post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - postProcessor(sn): number { - return Number(sn) - } - }) - }) - const model = Model.create({ - m: "5" - }) - unprotect(model) - expect(model.m).toBe("5") - expect(getSnapshot(model).m).toBe(5) - // reconciliation - model.m = "6" - expect(model.m).toBe("6") - expect(getSnapshot(model).m).toBe(6) - }) - - test("pre and post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: number) { - return String(sn) - }, - postProcessor(sn): number { - return Number(sn) - } - }) - }) - const model = Model.create({ - m: 5 - }) - unprotect(model) - expect(model.m).toBe("5") - expect(getSnapshot(model).m).toBe(5) - // reconciliation - model.m = "6" - expect(model.m).toBe("6") - expect(getSnapshot(model).m).toBe(6) - // cloning - expect(getSnapshot(clone(model)).m).toBe(6) - }) - }) - - describe("over an array type", () => { - const M = types.array(types.string) - - test("no processors", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, {}) - }) - const model = Model.create({ m: ["hi"] }) - unprotect(model) - expect(model.m[0]).toBe("hi") - expect(getSnapshot(model).m[0]).toBe("hi") - // reconciliation - model.m = cast(["ho"]) - expect(model.m[0]).toBe("ho") - expect(getSnapshot(model).m[0]).toBe("ho") - }) - - test("pre processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: number[]) { - return sn.map((n) => String(n)) - } - }) - }) - const model = Model.create({ m: [5] }) - unprotect(model) - expect(model.m[0]).toBe("5") - expect(getSnapshot(model).m[0]).toBe("5") - // reconciliation - model.m = cast([6]) - expect(model.m[0]).toBe("6") - expect(getSnapshot(model).m[0]).toBe("6") - }) - - test("post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - postProcessor(sn): number[] { - return sn.map((n) => Number(n)) - } - }) - }) - const model = Model.create({ - m: ["5"] - }) - unprotect(model) - expect(model.m[0]).toBe("5") - expect(getSnapshot(model).m[0]).toBe(5) - // reconciliation - model.m = cast(["6"]) - expect(model.m[0]).toBe("6") - expect(getSnapshot(model).m[0]).toBe(6) - }) - - test("pre and post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: number[]) { - return sn.map((n) => String(n)) - }, - postProcessor(sn): number[] { - return sn.map((n) => Number(n)) - } - }) - }) - const model = Model.create({ - m: [5] - }) - unprotect(model) - expect(model.m[0]).toBe("5") - expect(getSnapshot(model).m[0]).toBe(5) - // reconciliation - model.m = cast([6]) - expect(model.m[0]).toBe("6") - expect(getSnapshot(model).m[0]).toBe(6) - // cloning - expect(getSnapshot(clone(model.m))[0]).toBe(6) - }) - }) - - describe("over a map type", () => { - const M = types.map(types.string) - - test("no processors", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, {}) - }) - const model = Model.create({ m: { x: "hi" } }) - unprotect(model) - expect(model.m.get("x")).toBe("hi") - expect(getSnapshot(model).m.x).toBe("hi") - // reconciliation - model.m.set("x", "ho") - expect(model.m.get("x")).toBe("ho") - expect(getSnapshot(model).m.x).toBe("ho") - }) - - test("pre processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: { x: number }) { - return { - ...sn, - x: String(sn.x) - } - } - }) - }) - const model = Model.create({ m: { x: 5 } }) - unprotect(model) - expect(model.m.get("x")).toBe("5") - expect(getSnapshot(model).m.x).toBe("5") - // reconciliation - model.m = cast({ x: 6 }) - expect(model.m.get("x")).toBe("6") - expect(getSnapshot(model).m.x).toBe("6") - }) - - test("post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - postProcessor(sn): { x: number } { - return { - ...sn, - x: Number(sn.x) - } - } - }) - }) - const model = Model.create({ - m: { x: "5" } - }) - unprotect(model) - expect(model.m.get("x")).toBe("5") - expect(getSnapshot(model).m.x).toBe(5) - // reconciliation - model.m = cast({ x: "6" }) - expect(model.m.get("x")).toBe("6") - expect(getSnapshot(model).m.x).toBe(6) - }) - - test("pre and post processor", () => { - const Model = types.model({ - m: types.snapshotProcessor(M, { - preProcessor(sn: { x: number }) { - return { - ...sn, - x: String(sn.x) - } - }, - postProcessor(sn): { x: number } { - return { - ...sn, - x: Number(sn.x) - } - } - }) - }) - const model = Model.create({ - m: { x: 5 } - }) - unprotect(model) - expect(model.m.get("x")).toBe("5") - expect(getSnapshot(model).m.x).toBe(5) - // reconciliation - model.m = cast({ x: 6 }) - expect(model.m.get("x")).toBe("6") - expect(getSnapshot(model).m.x).toBe(6) - // cloning - expect(getSnapshot(clone(model.m)).x).toBe(6) - }) - }) - - test("chained transforms", () => { - const TL = types.snapshotProcessor(types.string, { - preProcessor(sn: string) { - return sn.trimLeft() - }, - postProcessor(sn): string { - return "_" + sn - } - }) - const TB = types.snapshotProcessor(TL, { - preProcessor(sn: string) { - return sn.trimRight() - }, - postProcessor(sn): string { - return sn + "_" - } - }) - const M = types.model({ - name: TB - }) - - const t = TB.create(" hello ") - expect(t).toBe("hello") - - const m = M.create({ - name: " hello " - }) - expect(m.name).toBe("hello") - expect(getSnapshot(m).name).toBe("_hello_") - }) - - describe("moving nodes around with a pre-processor", () => { - const Task = types.model("Task", { x: types.number }) - const Store = types.model({ - a: types.array( - types.snapshotProcessor( - Task, - { - preProcessor(sn: { x: string }) { - return { - x: Number(sn.x) - } - } - }, - "PTask" - ) - ), - b: types.array(Task) - }) - - test("moving from a to b", () => { - const s = Store.create({ - a: [{ x: "1" }] - }) - unprotect(s) - const n = s.a[0] - detach(n) - expect(s.a.length).toBe(0) - expect(getSnapshot(n)).toEqual({ x: 1 }) - - s.b.push(n) - expect(s.b.length).toBe(1) - expect(getSnapshot(s.b)).toEqual([{ x: 1 }]) - }) - - test("moving from b to a", () => { - const s = Store.create({ - b: [{ x: 1 }] - }) - unprotect(s) - const n = s.b[0] - detach(n) - expect(s.b.length).toBe(0) - expect(getSnapshot(n)).toEqual({ x: 1 }) - - s.a.push(n) - expect(s.a.length).toBe(1) - expect(getSnapshot(s.a)).toEqual([{ x: 1 }]) - }) - }) - - describe("moving nodes around with a post-processor", () => { - const Task = types.model({ x: types.number }) - const Store = types.model({ - a: types.array( - types.snapshotProcessor(Task, { - postProcessor(sn): { x: string } { - return { - x: String(sn.x) - } - } - }) - ), - b: types.array(Task) - }) - - test("moving from a to b", () => { - const s = Store.create({ - a: [{ x: 1 }] - }) - unprotect(s) - const n = s.a[0] - detach(n) - expect(s.a.length).toBe(0) - expect(getSnapshot(n)).toEqual({ x: "1" }) - - s.b.push(n) - expect(s.b.length).toBe(1) - expect(getSnapshot(s.b)).toEqual([{ x: "1" }]) - }) - - test("moving from b to a", () => { - const s = Store.create({ - b: [{ x: 1 }] - }) - unprotect(s) - const n = s.b[0] - detach(n) - expect(s.b.length).toBe(0) - expect(getSnapshot(n)).toEqual({ x: 1 }) - - s.a.push(n) - expect(s.a.length).toBe(1) - expect(getSnapshot(s.a)).toEqual([{ x: "1" }]) - }) - }) - - describe("assigning instances works", () => { - const Todo = types.model("Todo", { - id: types.identifier - }) - - const TodoWithProcessor = types.snapshotProcessor(Todo, { - preProcessor(snapshot: { id: string }) { - return snapshot - } - }) - - const Store = types - .model("TodoStore", { - todos: types.map(TodoWithProcessor), - instance: types.optional(TodoWithProcessor, { id: "new" }) - }) - .actions((self) => ({ - addTodo(todo: { id: string }) { - self.todos.put(todo) - }, - setInstance(next: { id: string }) { - self.instance = next - } - })) - - test("using instances in maps work", () => { - const store = Store.create() - const todo = TodoWithProcessor.create({ id: "map" }) - - store.addTodo(todo) - - expect(store.todos.size).toBe(1) - expect(getSnapshot(store.todos)).toEqual({ map: { id: "map" } }) - }) - - test("using instances as values works", () => { - const store = Store.create() - const todo = TodoWithProcessor.create({ id: "map" }) - - store.setInstance(todo) - - expect(store.instance).toBe(todo) - }) - - test("using the non processed type in place of the processed one works", () => { - const store = Store.create() - const todo = Todo.create({ id: "map" }) - - store.setInstance(todo) - - expect(store.instance).toBe(todo) - }) - - test("using the processed type in place of the non processed one works", () => { - const store = types - .model("Store", { instance: Todo }) - .actions((self) => ({ - setInstance(next: { id: string }) { - self.instance = next - } - })) - .create({ instance: { id: "new" } }) - - const todo = TodoWithProcessor.create({ id: "map" }) - - store.setInstance(todo) - - expect(store.instance).toBe(todo) - }) - }) - - test("cached initial snapshots are ok", () => { - const M2 = types.snapshotProcessor(types.model({ x: types.number }), { - preProcessor(sn: { x: number }) { - return { ...sn, x: 0 } - } - }) - const M1 = types.model({ m2: M2 }) - const M = types.model({ m1: M1 }) - - const m = M.create({ m1: { m2: { x: 10 } } }) - expect(getSnapshot(m)).toEqual({ - m1: { m2: { x: 0 } } - }) - }) - - test("works with IType.is", () => { - const Model = types.model({ x: types.number }) - const model = Model.create({ x: 1 }) - expect(Model.is(model)).toBe(true) - expect(Model.is({ x: 1 })).toBe(true) - - const ProcessedModel = types.snapshotProcessor(Model, { - preProcessor(sn: { y: number }) { - const copy = { ...sn, x: sn.y } - // @ts-ignore - delete copy.y - return copy - }, - postProcessor(sn: { x: number }) { - const copy = { ...sn, y: sn.x } - // @ts-ignore - delete copy.x - return copy - } - }) - - const processedModel = ProcessedModel.create({ y: 1 }) - expect(ProcessedModel.is(processedModel)).toBe(true) - expect(ProcessedModel.is({ y: 1 })).toBe(true) - expect(ProcessedModel.is(Model)).toBe(false) - }) - - describe("1776 - reconciliation in an array", () => { - test("model with transformed property is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier, - x: types.number - }), - { - preProcessor(sn: { id: string; y: number }) { - if ("x" in sn) { - // Ensure snapshot don't run through preprocessor twice - throw new Error("sn has already been preprocessed") - } - return { id: sn.id, x: sn.y } - } - } - ) - const Store = types.model({ items: types.array(SP) }).actions((self) => ({ - setItems(items: SnapshotIn[]) { - self.items = cast(items) - } - })) - const store = Store.create({ items: [{ id: "1", y: 0 }] }) - const oldNodeId = getNodeId(store.items[0]) - store.setItems([{ id: "1", y: 1 }]) - expect(getNodeId(store.items[0])).toBe(oldNodeId) - }) - - test("model with transformed identifier attribute is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier - }), - { - preProcessor(sn: { foo: string }) { - return { id: sn.foo } - } - } - ) - const Store = types.model({ items: types.array(SP) }).actions((self) => ({ - setItems(items: SnapshotIn[]) { - self.items = cast(items) - } - })) - const store = Store.create({ items: [{ foo: "1" }] }) - const oldNodeId = getNodeId(store.items[0]) - store.setItems([{ foo: "1" }]) - expect(getNodeId(store.items[0])).toBe(oldNodeId) - }) - }) - - describe("single node reconcilication", () => { - test("model with transformed property is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier, - x: types.number - }), - { - preProcessor(sn: { id: string; y: number }) { - if ("x" in sn) { - // Ensure snapshot don't run through preprocessor twice - throw new Error("sn has already been preprocessed") - } - return { id: sn.id, x: sn.y } - } - } - ) - const Store = types.model({ item: SP }).actions((self) => ({ - setItem(item: SnapshotIn) { - self.item = cast(item) - } - })) - const store = Store.create({ item: { id: "1", y: 0 } }) - const oldNodeId = getNodeId(store.item) - store.setItem({ id: "1", y: 1 }) - expect(getNodeId(store.item)).toBe(oldNodeId) - expect(store.item.x).toBe(1) - }) - - test("model with transformed identifier property is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier - }), - { - preProcessor(sn: { foo: string }) { - return { id: sn.foo } - } - } - ) - const Store = types.model({ item: SP }).actions((self) => ({ - setItem(item: SnapshotIn) { - self.item = cast(item) - } - })) - const store = Store.create({ item: { foo: "1" } }) - const oldNodeId = getNodeId(store.item) - store.setItem({ foo: "1" }) - expect(getNodeId(store.item)).toBe(oldNodeId) - expect(store.item.id).toBe("1") - }) - - test("1791 - model wrapped with maybe is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier, - x: types.number - }), - { - preProcessor(sn: { id: string; y: number }) { - return { id: sn.id, x: sn.y } - } - } - ) - const Store = types.model({ item: types.maybe(SP) }).actions((self) => ({ - setItem(item: SnapshotIn) { - self.item = cast(item) - } - })) - const store = Store.create({ item: { id: "1", y: 0 } }) - const oldNodeId = getNodeId(store.item!) - store.setItem({ id: "1", y: 1 }) - expect(getNodeId(store.item!)).toBe(oldNodeId) - expect(store.item?.x).toBe(1) - }) - - test("model wrapped with optional is reconciled", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier, - x: types.number - }), - { - preProcessor(sn: { id: string; y: number }) { - return { id: sn.id, x: sn.y } - } - } - ) - const Store = types - .model({ item: types.optional(SP, { id: "1", y: 0 }) }) - .actions((self) => ({ - setItem(item?: SnapshotIn) { - self.item = cast(item) - } - })) - const store = Store.create() - const oldNodeId = getNodeId(store.item!) - expect(store.item?.x).toBe(0) - store.setItem({ id: "1", y: 1 }) - expect(getNodeId(store.item!)).toBe(oldNodeId) - expect(store.item?.x).toBe(1) - store.setItem(undefined) - expect(getNodeId(store.item!)).toBe(oldNodeId) - expect(store.item?.x).toBe(0) - }) - }) - - test("1777 - preProcessor wrapped in maybe accepts undefined", () => { - const SP = types.snapshotProcessor( - types.model({ - id: types.identifier, - x: types.number - }), - { - preProcessor(sn: { id: string; y: number }) { - return { id: sn.id, x: sn.y } - } - } - ) - const Store = types.model({ item: types.maybe(SP) }).actions((self) => ({ - setItem(item?: SnapshotIn) { - self.item = cast(item) - } - })) - const store = Store.create() - expect(store.item).toBeUndefined() - store.setItem({ id: "1", y: 1 }) - expect(store.item?.x).toBe(1) - store.setItem(undefined) - expect(store.item).toBeUndefined() - }) - - test("1849 - Wrapped unions don't cause infinite recursion", () => { - const Store = types - .model({ - prop: types.optional( - types.snapshotProcessor( - types.union(types.literal("a"), types.literal("b")), - {} - ), - "a" - ) - }) - .actions((self) => ({ - setProp(prop: typeof self.prop) { - self.prop = prop - } - })) - - const store = Store.create() - expect(store.prop).toBe("a") - expect(() => store.setProp("b")).not.toThrow() - expect(store.prop).toBe("b") - }) -}) diff --git a/packages/mobx-state-tree/__tests__/core/this.test.ts b/packages/mobx-state-tree/__tests__/core/this.test.ts deleted file mode 100644 index 873fc9d51..000000000 --- a/packages/mobx-state-tree/__tests__/core/this.test.ts +++ /dev/null @@ -1,94 +0,0 @@ -import { types } from "../../src" -import { isObservableProp, isComputedProp } from "mobx" - -// MWE: disabled test, `this` isn't supposed to work, and afaik nowhere advertised -test.skip("this support", () => { - const M = types - .model({ x: 5 }) - .views((self) => ({ - get x2() { - return self.x * 2 - }, - get x4() { - return this.x2 * 2 - }, - boundTo() { - return this - }, - innerBoundTo() { - return () => this - }, - isThisObservable() { - return ( - isObservableProp(this, "x2") && - isObservableProp(this, "x4") && - isObservableProp(this, "localState") && - isComputedProp(this, "x2") - ) - } - })) - .volatile((self) => ({ - localState: 3, - getLocalState() { - return this.localState - }, - getLocalState2() { - return this.getLocalState() * 2 - } - })) - - .actions((self) => { - return { - xBy(by: number) { - return self.x * by - }, - setX(x: number) { - self.x = x - }, - setThisX(x: number) { - ;(this as any).x = x // this should not affect self.x - }, - setXBy(x: number) { - this.setX(this.xBy(x)) - }, - setLocalState(x: number) { - self.localState = x - } - } - }) - - const mi = M.create() - - expect(mi.isThisObservable()).toBe(true) - - expect(mi.boundTo()).toBe(mi) - expect(mi.innerBoundTo()()).toBe(mi) - - expect(mi.x).toBe(5) - - mi.setX(6) - expect(mi.x).toBe(6) - - mi.setXBy(2) - expect(mi.x).toBe(12) - expect(mi.x2).toBe(12 * 2) - expect(mi.x4).toBe(12 * 4) - expect(mi.xBy(2)).toBe(24) - - expect(mi.localState).toBe(3) - expect(mi.getLocalState()).toBe(3) - expect(mi.getLocalState2()).toBe(3 * 2) - - mi.setLocalState(6) - expect(mi.localState).toBe(6) - expect(mi.getLocalState()).toBe(6) - expect(mi.getLocalState2()).toBe(6 * 2) - - mi.setLocalState(7) - expect(mi.localState).toBe(7) - - // make sure attempts to modify this (as long as it is not an action) doesn't affect self - const oldX = mi.x - mi.setThisX(oldX + 1) - expect(mi.x).toBe(oldX) -}) diff --git a/packages/mobx-state-tree/__tests__/core/type-system.test.ts b/packages/mobx-state-tree/__tests__/core/type-system.test.ts deleted file mode 100644 index f02181a78..000000000 --- a/packages/mobx-state-tree/__tests__/core/type-system.test.ts +++ /dev/null @@ -1,1156 +0,0 @@ -import { assert, _ } from "spec.ts" - -import { - types, - getSnapshot, - unprotect, - getRoot, - getParent, - SnapshotOrInstance, - cast, - SnapshotIn, - Instance, - castToSnapshot, - IType, - isStateTreeNode, - isFrozenType, - TypeOfValue, - IAnyType, - ModelPrimitive, - ModelPropertiesDeclaration, - SnapshotOut -} from "../../src" -import { $nonEmptyObject } from "../../src/internal" - -const createTestFactories = () => { - const Box = types.model({ - width: 0, - height: 0 - }) - const Square = types.model({ - width: 0, - height: 0 - }) - const Cube = types.model({ - width: 0, - height: 0, - depth: 0 - }) - return { Box, Square, Cube } -} -test("it should recognize a valid snapshot", () => { - const { Box } = createTestFactories() - expect(Box.is({ width: 1, height: 2 })).toEqual(true) - expect(Box.is({ width: 1, height: 2, depth: 3 })).toEqual(true) -}) -test("it should recognize an invalid snapshot", () => { - const { Box } = createTestFactories() - expect(Box.is({ width: "1", height: "2" })).toEqual(false) -}) -test("it should check valid nodes as well", () => { - const { Box } = createTestFactories() - const doc = Box.create() - expect(Box.is(doc)).toEqual(true) -}) -test("it should check invalid nodes as well", () => { - const { Box } = createTestFactories() - const doc = Box.create() - expect( - types - .model({ - anotherAttr: types.number - }) - .is(doc) - ).toEqual(false) -}) -test("it should do typescript type inference correctly", () => { - const A = types - .model({ - x: types.number, - y: types.maybeNull(types.string) - }) - .views((self) => ({ - get z(): string { - return "hi" - } - })) - .actions((self) => { - function method() { - const x: string = self.z + self.x + self.y - anotherMethod(x) - } - function anotherMethod(x: string) {} - return { - method, - anotherMethod - } - }) - // factory is invokable - const a = A.create({ x: 2, y: "7" }) - unprotect(a) - // property can be used as proper type - const z: number = a.x - // property can be assigned to crrectly - a.x = 7 - // wrong type cannot be assigned - // MANUAL TEST: not ok: a.x = "stuff" - // sub factories work - const B = types.model({ - sub: types.maybe(A) - }) - const b = B.create() - unprotect(b) - // sub fields can be reassigned - b.sub = A.create({ - // MANUAL TEST not ok: z: 4, - x: 3 - }) - // sub fields have proper type - b.sub.x = 4 - const d: string | null = b.sub.y - a.y = null - const zz: string = a.z - // Manual test not assignable: - // a.z = "test" - b.sub.method() - expect(true).toBe(true) // supress no asserts warning - // snapshots are of the proper type - const snapshot = getSnapshot(a) - const sx: number = snapshot.x - const sy: string | null = snapshot.y - expect(sx).toBe(7) - expect(sy).toBe(null) -}) -test("#66 - it should accept superfluous fields", () => { - const Item = types.model({ - id: types.number, - name: types.string - }) - expect(Item.is({})).toBe(false) - expect(Item.is({ id: 3 })).toBe(false) - expect(Item.is({ id: 3, name: "" })).toBe(true) - expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) - const a = Item.create({ id: 3, name: "", description: "bla" } as any) - expect((a as any).description).toBe(undefined) -}) -test("#66 - it should not require defaulted fields", () => { - const Item = types.model({ - id: types.number, - name: types.optional(types.string, "boo") - }) - expect(Item.is({})).toBe(false) - expect(Item.is({ id: 3 })).toBe(true) - expect(Item.is({ id: 3, name: "" })).toBe(true) - expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) - const a = Item.create({ id: 3, description: "bla" } as any) - expect((a as any).description).toBe(undefined) - expect(a.name).toBe("boo") -}) -test("#66 - it should be possible to omit defaulted fields", () => { - const Item = types.model({ - id: types.number, - name: "boo" - }) - expect(Item.is({})).toBe(false) - expect(Item.is({ id: 3 })).toBe(true) - expect(Item.is({ id: 3, name: "" })).toBe(true) - expect(Item.is({ id: 3, name: "", description: "" })).toBe(true) - const a = Item.create({ id: 3, description: "bla" } as any) - expect((a as any).description).toBe(undefined) - expect(a.name).toBe("boo") -}) -test("#66 - it should pick the correct type of defaulted fields", () => { - const Item = types.model({ - id: types.number, - name: "boo" - }) - const a = Item.create({ id: 3 }) - unprotect(a) - expect(a.name).toBe("boo") - if (process.env.NODE_ENV !== "production") { - expect(() => ((a as any).name = 3)).toThrowError( - `[mobx-state-tree] Error while converting \`3\` to \`string\`:\n\n value \`3\` is not assignable to type: \`string\` (Value is not a string).` - ) - } -}) -test("cannot create factories with null values", () => { - expect(() => - types.model({ - x: null - } as any) - ).toThrow() -}) -test("can create factories with maybe primitives", () => { - const F = types.model({ - x: types.maybeNull(types.string) - }) - expect(F.is(undefined)).toBe(false) - expect(F.is({})).toBe(true) - expect(F.is({ x: null })).toBe(true) - expect(F.is({ x: "test" })).toBe(true) - expect(F.is({ x: 3 })).toBe(false) - expect(F.create().x).toBe(null) - expect(F.create({ x: undefined }).x).toBe(null) - expect(F.create({ x: "" }).x).toBe("") - expect(F.create({ x: "3" }).x).toBe("3") -}) -test("it is possible to refer to a type", () => { - const Todo = types - .model({ - title: types.string - }) - .actions((self) => { - function setTitle(v: string) {} - return { - setTitle - } - }) - function x(): typeof Todo.Type { - return Todo.create({ title: "test" }) - } - const z = x() - unprotect(z) - z.setTitle("bla") - z.title = "bla" - // z.title = 3 // Test manual: should give compile error - expect(true).toBe(true) // supress no asserts warning -}) -test(".Type should not be callable", () => { - const Todo = types - .model({ - title: types.string - }) - .actions((self) => { - function setTitle(v: string) {} - return { - setTitle - } - }) - expect(() => Todo.Type).toThrow() -}) -test(".SnapshotType should not be callable", () => { - const Todo = types - .model({ - title: types.string - }) - .actions((self) => { - function setTitle(v: string) {} - return { - setTitle - } - }) - expect(() => Todo.SnapshotType).toThrow() -}) -test("types instances with compatible snapshots should not be interchangeable", () => { - const A = types.model("A", {}).actions((self) => { - function doA() {} - return { - doA - } - }) - const B = types.model("B", {}).actions((self) => { - function doB() {} - return { - doB - } - }) - const C = types.model("C", { - x: types.maybe(A) - }) - expect(A.is({})).toBe(true) - expect(A.is(B.create())).toBe(false) // if thies yielded true, then `B.create().doA()` should work! - expect(A.is(getSnapshot(B.create()))).toBe(true) - const c = C.create() - unprotect(c) - expect(() => { - c.x = undefined - }).not.toThrow() - expect(() => { - c.x = cast({}) - }).not.toThrow() - expect(() => { - c.x = A.create() - }).not.toThrow() - expect(() => { - ;(c as any).x = B.create() - }).toThrow() -}) -test("it handles complex types correctly", () => { - const Todo = types - .model({ - title: types.string - }) - .actions((self) => { - function setTitle(v: string) {} - return { - setTitle - } - }) - const Store = types - .model({ - todos: types.map(Todo) - }) - .views((self) => { - function getActualAmount() { - return self.todos.size - } - return { - get amount() { - return getActualAmount() - }, - getAmount(): number { - return self.todos.size + getActualAmount() - } - } - }) - .actions((self) => { - function setAmount() { - const x: number = self.todos.size + self.amount + self.getAmount() - } - return { - setAmount - } - }) - expect(true).toBe(true) // supress no asserts warning -}) -if (process.env.NODE_ENV !== "production") { - test("it should provide detailed reasons why the value is not appicable", () => { - const Todo = types - .model({ - title: types.string - }) - .actions((self) => { - function setTitle(v: string) {} - return { - setTitle - } - }) - const Store = types - .model({ - todos: types.map(Todo) - }) - .views((self) => ({ - get amount() { - return self.todos.size - }, - getAmount(): number { - return self.todos.size + self.todos.size - } - })) - .actions((self) => { - function setAmount() { - const x: number = self.todos.size + self.amount + self.getAmount() - } - return { - setAmount - } - }) - expect(() => - Store.create({ - todos: { "1": { title: true, setTitle: "hello" } }, - amount: 1, - getAmount: "hello" - } as any) - ).toThrowError( - // MWE: TODO: Ideally (like in MST =< 0.9): - // at path "/todos/1/setTitle" value \`"hello"\` is not assignable (Action properties should not be provided in the snapshot). - // at path "/amount" value \`1\` is not assignable (Computed properties should not be provided in the snapshot). - // at path "/getAmount" value \`"hello"\` is not assignable (View properties should not be provided in the snapshot).` - `[mobx-state-tree] Error while converting \`{"todos":{"1":{"title":true,"setTitle":"hello"}},"amount":1,"getAmount":"hello"}\` to \`AnonymousModel\`: - - at path "/todos/1/title" value \`true\` is not assignable to type: \`string\` (Value is not a string).` - ) - }) -} -test("it should type compose correctly", () => { - const Car = types - .model({ - wheels: 3 - }) - .actions((self) => { - let connection = null as any as Promise - function drive() {} - function afterCreate() { - connection = Promise.resolve(true) - } - return { - drive, - afterCreate - } - }) - const Logger = types - .model({ - logNode: "test" - }) - .actions((self) => { - function log(msg: string) {} - return { - log - } - }) - const LoggableCar = types.compose(Car, Logger) - const x = LoggableCar.create({ wheels: 3, logNode: "test" /* compile error: x: 7 */ }) - // x.test() // compile error - x.drive() - x.log("z") -}) -test("it should extend {pre,post}ProcessSnapshot on compose", () => { - const CompositionTracker = types - .model({ - composedOf: types.array(types.string), - composedWith: types.array(types.string) - }) - .preProcessSnapshot((snapshot) => ({ - ...snapshot, - composedOf: (snapshot.composedOf || []).concat("CompositionTracker") - })) - .postProcessSnapshot((snapshot) => ({ - ...snapshot, - composedWith: (snapshot.composedWith || []).concat("WagonTracker") - })) - const Car = types - .model({}) - .preProcessSnapshot((snapshot) => ({ - ...snapshot, - composedOf: ((snapshot as any).composedOf || []).concat("Car") - })) - .postProcessSnapshot((snapshot) => ({ - ...snapshot, - composedWith: ((snapshot as any).composedWith || []).concat("Wagon") - })) - const Logger = types - .model({}) - .preProcessSnapshot((snapshot) => ({ - ...snapshot, - composedOf: ((snapshot as any).composedOf || []).concat("CarLogger") - })) - .postProcessSnapshot((snapshot) => ({ - ...snapshot, - composedWith: ((snapshot as any).composedWith || []).concat("WagonLogger") - })) - - const LoggableCar = types.compose(CompositionTracker, Car, Logger).props({ - composedOf: types.array(types.string), - composedWith: types.array(types.string) - }) - const x = LoggableCar.create({}) - expect(x.composedOf).toContain("CompositionTracker") - expect(x.composedOf).toContain("Car") - expect(x.composedOf).toContain("CarLogger") - expect(x.composedOf).toEqual(["CompositionTracker", "Car", "CarLogger"]) - expect(getSnapshot(x).composedWith).toContain("WagonTracker") - expect(getSnapshot(x).composedWith).toContain("Wagon") - expect(getSnapshot(x).composedWith).toContain("WagonLogger") - expect(getSnapshot(x).composedWith).toEqual(["WagonTracker", "Wagon", "WagonLogger"]) -}) -test("it should extend types correctly", () => { - const Car = types - .model({ - wheels: 3 - }) - .actions((self) => { - function drive() {} - return { - drive - } - }) - const Logger = types - .model("Logger") - .props({ - logNode: "test" - }) - .actions((self) => { - let connection: Promise - return { - log(msg: string) {}, - afterCreate() { - connection = Promise.resolve(true) - } - } - }) - const LoggableCar = types.compose("LoggableCar", Car, Logger) - const x = LoggableCar.create({ wheels: 3, logNode: "test" /* compile error: x: 7 */ }) - // x.test() // compile error - x.drive() - x.log("z") -}) -test("self referring views", () => { - const Car = types.model({ x: 3 }).views((self) => { - const views = { - get tripple() { - return self.x + views.double - }, - get double() { - return self.x * 2 - } - } - return views - }) - expect(Car.create().tripple).toBe(9) -}) - -test("#922", () => { - expect(() => { - const Stateable = types.model("Statable", { - state: types.optional( - types.enumeration("state", ["initalized", "pending", "done", "error"]), - "initalized" - ) - }) - - const Client = types.model("Client", { - id: types.identifierNumber, - name: types.string - }) - - const UserClientList = types.compose( - "UserClientList", - Stateable, - types.model({ - items: types.array(Client), - month: types.optional(types.Date, () => { - return new Date() - }) - }) - ) - - const NonExtendedUserClientList = types.model("NonExtendedUserClientList", { - items: types.array(Client), - month: types.optional(types.Date, () => { - return new Date() - }), - state: types.optional( - types.enumeration("state", ["initalized", "pending", "done", "error"]), - "initalized" - ) - }) - - const User = types.model("User", { - name: types.string, - clients: types.optional(UserClientList, () => UserClientList.create({})) - }) - - const NonExtendedUser = types.model("User", { - name: types.string, - clients: types.optional(NonExtendedUserClientList, () => - NonExtendedUserClientList.create({}) - ) - }) - - const you = NonExtendedUser.create({ - name: "you" - }) - - const me = User.create({ - name: "me" - }) - }).not.toThrow() -}) - -test("#922 - 2", () => { - expect(() => { - types.optional(types.enumeration("state", ["init", "pending", "done", "error"]), "init") - }).not.toThrow() -}) - -test("#932", () => { - interface MyInterface { - test: string - } - - const MyModel = types.model("MyModel", { - myField: types.array(types.frozen()) - }) - - const x = MyModel.create({ myField: [{ test: "stuff" }] }) - const a: string = x.myField[0].test -}) - -test("932 - 2", () => { - type MyType = string - const ModelA = types.model("ModelA", { - myField: types.maybe(types.frozen()) - }) - const x = ModelA.create({}) - const y = x.myField // y is string | undefined - - const ModelA2 = types.model("ModelA", { - myField: types.frozen() - }) - const x2 = ModelA2.create({ - myField: "test" // mandatory - }) - const y2: string = x2.myField // string only -}) - -test("#923", () => { - const Foo = types.model("Foo", { - name: types.optional(types.string, "") - }) - - const Bar = types.model("Bar", { - foos: types.optional(types.array(Foo), []) - }) - - types.optional(types.map(Bar), {}) // Should have no compile error! -}) - -test("snapshot type of reference must be string | number", () => { - const M = types.model({ id: types.identifier, a: "bar" }) - const R = types.reference(M) - - const S = types.model({ realM: M, refM: R }) - const s = S.create({ - realM: { id: "5" }, - refM: "5" - }) - const sn: string | number = getSnapshot(s.refM) -}) - -test("#951", () => { - const C = types.model({ a: 123 }) - - // model as root - const ModelWithC = types.model({ c: C }) - const modelInstance = ModelWithC.create({ c: C.create() }) - - // getRoot - const modelRoot1 = getRoot(modelInstance.c) - const modelCR1: Instance = modelRoot1.c - const modelRoot2 = getRoot>(modelInstance.c) - const modelCR2: Instance = modelRoot2.c - - // getParent - const modelParent1 = getParent(modelInstance.c) - const modelCP1: Instance = modelParent1 - const modelParent2 = getParent>(modelInstance.c) - const modelCP2: Instance = modelParent2 - - // array as root - const ArrayOfC = types.array(C) - const arrayInstance = ArrayOfC.create([C.create()]) - - // getRoot - const arrayRoot1 = getRoot(arrayInstance[0]) - const arrayCR1: Instance = arrayRoot1[0] - - // getParent - const arrayParent1 = getParent(arrayInstance[0]) - const arrayCP1: Instance = arrayParent1 - - // map as root - const MapOfC = types.map(C) - const mapInstance = MapOfC.create({ a: C.create() }) - - // getRoot - const mapRoot1 = getRoot(mapInstance.get("a")!) - const mapC1: Instance = mapRoot1.get("a")! - - // getParent - const mapParent1 = getRoot(mapInstance.get("a")!) - const mapCP1: Instance = mapParent1 -}) - -test("cast and SnapshotOrInstance", () => { - const NumberArray = types.array(types.number) - const NumberMap = types.map(types.number) - const A = types - .model({ n: 123, n2: types.number, arr: NumberArray, map: NumberMap }) - .actions((self) => ({ - // for primitives (although not needed) - setN(nn: SnapshotOrInstance) { - self.n = cast(nn) - }, - setN2(nn: SnapshotOrInstance) { - self.n = cast(nn) - }, - setN3(nn: SnapshotOrInstance) { - self.n = cast(nn) - }, - setN4(nn: number) { - self.n = cast(nn) - }, - setN5() { - self.n = cast(5) - }, - - // for arrays - setArr(nn: SnapshotOrInstance) { - self.arr = cast(nn) - }, - setArr2(nn: SnapshotOrInstance) { - self.arr = cast(nn) - }, - setArr3(nn: SnapshotIn) { - self.arr = cast(nn) - }, - setArr31(nn: number[]) { - self.arr = cast(nn) - }, - setArr4() { - // it works even without specifying the target type, magic! - self.arr = cast([2, 3, 4]) - self.arr = cast(NumberArray.create([2, 3, 4])) - }, - - // for maps - setMap(nn: SnapshotOrInstance) { - self.map = cast(nn) - }, - setMap2(nn: SnapshotOrInstance) { - self.map = cast(nn) - }, - setMap3(nn: SnapshotIn) { - self.map = cast(nn) - }, - setMap31(nn: { [k: string]: number }) { - self.map = cast(nn) - }, - setMap4() { - // it works even without specifying the target type, magic! - self.map = cast({ a: 2, b: 3 }) - self.map = cast(NumberMap.create({ a: 2, b: 3 })) - } - })) - - const C = types - .model({ a: A, maybeA: types.maybe(A), maybeNullA: types.maybeNull(A) }) - .actions((self) => ({ - // for submodels, using typeof self.var - setA(na: SnapshotOrInstance) { - self.a = cast(na) - // we just want to check it compiles - if (0 !== 0) { - self.maybeA = cast(na) - self.maybeNullA = cast(na) - } - }, - // for submodels, using the type directly - setA2(na: SnapshotOrInstance) { - self.a = cast(na) - // we just want to check it compiles - if (0 !== 0) { - self.maybeA = cast(na) - self.maybeNullA = cast(na) - } - }, - setA3(na: SnapshotIn) { - self.a = cast(na) - // we just want to check it compiles - if (0 !== 0) { - self.maybeA = cast(na) - self.maybeNullA = cast(na) - } - }, - setA4(na: Instance) { - self.a = cast(na) - // we just want to check it compiles - if (0 !== 0) { - self.maybeA = cast(na) - self.maybeNullA = cast(na) - } - }, - setA5() { - // it works even without specifying the target type, magic! - self.a = cast({ n2: 5 }) - self.a = cast(A.create({ n2: 5 })) - // we just want to check it compiles - if (0 !== 0) { - self.maybeA = cast({ n2: 5 }) - self.maybeA = cast(A.create({ n2: 5 })) - self.maybeNullA = cast({ n2: 5 }) - self.maybeNullA = cast(A.create({ n2: 5 })) - } - } - })) - - const c = C.create({ a: { n2: 5 } }) - unprotect(c) - // all below works - c.setA({ n2: 5 }) - c.setA(A.create({ n2: 5 })) - c.setA2({ n2: 5 }) - c.setA2(A.create({ n2: 5 })) - c.setA3({ n2: 5 }) - // c.setA3(A.create({ n2: 5 })) // this one doesn't work (as expected, it wants the creation type) - // c.setA4({n2: 5}) // this one doesn't work (as expected, it wants the instance type) - c.setA4(A.create({ n2: 5 })) - c.setA5() - - c.a.setN(1) - c.a.setN2(1) - c.a.setN3(1) - c.a.setN4(1) - c.a.setN5() - - c.a.setArr([]) - c.a.setArr(NumberArray.create([])) - c.a.setArr2([]) - c.a.setArr2(NumberArray.create([])) - c.a.setArr3([]) - c.a.setArr3(NumberArray.create([])) - c.a.setArr4() - - c.a.setMap({ a: 2, b: 3 }) - c.a.setMap(NumberMap.create({ a: 2, b: 3 })) - c.a.setMap2({ a: 2, b: 3 }) - c.a.setMap2(NumberMap.create({ a: 2, b: 3 })) - c.a.setMap3({ a: 2, b: 3 }) - // c.a.setMap3(NumberMap.create({ a: 2, b: 3 })) // doesn't work (as expected, wants a plain object) - c.a.setMap4() - - const arr = types.array(A).create() - unprotect(arr) - arr[0] = cast({ n2: 5 }) - - const map = types.map(A).create() - unprotect(map) - map.set("a", cast({ n2: 5 })) // not really needed in this case, but whatever :) - - // this does not compile, yay! - /* - cast([]) - cast({ a: 5 }) - cast(NumberArray.create([])) - cast(A.create({ n2: 5 })) - cast({ a: 2, b: 5 }) - cast(NumberMap.create({ a: 2, b: 3 })) - */ -}) - -test("#994", () => { - const Cinema = types.model("Cinema", { - id: types.identifier, - name: types.maybe(types.string) - }) - - const ref = types.reference(Cinema) // should compile ok on TS3 -}) - -test("castToSnapshot", () => { - const firstModel = types.model({ brew1: types.map(types.number) }) - const secondModel = types - .model({ brew2: types.map(firstModel) }) - .actions((self) => ({ do() {} })) - const appMod = types.model({ aaa: secondModel }) - - const storeSnapshot: SnapshotIn = { - brew2: { outside: { brew1: { inner: 222 } } } - } - const storeInstance = secondModel.create(storeSnapshot) - const storeSnapshotOrInstance1: SnapshotOrInstance = - secondModel.create(storeSnapshot) - const storeSnapshotOrInstance2: SnapshotOrInstance = storeSnapshot - - appMod.create({ aaa: castToSnapshot(storeInstance) }) - appMod.create({ aaa: castToSnapshot(storeSnapshot) }) - appMod.create({ aaa: castToSnapshot(storeSnapshotOrInstance1) }) - appMod.create({ aaa: castToSnapshot(storeSnapshotOrInstance2) }) - // appMod.create({ aaa: castToSnapshot(5) }) // should not compile -}) - -// disabled due to TS3.4 nesting issue -test.skip("create correctly chooses if the snapshot is needed or not - #920", () => { - const X = types.model({ - test: types.string - }) - const T = types.model({ - test: types.refinement(X, (s) => s.test.length > 5) - }) - // T.create() // manual test: expects compilation error - // T.create({}) // manual test: expects compilation error - T.create({ - test: { test: "hellothere" } - }) - - const T2 = types.model({ - test: types.maybe(X) - }) - T2.create() // ok - T2.create({}) // ok - - const A = types.model({ - test: "bla" - }) - A.create() // ok - A.create({}) // ok - - const B = types.array(types.string) - B.create() // ok - B.create(["hi"]) // ok - - const C = types.map(types.string) - C.create() // ok - C.create({ hi: "hi" }) // ok - - const D = types.number - // D.create() // manual test: expects compilation error - D.create(5) // ok - - const E = types.optional(types.number, 5) - E.create() // ok - E.create(6) // ok - - const F = types.frozen() - // F.create() // manual test: compilation error - F.create(6) // ok - - const FF = types.frozen() - FF.create() // ok - FF.create(undefined) // ok - - const G = types.frozen(5) - G.create() // ok - G.create(6) // ok - - const H = types.frozen(5) - H.create() // ok - H.create(6) // ok - - const I = types.optional(types.frozen(), 6) - I.create() - I.create(7) -}) - -test("#1117", () => { - const Failsafe = ( - t: IType, - handleProblem: ( - value: C, - validationError: ReturnType["validate"]> - ) => void = (value, error) => { - console.error("Skipping value: typecheck error on", value) - console.error(error) - } - ) => - types.custom({ - name: `Failsafe<${t.name}>`, - fromSnapshot(snapshot: C) { - try { - return t.create(snapshot) // this should compile - } catch (e) { - handleProblem(snapshot, e as any) - return null - } - }, - toSnapshot(x) { - if (isStateTreeNode(x)) return getSnapshot(x) - return x as any as C - }, - isTargetType(v): v is T | null { - if (isFrozenType(t)) { - return t.is(v) - } - return false - }, - getValidationMessage() { - return "" - } - }) -}) - -test("MST array type should be assignable to plain array type", () => { - { - const Todo = types - .model({ - done: false, - name: types.string - }) - .actions((self) => ({ - toggleDone() { - self.done = !self.done - } - })) - const TodoArray = types.array(Todo) - - const todoArray = TodoArray.create([{ done: true, name: "todo1" }, { name: "todo2" }]) - unprotect(todoArray) - const otherTodoArray: Array> = todoArray - otherTodoArray.push(cast({ done: false, name: "todo2" })) - } - - { - const T = types.model({ - a: types.optional(types.array(types.number), []) - }) - - const arr: Array = T.create().a - } - - { - const T = types.model({ - a: types.optional(types.array(types.number), [], [5]) - }) - - const arr: Array = T.create({ - a: 5 - }).a - } -}) - -test("can get snapshot from submodel (submodel is IStateNodeTree", () => { - const T = types.model({ - a: types.model({ x: 5 }) - }) - const t = T.create({ a: {} }) - const sn = getSnapshot(t.a).x -}) - -test("can extract type from complex objects", () => { - const T = types.maybe( - types.model({ - a: types.model({ - x: 5 - }) - }) - ) - const t = T.create({ - a: {} - })! - - type OriginalType = TypeOfValue - const T2: OriginalType = T -}) - -test("#1268", () => { - const Book = types.model({ - id: types.identifier - }) - - const BooksStore = types.model({ - books: types.array(types.reference(Book)) - }) - - const RootStore = types.model({ - booksStore: BooksStore - }) - - const booksStore = BooksStore.create({ books: [] }) - - const rootStore = RootStore.create({ booksStore: castToSnapshot(booksStore) }) -}) - -test("#1307 optional can be omitted in .create", () => { - const Model1 = types.model({ name: types.optional(types.string, "") }) - const model1 = Model1.create({}) - assert(model1.name, _ as string) - - const Model2 = types.model({ name: "" }) - const model2 = Model2.create({}) - assert(model2.name, _ as string) -}) - -test("#1307 custom types failing", () => { - const createCustomType = ({ - CustomType - }: { - CustomType: ICustomType - }) => { - return types - .model("Example", { - someProp: types.boolean, - someType: CustomType - }) - .views((self) => ({ - get isSomePropTrue(): boolean { - return self.someProp - } - })) - } -}) - -test("#1343", () => { - function createTypeA(t: T) { - return types.model("TypeA", t).views((self) => ({ - get someView() { - return null - } - })) - } - - function createTypeB(t: T) { - return types - .model("TypeB", { - a: createTypeA(t) - }) - .views((self) => ({ - get someViewFromA() { - return self.a.someView - } - })) - } -}) - -test("#1330", () => { - const ChildStore = types - .model("ChildStore", { - foo: types.string, - bar: types.boolean - }) - .views((self) => ({ - get root(): IRootStore { - return getRoot(self) - } - })) - .actions((self) => ({ - test() { - const { childStore } = self.root - // childStore and childStore.foo is properly inferred in TS 3.4 but not in 3.5 - console.log(childStore.foo) - } - })) - - interface IRootStore extends Instance {} - - const RootStore = types.model("RootStore", { - childStore: ChildStore, - test: "" - }) - - assert( - RootStore.create({ - childStore: { - foo: "a", - bar: true - } - }).childStore.root.test, - _ as string - ) -}) - -test("maybe / optional type inference verification", () => { - const T = types.model({ - a: types.string, - b: "test", - c: types.maybe(types.string), - d: types.maybeNull(types.string), - e: types.optional(types.string, "test") - }) - - interface ITC extends SnapshotIn {} - interface ITS extends SnapshotOut {} - - assert( - _ as ITC, - _ as { - [$nonEmptyObject]?: any - a: string - b?: string - c?: string | undefined - d?: string | null - e?: string - } - ) - - assert( - _ as ITS, - _ as { - [$nonEmptyObject]?: any - a: string - b: string - c: string | undefined - d: string | null - e: string - } - ) -}) diff --git a/packages/mobx-state-tree/__tests__/core/union.test.ts b/packages/mobx-state-tree/__tests__/core/union.test.ts deleted file mode 100644 index 589ffcf2b..000000000 --- a/packages/mobx-state-tree/__tests__/core/union.test.ts +++ /dev/null @@ -1,317 +0,0 @@ -import { configure } from "mobx" -import { - types, - hasParent, - tryResolve, - getSnapshot, - applySnapshot, - getType, - setLivelinessChecking, - SnapshotIn, - Instance -} from "../../src" -import { snapshotProcessor } from "../../src/internal" - -const createTestFactories = () => { - const Box = types.model("Box", { - width: types.number, - height: types.number - }) - const Square = types.model("Square", { - width: types.number - }) - const Cube = types.model("Cube", { - width: types.number, - height: types.number, - depth: types.number - }) - const Plane = types.union(Square, Box) - const Heighed = types.union(Box, Cube) - const DispatchPlane = types.union( - { dispatcher: (snapshot) => (snapshot && "height" in snapshot ? Box : Square) }, - Box, - Square - ) - const Block = types.model("Block", { - list: types.array(Heighed) - }) - return { Box, Square, Cube, Plane, DispatchPlane, Heighed, Block } -} -const createLiteralTestFactories = () => { - const Man = types.model("Man", { type: types.literal("M") }) - const Woman = types.model("Woman", { type: types.literal("W") }) - const All = types.model("All", { type: types.string }) - const ManWomanOrAll = types.union(Man, Woman, All) - return { Man, Woman, All, ManWomanOrAll } -} -if (process.env.NODE_ENV !== "production") { - test("it should complain about multiple applicable types no dispatch method", () => { - const { Box, Square } = createTestFactories() - const PlaneNotEager = types.union({ eager: false }, Square, Box) - expect(() => { - PlaneNotEager.create({ width: 2, height: 2 }) - }).toThrow(/Error while converting/) - }) -} -test("it should have parent whenever creating or applying from a complex data structure to a model which has Union typed children", () => { - const { Block, Heighed } = createTestFactories() - const block = Block.create({ - list: [{ width: 2, height: 2 }] - }) - const child = tryResolve(block, "./list/0") - expect(hasParent(child)).toBe(true) -}) -if (process.env.NODE_ENV !== "production") { - test("it should complain about no applicable types", () => { - const { Heighed } = createTestFactories() - expect(() => { - Heighed.create({ height: 2 } as any) - }).toThrow(/Error while converting/) - }) -} -test("it should be smart enough to discriminate by keys", () => { - const { Box, Plane, Square } = createTestFactories() - const doc = types.union(Square, Box).create({ width: 2 }) - expect(Box.is(doc)).toEqual(false) - expect(Square.is(doc)).toEqual(true) -}) -test("it should discriminate by value type", () => { - const Size = types.model("Size", { - width: 0, - height: 0 - }) - const Picture = types.model("Picture", { - url: "", - size: Size - }) - const Square = types.model("Square", { - size: 0 - }) - const PictureOrSquare = types.union(Picture, Square) - const doc = PictureOrSquare.create({ size: { width: 0, height: 0 } }) - expect(Picture.is(doc)).toEqual(true) - expect(Square.is(doc)).toEqual(false) -}) -test("it should compute exact union types", () => { - const { Box, Plane, Square } = createTestFactories() - expect(Plane.is(Box.create({ width: 3, height: 2 }))).toEqual(true) - expect(Plane.is(Square.create({ width: 3 }))).toEqual(true) -}) -test("it should compute exact union types - 2", () => { - const { Box, DispatchPlane, Square } = createTestFactories() - expect(DispatchPlane.is(Box.create({ width: 3, height: 2 }))).toEqual(true) - expect( - DispatchPlane.is( - Square.create({ width: 3, height: 2 } as any /* incorrect type, superfluous attr!*/) - ) - ).toEqual(true) -}) -test("it should use dispatch to discriminate", () => { - const { Box, DispatchPlane, Square } = createTestFactories() - const a = DispatchPlane.create({ width: 3 }) - expect(getSnapshot(a)).toEqual({ width: 3 }) -}) - -test("it should eagerly match by ambiguos value", () => { - const { ManWomanOrAll, All, Man } = createLiteralTestFactories() - const person = ManWomanOrAll.create({ type: "Z" }) - expect(All.is(person)).toEqual(true) - expect(Man.is(person)).toEqual(false) -}) - -test("it should eagerly match by ambiguos value - 2", () => { - const { All, Man } = createLiteralTestFactories() - const person = types.union(All, Man).create({ type: "M" }) - expect(All.is(person)).toEqual(true) - expect(Man.is(person)).toEqual(false) // not matched, All grabbed everything! -}) - -test("it should eagerly match by value literal", () => { - const { ManWomanOrAll, All, Man } = createLiteralTestFactories() - const person = ManWomanOrAll.create({ type: "M" }) - expect(All.is(person)).toEqual(false) - expect(Man.is(person)).toEqual(true) -}) - -test("dispatch", () => { - const Odd = types - .model({ - value: types.number - }) - .actions((self) => ({ - isOdd() { - return true - }, - isEven() { - return false - } - })) - const Even = types.model({ value: types.number }).actions((self) => ({ - isOdd() { - return false - }, - isEven() { - return true - } - })) - const Num = types.union( - { dispatcher: (snapshot) => (snapshot.value % 2 === 0 ? Even : Odd) }, - Even, - Odd - ) - expect(Num.create({ value: 3 }).isOdd()).toBe(true) - expect(Num.create({ value: 3 }).isEven()).toBe(false) - expect(Num.create({ value: 4 }).isOdd()).toBe(false) - expect(Num.create({ value: 4 }).isEven()).toBe(true) - if (process.env.NODE_ENV !== "production") { - expect(() => { - types.union( - ((snapshot: any) => (snapshot.value % 2 === 0 ? Even : Odd)) as any, // { dispatcher: snapshot => (snapshot.value % 2 === 0 ? Even : Odd) }, - Even, - Odd - ) - }).toThrow("expected object") - } -}) - -test("961 - apply snapshot to union should not throw when union keeps models with different properties and snapshot is got by getSnapshot", () => { - const Foo = types.model({ foo: 1 }) - const Bar = types.model({ bar: 1 }) - const U = types.union(Foo, Bar) - - const u = U.create({ foo: 1 }) - applySnapshot(u, getSnapshot(Bar.create())) -}) - -describe("1045 - secondary union types with applySnapshot and ids", () => { - function initTest( - useSnapshot: boolean, - useCreate: boolean, - submodel1First: boolean, - type: number - ) { - setLivelinessChecking("error") - - const Submodel1NoSP = types.model("Submodel1", { - id: types.identifier, - extraField1: types.string, - extraField2: types.maybe(types.string) - }) - - const Submodel1SP = types.snapshotProcessor(Submodel1NoSP, { - preProcessor(sn: SnapshotIn>) { - const { id, extraField1, extraField2 } = sn - return { - id, - extraField1: extraField1.toUpperCase(), - extraField2: extraField2?.toUpperCase() - } - } - }) - - const Submodel2NoSP = types.model("Submodel2", { - id: types.identifier, - extraField1: types.maybe(types.string), - extraField2: types.string - }) - - const Submodel2SP = types.snapshotProcessor(Submodel2NoSP, { - preProcessor(sn: SnapshotIn>) { - const { id, extraField1, extraField2 } = sn - return { - id, - extraField1: extraField1?.toUpperCase(), - extraField2: extraField2.toUpperCase() - } - } - }) - - const Submodel1 = useSnapshot ? Submodel1SP : Submodel1NoSP - const Submodel2 = useSnapshot ? Submodel2SP : Submodel2NoSP - - const Submodel = submodel1First - ? types.union(Submodel1, Submodel2) - : types.union(Submodel2, Submodel1) - - const Model = types.array(Submodel) - - const store = Model.create([{ id: "id1", extraField1: "extraField1" }]) - - return { - store, - applySn: function () { - const sn1 = { - id: "id1", - extraField1: "new extraField1", - extraField2: "some value" - } - const sn2 = { - id: "id1", - extraField1: undefined, - extraField2: "some value" - } - const sn = type === 1 ? sn1 : sn2 - const submodel = type === 1 ? Submodel1 : Submodel2 - const expected = useSnapshot - ? { - id: sn.id, - extraField1: sn.extraField1?.toUpperCase(), - extraField2: sn.extraField2?.toUpperCase() - } - : sn - - applySnapshot(store, [useCreate ? (submodel as any).create(sn) : sn]) - - expect(store.length).toBe(1) - expect(store[0]).toEqual(expected) - expect(getType(store[0])).toBe(useSnapshot ? submodel.getSubTypes() : submodel) - } - } - } - - for (const useSnapshot of [false, true]) { - describe(useSnapshot ? "with snapshotProcessor" : "without snapshotProcessor", () => { - for (const submodel1First of [true, false]) { - describe(submodel1First ? "submodel1 first" : "submodel2 first", () => { - for (const useCreate of [false, true]) { - describe(useCreate ? "using create" : "not using create", () => { - for (const type of [2, 1]) { - describe(`snapshot is of type Submodel${type}`, () => { - it(`apply snapshot works when the node is not touched`, () => { - configure({ - useProxies: "never" - }) - - const t = initTest( - useSnapshot, - useCreate, - submodel1First, - type - ) - t.applySn() - }) - - it(`apply snapshot works when the node is touched`, () => { - configure({ - useProxies: "never" - }) - - const t = initTest( - useSnapshot, - useCreate, - submodel1First, - type - ) - // tslint:disable-next-line:no-unused-expression - t.store[0] - t.applySn() - }) - }) - } - }) - } - }) - } - }) - } -}) diff --git a/packages/mobx-state-tree/__tests__/core/volatile.test.ts b/packages/mobx-state-tree/__tests__/core/volatile.test.ts deleted file mode 100644 index a24e7a5c1..000000000 --- a/packages/mobx-state-tree/__tests__/core/volatile.test.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { types, getSnapshot, recordPatches, unprotect } from "../../src" -import { reaction, isObservableProp, isObservable, autorun, observable } from "mobx" - -const Todo = types - .model({ - done: false - }) - .volatile((self) => ({ - state: Promise.resolve(1) - })) - .actions((self) => ({ - toggle() { - self.done = !self.done - }, - reload() { - self.state = Promise.resolve(2) - } - })) - -test("Properties should be readable and writable", () => { - const i = Todo.create() - expect(i.state instanceof Promise).toBe(true) - i.reload() - expect(i.state instanceof Promise).toBe(true) -}) - -test("VS should not show up in snapshots", () => { - expect(getSnapshot(Todo.create())).toEqual({ done: false }) -}) - -test("VS should not show up in patches", () => { - const i = Todo.create() - const r = recordPatches(i) - i.reload() - i.toggle() - r.stop() - expect(r.patches).toEqual([{ op: "replace", path: "/done", value: true }]) -}) - -test("VS be observable", () => { - const promises: Promise[] = [] - const i = Todo.create() - const d = reaction( - () => i.state, - (p) => promises.push(p) - ) - i.reload() - i.reload() - expect(promises.length).toBe(2) - d() -}) - -test("VS should not be deeply observable", () => { - const i = types - .model({}) - .volatile((self) => ({ - x: { a: 1 } - })) - .create() - unprotect(i) - expect(isObservableProp(i, "x")).toBe(true) - expect(isObservable(i.x)).toBe(false) - expect(isObservableProp(i.x, "a")).toBe(false) - i.x = { a: 2 } - expect(isObservableProp(i, "x")).toBe(true) - expect(isObservable(i.x)).toBe(false) - expect(isObservableProp(i.x, "a")).toBe(false) -}) - -test("VS should not be strongly typed observable", () => { - const i = Todo.create() - // TEST: type error i.state = 7 - i.state.then(() => {}) // it's a promise - // TEST: not available on snapshot: getSnapshot(i).state - expect(true).toBe(true) -}) - -test("VS should not be modifiable without action", () => { - const i = Todo.create() - expect(() => { - i.state = Promise.resolve(4) - }).toThrowError(/the object is protected and can only be modified by using an action/) -}) - -test("VS should expect a function as an argument", () => { - expect(() => { - const t = types - .model({}) - // @ts-ignore - .volatile({ state: 1 }) - .create() - }).toThrowError( - `You passed an object to volatile state as an argument, when function is expected` - ) -}) - -test("VS should not be modifiable when unprotected", () => { - const i = Todo.create() - unprotect(i) - const p = Promise.resolve(7) - expect(() => { - i.state = p - }).not.toThrow() - expect(i.state === p).toBe(true) -}) - -test("VS sample from the docs should work (1)", () => { - const T = types.model({}).extend((self) => { - const localState = observable.box(3) - - return { - views: { - get x() { - return localState.get() - } - }, - actions: { - setX(value: number) { - localState.set(value) - } - } - } - }) - - const t = T.create() - expect(t.x).toBe(3) - t.setX(5) - expect(t.x).toBe(5) - - // now observe it - const observed: number[] = [] - const dispose = autorun(() => { - observed.push(t.x) - }) - - t.setX(7) - expect(t.x).toBe(7) - expect(observed).toEqual([5, 7]) - dispose() -}) - -test("VS sample from the docs should work (2)", () => { - const T = types.model({}).extend((self) => { - let localState = 3 - - return { - views: { - getX() { - return localState - } - }, - actions: { - setX(value: number) { - localState = value - } - } - } - }) - - const t = T.create() - expect(t.getX()).toBe(3) - t.setX(5) - expect(t.getX()).toBe(5) - - // now observe it (should not be observable) - const observed: number[] = [] - const dispose = autorun(() => { - observed.push(t.getX()) - }) - - t.setX(7) - expect(t.getX()).toBe(7) - expect(observed).toEqual([5]) - dispose() -}) diff --git a/packages/mobx-state-tree/__tests__/perf/fixture-data.test.ts b/packages/mobx-state-tree/__tests__/perf/fixture-data.test.ts deleted file mode 100644 index ba30e015d..000000000 --- a/packages/mobx-state-tree/__tests__/perf/fixture-data.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { rando, createHeros, createMonsters, createTreasure } from "./fixtures/fixture-data" -import { Hero, Monster, Treasure } from "./fixtures/fixture-models" - -test("createHeros", () => { - const data = createHeros(10) - expect(data.length).toBe(10) - const hero = Hero.create(data[0]) - expect(hero.descriptionLength > 1).toBe(true) -}) -test("createMonsters", () => { - const data = createMonsters(10, 10, 10) - expect(data.length).toBe(10) - expect(data[1].treasures.length).toBe(10) - expect(data[0].eatenHeroes.length).toBe(10) - const monster = Monster.create(data[0]) - expect(monster.eatenHeroes && monster.eatenHeroes.length === 10).toBe(true) - expect(monster.treasures.length === 10).toBe(true) -}) -test("createTreasure", () => { - const data = createTreasure(10) - expect(data.length).toBe(10) - const treasure = Treasure.create(data[1]) - expect(treasure.gold > 0).toBe(true) -}) -test("rando sorting", () => { - // i'm going straight to hell for this test... must get coverage to 100%.... no matter the cost. - let foundTrue = false - let foundFalse = false - let result - do { - result = rando() - if (result) { - foundTrue = true - } else { - foundFalse = true - } - } while (!foundTrue || !foundFalse) - expect(foundTrue).toBe(true) - expect(foundFalse).toBe(true) -}) diff --git a/packages/mobx-state-tree/__tests__/perf/fixture-models.test.ts b/packages/mobx-state-tree/__tests__/perf/fixture-models.test.ts deleted file mode 100644 index 0311741dc..000000000 --- a/packages/mobx-state-tree/__tests__/perf/fixture-models.test.ts +++ /dev/null @@ -1,52 +0,0 @@ -import { Hero, Monster, Treasure } from "./fixtures/fixture-models" -const mst = require("../../dist/mobx-state-tree.umd") -const { unprotect } = mst - -const SAMPLE_HERO = { - id: 1, - name: "jimmy", - level: 1, - role: "cleric", - description: "hi" -} -test("Hero computed fields", () => { - const hero = Hero.create(SAMPLE_HERO) - expect(hero.descriptionLength).toBe(2) -}) -test("Tresure", () => { - const treasure = Treasure.create({ gold: 1, trapped: true }) - expect(treasure.trapped).toBe(true) - expect(treasure.gold).toBe(1) -}) -test("Monster computed fields", () => { - const monster = Monster.create({ - id: "foo", - level: 1, - maxHp: 3, - hp: 1, - warning: "boo!", - createdAt: new Date(), - treasures: [ - { gold: 2, trapped: true }, - { gold: 3, trapped: true } - ], - eatenHeroes: [SAMPLE_HERO], - hasFangs: true, - hasClaws: true, - hasWings: true, - hasGrowl: true, - freestyle: null - }) - expect(monster.isAlive).toBe(true) - expect(monster.isFlashingRed).toBe(true) - unprotect(monster) - expect(monster.weight).toBe(2) - monster.level = 0 - monster.hasFangs = false - monster.hasWings = false - monster.eatenHeroes = null - expect(monster.weight).toBe(1) - monster.hp = 0 - expect(monster.isFlashingRed).toBe(false) - expect(monster.isAlive).toBe(false) -}) diff --git a/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-data.ts b/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-data.ts deleted file mode 100644 index fbd4f1d47..000000000 --- a/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-data.ts +++ /dev/null @@ -1,99 +0,0 @@ -import { HeroRoles } from "./fixture-models" - -/** - * Creates data containing very few fields. - * - * @param count The number of items to create. - */ -export function createTreasure(count: number) { - const data = [] - let i = 0 - do { - data.push({ - trapped: i % 2 === 0, - gold: ((count % 10) + 1) * 10 - }) - i++ - } while (i < count) - return data -} - -// why yes i DID graduate high school, why do you ask? -export const rando = () => (Math.random() > 0.5 ? 1 : 0) - -const titles = ["Sir", "Lady", "Baron von", "Baroness", "Captain", "Dread", "Fancy"].sort(rando) -const givenNames = ["Abe", "Beth", "Chuck", "Dora", "Ernie", "Fran", "Gary", "Haily"].sort(rando) -const epicNames = ["Amazing", "Brauny", "Chafed", "Dapper", "Egomaniac", "Foul"].sort(rando) -const wtf = `Daenerys Stormborn of the House Targaryen, First of Her Name, the Unburnt, - Queen of the Andals and the First Men, Khaleesi of the Great Grass Sea, Breaker of Chains, - and Mother of Dragons. ` -/** - * Creates data with a medium number of fields and data. - * - * @param count The number of items to create. - */ -export function createHeros(count: number) { - const data = [] - let i = 0 - let even = true - let n1 - let n2 - let n3 - do { - n1 = titles[i % titles.length] - n2 = givenNames[i % givenNames.length] - n3 = epicNames[i % epicNames.length] - data.push({ - id: i, - name: `${n1} ${n2} the ${n3}`, - level: (count % 100) + 1, - role: HeroRoles[i % HeroRoles.length], - description: `${wtf} ${wtf} ${wtf}` - }) - even = !even - i++ - } while (i < count) - return data -} - -/** - * Creates data with a large number of fields and data. - * - * @param count The number of items to create. - * @param treasureCount The number of small children to create. - * @param heroCount The number of medium children to create. - */ -export function createMonsters(count: number, treasureCount: number, heroCount: number) { - const data = [] - let i = 0 - let even = true - do { - const treasures = createTreasure(treasureCount) - const eatenHeroes = createHeros(heroCount) - data.push({ - id: `omg-${i}-run!`, - freestyle: `${wtf} ${wtf} ${wtf}${wtf} ${wtf} ${wtf}`, - level: (count % 100) + 1, - hp: i % 2 === 0 ? 1 : 5 * i, - maxHp: 5 * i, - warning: "!!!!!!", - createdAt: new Date(), - hasFangs: even, - hasClaws: even, - hasWings: !even, - hasGrowl: !even, - fearsFire: even, - fearsWater: !even, - fearsWarriors: even, - fearsClerics: !even, - fearsMages: even, - fearsThieves: !even, - stenchLevel: i % 5, - treasures, - eatenHeroes - }) - even = !even - i++ - } while (i < count) - return data -} diff --git a/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-models.ts b/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-models.ts deleted file mode 100644 index 331350d9a..000000000 --- a/packages/mobx-state-tree/__tests__/perf/fixtures/fixture-models.ts +++ /dev/null @@ -1,62 +0,0 @@ -const mst = require("../../../dist/mobx-state-tree.umd") -const { types } = mst - -// tiny -export const Treasure = types.model("Treasure", { - trapped: types.boolean, - gold: types.optional(types.number, 0) -}) -// medium -export const HeroRoles = ["warrior", "wizard", "cleric", "thief"] -export const Hero = types - .model("Hero", { - id: types.identifierNumber, - name: types.string, - description: types.string, - level: types.optional(types.number, 1), - role: types.union(...exports.HeroRoles.map(types.literal)) - }) - .views((self: any) => ({ - get descriptionLength() { - return self.description.length - } - })) -// large -export const Monster = types - .model("Monster", { - id: types.identifier, - freestyle: types.frozen(), - level: types.number, - maxHp: types.number, - hp: types.number, - warning: types.maybeNull(types.string), - createdAt: types.maybeNull(types.Date), - treasures: types.optional(types.array(exports.Treasure), []), - eatenHeroes: types.maybeNull(types.array(exports.Hero)), - hasFangs: types.optional(types.boolean, false), - hasClaws: types.optional(types.boolean, false), - hasWings: types.optional(types.boolean, false), - hasGrowl: types.optional(types.boolean, false), - stenchLevel: types.optional(types.number, 0), - fearsFire: types.optional(types.boolean, false), - fearsWater: types.optional(types.boolean, false), - fearsWarriors: types.optional(types.boolean, false), - fearsClerics: types.optional(types.boolean, false), - fearsMages: types.optional(types.boolean, false), - fearsThieves: types.optional(types.boolean, false), - fearsProgrammers: types.optional(types.boolean, true) - }) - .views((self: any) => ({ - get isAlive() { - return self.hp > 0 - }, - get isFlashingRed() { - return self.hp > 0 && self.hp < self.maxHp && self.hp === 1 - }, - get weight() { - const victimWeight = self.eatenHeroes ? self.eatenHeroes.length : 0 - const fangWeight = self.hasFangs ? 10 : 5 - const wingWeight = self.hasWings ? 12 : 4 - return (victimWeight + fangWeight + wingWeight) * self.level > 5 ? 2 : 1 - } - })) diff --git a/packages/mobx-state-tree/__tests__/perf/perf.test.ts b/packages/mobx-state-tree/__tests__/perf/perf.test.ts deleted file mode 100644 index 4f841c8ac..000000000 --- a/packages/mobx-state-tree/__tests__/perf/perf.test.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { smallScenario, mediumScenario, largeScenario } from "./scenarios" -import { start } from "./timer" - -// TODO: Not sure how this should work. This feels super fragile. -const TOO_SLOW_MS = 10000 -test("performs well on small scenario", () => { - expect(smallScenario(10).elapsed < TOO_SLOW_MS).toBe(true) -}) -test("performs well on medium scenario", () => { - expect(mediumScenario(10).elapsed < TOO_SLOW_MS).toBe(true) -}) -test("performs well on large scenario", () => { - expect(largeScenario(10, 0, 0).elapsed < TOO_SLOW_MS).toBe(true) - expect(largeScenario(10, 10, 0).elapsed < TOO_SLOW_MS).toBe(true) - expect(largeScenario(10, 0, 10).elapsed < TOO_SLOW_MS).toBe(true) - expect(largeScenario(10, 10, 10).elapsed < TOO_SLOW_MS).toBe(true) -}) -test("timer", (done) => { - const go = start() - setTimeout(function () { - const lap = go(true) - setTimeout(function () { - const d = go() - expect(lap).not.toBe(0) - expect(d).not.toBe(0) - expect(lap).not.toBe(d) - done() - }, 2) - }, 2) -}) diff --git a/packages/mobx-state-tree/__tests__/perf/report.ts b/packages/mobx-state-tree/__tests__/perf/report.ts deleted file mode 100644 index 238f03253..000000000 --- a/packages/mobx-state-tree/__tests__/perf/report.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { smallScenario, mediumScenario, largeScenario } from "./scenarios" - -// here's what we'll be testing -const plan = [ - "-----------", - "Small Model", - "-----------", - () => smallScenario(100), - () => smallScenario(1000), - () => smallScenario(10000), - () => smallScenario(1000), - () => smallScenario(100), - "", - "------------", - "Medium Model", - "------------", - () => mediumScenario(100), - () => mediumScenario(1000), - () => mediumScenario(10000), - () => mediumScenario(1000), - () => mediumScenario(100), - "", - "------------------------", - "Large Model - 0 children", - "------------------------", - () => largeScenario(100, 0, 0), - () => largeScenario(1000, 0, 0), - () => largeScenario(100, 0, 0), - "", - "-------------------------------------------", - "Large Model - 10 small & 10 medium children", - "-------------------------------------------", - () => largeScenario(50, 10, 10), - () => largeScenario(250, 10, 10), - () => largeScenario(50, 10, 10), - "", - "-------------------------------------------", - "Large Model - 100 small & 0 medium children", - "-------------------------------------------", - () => largeScenario(50, 100, 0), - () => largeScenario(250, 100, 0), - () => largeScenario(50, 100, 0), - "", - "-------------------------------------------", - "Large Model - 0 small & 100 medium children", - "-------------------------------------------", - () => largeScenario(50, 0, 100), - () => largeScenario(250, 0, 100), - () => largeScenario(50, 0, 100) -] -// burn a few to get the juices flowing -smallScenario(1000) -mediumScenario(500) -largeScenario(100, 10, 10) -// remember when this broke the internet? -function leftPad(value: string, length: number, char = " "): string { - return value.toString().length < length ? leftPad(char + value, length) : value -} -// let's start -plan.forEach((fn) => { - // strings get printed, i guess. - if (typeof fn === "string") { - console.log(fn) - return - } - // trigger awkward gc up front if we can - if (global.gc) { - global.gc() - } - // run the report - const result = fn() - // calculate some fields - const seconds = leftPad((result.elapsed / 1.0).toLocaleString(), 8) - const times = leftPad(`x ${result.count.toLocaleString()}`, 10) - const avg = leftPad((result.elapsed / result.count).toFixed(1), 4) - // print - console.log(`${seconds}ms | ${times} | ${avg}ms avg`) -}) -console.log("") diff --git a/packages/mobx-state-tree/__tests__/tslint.json b/packages/mobx-state-tree/__tests__/tslint.json deleted file mode 100644 index 55f072963..000000000 --- a/packages/mobx-state-tree/__tests__/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../../tslint.json" -} diff --git a/packages/mobx-state-tree/jest.config.js b/packages/mobx-state-tree/jest.config.js deleted file mode 100644 index 745b32a4f..000000000 --- a/packages/mobx-state-tree/jest.config.js +++ /dev/null @@ -1,15 +0,0 @@ -module.exports = { - displayName: "test", - testEnvironment: "node", - transform: { - "^.+\\.tsx?$": "ts-jest" - }, - testRegex: ".*\\.test\\.tsx?$", - moduleFileExtensions: ["ts", "tsx", "js"], - globals: { - "ts-jest": { - tsConfig: "__tests__/tsconfig.json" - } - }, - reporters: ["default", "jest-junit"] -} diff --git a/packages/mobx-state-tree/package.json b/packages/mobx-state-tree/package.json deleted file mode 100644 index e8b9e937f..000000000 --- a/packages/mobx-state-tree/package.json +++ /dev/null @@ -1,90 +0,0 @@ -{ - "name": "mobx-state-tree", - "version": "5.2.0", - "description": "Opinionated, transactional, MobX powered state container", - "main": "dist/mobx-state-tree.js", - "umd:main": "dist/mobx-state-tree.umd.js", - "module": "dist/mobx-state-tree.module.js", - "browser": { - "./dist/mobx-state-tree.js": "./dist/mobx-state-tree.js", - "./dist/mobx-state-tree.module.js": "./dist/mobx-state-tree.module.js" - }, - "unpkg": "dist/mobx-state-tree.umd.min.js", - "jsnext:main": "dist/mobx-state-tree.module.js", - "react-native": "dist/mobx-state-tree.module.js", - "typings": "dist/index.d.ts", - "sideEffects": false, - "scripts": { - "clean": "shx rm -rf dist && shx rm -rf lib", - "build": "yarn clean && shx cp ../../README.md . && tsc && cpr lib dist --filter=\\.js$ && rollup -c", - "jest": "jest --testPathPattern=/__tests__/core/", - "jest:perf": "jest --testPathPattern=/__tests__/perf/", - "test:perf": "yarn build && yarn jest:perf && TS_NODE_COMPILER_OPTIONS='{\"module\": \"commonjs\"}' /usr/bin/time node --expose-gc --require ts-node/register __tests__/perf/report.ts", - "test": "yarn test:dev && yarn test:prod && yarn test:others", - "test:dev": "cross-env NODE_ENV=development JEST_JUNIT_OUTPUT=../../test-results/mobx-state-tree/dev.xml yarn jest", - "test:prod": "cross-env NODE_ENV=production JEST_JUNIT_OUTPUT=../../test-results/mobx-state-tree/prod.xml yarn jest", - "test:others": "yarn test:cyclic", - "test:cyclic": "node -e \"require('.')\"", - "_prepublish": "yarn build && yarn build-docs", - "fix-typedoc": "shx rm -rf ../../node_modules/typedoc/node_modules/typescript", - "build-docs": "yarn run fix-typedoc && shx rm -rf ../../docs/API && typedoc --options ./typedocconfig.js", - "lint": "tslint -c ./tslint.json 'src/**/*.ts'" - }, - "repository": { - "type": "git", - "url": "https://github.com/mobxjs/mobx-state-tree.git" - }, - "author": "Michel Weststrate", - "license": "MIT", - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/mobx" - }, - "bugs": { - "url": "https://github.com/mobxjs/mobx-state-tree/issues" - }, - "files": [ - "dist/" - ], - "devDependencies": { - "@types/jest": "^26.0.3", - "@types/node": "^12.0.2", - "concat": "^1.0.3", - "coveralls": "^3.1.0", - "cpr": "^3.0.1", - "cross-env": "^7.0.2", - "jest": "^26.1.0", - "jest-junit": "^11.0.1", - "lerna": "^3.13.1", - "mobx": "^6.3.0", - "rollup": "^2.18.1", - "rollup-plugin-commonjs": "^10.0.0", - "rollup-plugin-filesize": "^9.0.1", - "rollup-plugin-node-resolve": "^5.0.0", - "rollup-plugin-replace": "^2.1.0", - "rollup-plugin-terser": "^6.1.0", - "shx": "^0.3.2", - "size-limit": "^4.5.2", - "spec.ts": "^1.1.3", - "ts-jest": "^26.1.1", - "ts-node": "^8.10.2", - "tslib": "^2.0.0", - "tslint": "^6.1.2", - "typedoc": "0.15.8", - "typedoc-plugin-markdown": "2.2.11", - "typescript": "^3.5.3" - }, - "peerDependencies": { - "mobx": "^6.3.0" - }, - "keywords": [ - "mobx", - "mobx-state-tree", - "promise", - "reactive", - "frp", - "functional-reactive-programming", - "state management" - ], - "gitHead": "27ec7ac0b0743a367fb01a7f40192f3042bd91f2" -} diff --git a/packages/mobx-state-tree/rollup.config.js b/packages/mobx-state-tree/rollup.config.js deleted file mode 100644 index d9d47d679..000000000 --- a/packages/mobx-state-tree/rollup.config.js +++ /dev/null @@ -1,25 +0,0 @@ -import { baseConfig } from "../../rollup.base-config" - -const config = (outFile, format, mode) => - baseConfig({ - outFile, - format, - mode, - - input: "./lib/index.js", - globals: { - mobx: "mobx" - }, - umdName: "mobxStateTree", - external: ["mobx"] - }) - -export default [ - config("mobx-state-tree.js", "cjs", "development"), - config("mobx-state-tree.min.js", "cjs", "production"), - - config("mobx-state-tree.umd.js", "umd", "development"), - config("mobx-state-tree.umd.min.js", "umd", "production"), - - config("mobx-state-tree.module.js", "es", "development") -] diff --git a/packages/mobx-state-tree/scripts/generate-compose-type.js b/packages/mobx-state-tree/scripts/generate-compose-type.js deleted file mode 100644 index ff5c3dfce..000000000 --- a/packages/mobx-state-tree/scripts/generate-compose-type.js +++ /dev/null @@ -1,53 +0,0 @@ -const { getDeclaration } = require("./generate-shared") - -let str = `// generated with ${__filename}\n` - -const minArgs = 2 -const maxArgs = 10 -const preParam = "name: string, " - -const returnTypeTransform = (rt) => { - // [['PA', 'PB', 'PC'], ['OA', 'OB', 'OC'], ['FCA', 'FCB', 'FCC'], ['FSA', 'FSB', 'FSC']] - // -> - // [['PA', 'PB', 'PC'], no change - // ['OA', 'OB', 'OC'], no change - // ['_CustomJoin>'] - // ['_CustomJoin>']] - - const [props, others, fixedC, fixedS] = rt - - function customJoin(left) { - if (left.length === 1) { - return left[0] - } - const [a, ...rest] = left - return `_CustomJoin<${a}, ${customJoin(rest)}>` - } - - return [props, others, [customJoin(fixedC)], [customJoin(fixedS)]] -} - -for (let i = minArgs; i < maxArgs; i++) { - str += getDeclaration( - "compose", - "IModelType", - ["P", "O", "FC", "FS"], - i, - preParam, - "&", - "IModelType", - returnTypeTransform - ) - str += getDeclaration( - "compose", - "IModelType", - ["P", "O", "FC", "FS"], - i, - null, - "&", - "IModelType", - returnTypeTransform - ) -} - -console.log(str) diff --git a/packages/mobx-state-tree/scripts/generate-shared.js b/packages/mobx-state-tree/scripts/generate-shared.js deleted file mode 100644 index 6d3633a5f..000000000 --- a/packages/mobx-state-tree/scripts/generate-shared.js +++ /dev/null @@ -1,55 +0,0 @@ -const alfa = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" - -function getTemplateVar(templateVar, argNumber) { - return `${templateVar}${alfa[argNumber]}` -} - -function getTemplateVars(templateVars, argNumber) { - return templateVars.map((tv) => getTemplateVar(tv, argNumber)) -} - -exports.getDeclaration = function getDeclaration( - funcName, - type, - templateVars, - args, - preParam, - operationChar, - outType = type, - allReturnTypesTransform = (x) => x -) { - let str = "// prettier-ignore\n" - - let allTemplateVars = [] - for (let i = 0; i < args; i++) { - allTemplateVars = allTemplateVars.concat(getTemplateVars(templateVars, i)) - } - allTemplateVars = allTemplateVars.map((tv) => - tv.startsWith("P") ? `${tv} extends ModelProperties` : tv - ) - str += `export function ${funcName}<${allTemplateVars.join(", ")}>(` - - if (preParam) { - str += preParam - } - - const allParams = [] - for (let i = 0; i < args; i++) { - allParams.push(`${alfa[i]}: ${type}<${getTemplateVars(templateVars, i).join(", ")}>`) - } - str += `${allParams.join(", ")}` - str += ")" - - let allReturnTypes = [] - for (const templateVar of templateVars) { - let union = [] - for (let i = 0; i < args; i++) { - union.push(getTemplateVar(templateVar, i)) - } - allReturnTypes.push(union) - } - allReturnTypes = allReturnTypesTransform(allReturnTypes) - str += `: ${outType}<${allReturnTypes.map((u) => u.join(` ${operationChar} `)).join(", ")}>` - - return str + "\n" -} diff --git a/packages/mobx-state-tree/scripts/generate-union-types.js b/packages/mobx-state-tree/scripts/generate-union-types.js deleted file mode 100644 index 8bcda25dd..000000000 --- a/packages/mobx-state-tree/scripts/generate-union-types.js +++ /dev/null @@ -1,69 +0,0 @@ -const { getDeclaration } = require("./generate-shared") - -let str = `// generated with ${__filename}\n` - -const minArgs = 2 -const maxArgs = 10 -const preParam = "options: UnionOptions, " -const modelReturnTypeTransform = (rt) => { - // [['PA', 'PB'], ['OA', 'OB'], ['FCA', 'FCB'], ['FSA', 'FSB']] - // -> - // [['ModelCreationType2', 'ModelCreationType2'], - // ['ModelSnapshotType2', 'ModelSnapshotType2'], - // ['ModelInstanceType', 'ModelInstanceType']] - const [props, others, fixedC, fixedS] = rt - - const c = [], - s = [], - t = [] - for (let i = 0; i < props.length; i++) { - const p = props[i] - const o = others[i] - const fc = fixedC[i] - const fs = fixedS[i] - - c.push(`ModelCreationType2<${p}, ${fc}>`) - s.push(`ModelSnapshotType2<${p}, ${fs}>`) - t.push(`ModelInstanceType<${p}, ${o}>`) - } - return [c, s, t] -} - -for (let i = minArgs; i < maxArgs; i++) { - str += getDeclaration( - "union", - "IModelType", - ["P", "O", "FC", "FS"], - i, - null, - "|", - "ITypeUnion", - modelReturnTypeTransform - ) - str += getDeclaration( - "union", - "IModelType", - ["P", "O", "FC", "FS"], - i, - preParam, - "|", - "ITypeUnion", - modelReturnTypeTransform - ) -} - -for (let i = minArgs; i < maxArgs; i++) { - str += getDeclaration("union", "IType", ["C", "S", "T"], i, null, "|", "ITypeUnion", undefined) - str += getDeclaration( - "union", - "IType", - ["C", "S", "T"], - i, - preParam, - "|", - "ITypeUnion", - undefined - ) -} - -console.log(str) diff --git a/packages/mobx-state-tree/src/core/action.ts b/packages/mobx-state-tree/src/core/action.ts deleted file mode 100644 index 80570bd09..000000000 --- a/packages/mobx-state-tree/src/core/action.ts +++ /dev/null @@ -1,310 +0,0 @@ -import { action as mobxAction } from "mobx" -import { - getStateTreeNode, - fail, - argsToArray, - IDisposer, - getRoot, - Hook, - IAnyStateTreeNode, - warnError, - AnyObjectNode, - devMode, - IActionContext -} from "../internal" - -export type IMiddlewareEventType = - | "action" - | "flow_spawn" - | "flow_resume" - | "flow_resume_error" - | "flow_return" - | "flow_throw" -// | "task_spawn TODO, see #273" - -export interface IMiddlewareEvent extends IActionContext { - /** Event type */ - readonly type: IMiddlewareEventType - - /** Parent event unique id */ - readonly parentId: number - /** Parent event object */ - readonly parentEvent: IMiddlewareEvent | undefined - - /** Root event unique id */ - readonly rootId: number - /** Id of all events, from root until current (excluding current) */ - readonly allParentIds: number[] -} - -export interface FunctionWithFlag extends Function { - _isMSTAction?: boolean - _isFlowAction?: boolean -} - -/** - * @internal - * @hidden - */ -export type IMiddleware = { - handler: IMiddlewareHandler - includeHooks: boolean -} - -export type IMiddlewareHandler = ( - actionCall: IMiddlewareEvent, - next: (actionCall: IMiddlewareEvent, callback?: (value: any) => any) => void, - abort: (value: any) => void -) => any - -let nextActionId = 1 -let currentActionContext: IMiddlewareEvent | undefined - -/** - * @internal - * @hidden - */ -export function getCurrentActionContext() { - return currentActionContext -} - -/** - * @internal - * @hidden - */ -export function getNextActionId() { - return nextActionId++ -} - -// TODO: optimize away entire action context if there is no middleware in tree? -/** - * @internal - * @hidden - */ -export function runWithActionContext(context: IMiddlewareEvent, fn: Function) { - const node = getStateTreeNode(context.context) - - if (context.type === "action") { - node.assertAlive({ - actionContext: context - }) - } - - const baseIsRunningAction = node._isRunningAction - node._isRunningAction = true - const previousContext = currentActionContext - currentActionContext = context - try { - return runMiddleWares(node, context, fn) - } finally { - currentActionContext = previousContext - node._isRunningAction = baseIsRunningAction - } -} - -/** - * @internal - * @hidden - */ -export function getParentActionContext(parentContext: IMiddlewareEvent | undefined) { - if (!parentContext) return undefined - if (parentContext.type === "action") return parentContext - return parentContext.parentActionEvent -} - -/** - * @internal - * @hidden - */ -export function createActionInvoker( - target: IAnyStateTreeNode, - name: string, - fn: T -) { - const res = function () { - const id = getNextActionId() - const parentContext = currentActionContext - const parentActionContext = getParentActionContext(parentContext) - - return runWithActionContext( - { - type: "action", - name, - id, - args: argsToArray(arguments), - context: target, - tree: getRoot(target), - rootId: parentContext ? parentContext.rootId : id, - parentId: parentContext ? parentContext.id : 0, - allParentIds: parentContext - ? [...parentContext.allParentIds, parentContext.id] - : [], - parentEvent: parentContext, - parentActionEvent: parentActionContext - }, - fn - ) - } - ;(res as FunctionWithFlag)._isMSTAction = true - ;(res as FunctionWithFlag)._isFlowAction = fn._isFlowAction - return res -} - -/** - * Middleware can be used to intercept any action is invoked on the subtree where it is attached. - * If a tree is protected (by default), this means that any mutation of the tree will pass through your middleware. - * - * For more details, see the [middleware docs](concepts/middleware.md) - * - * @param target Node to apply the middleware to. - * @param middleware Middleware to apply. - * @returns A callable function to dispose the middleware. - */ -export function addMiddleware( - target: IAnyStateTreeNode, - handler: IMiddlewareHandler, - includeHooks: boolean = true -): IDisposer { - const node = getStateTreeNode(target) - if (devMode()) { - if (!node.isProtectionEnabled) { - warnError( - "It is recommended to protect the state tree before attaching action middleware, as otherwise it cannot be guaranteed that all changes are passed through middleware. See `protect`" - ) - } - } - return node.addMiddleWare(handler, includeHooks) -} - -/** - * Binds middleware to a specific action. - * - * Example: - * ```ts - * type.actions(self => { - * function takeA____() { - * self.toilet.donate() - * self.wipe() - * self.wipe() - * self.toilet.flush() - * } - * return { - * takeA____: decorate(atomic, takeA____) - * } - * }) - * ``` - * - * @param handler - * @param fn - * @param includeHooks - * @returns The original function - */ -export function decorate( - handler: IMiddlewareHandler, - fn: T, - includeHooks = true -): T { - const middleware: IMiddleware = { handler, includeHooks } - ;(fn as any).$mst_middleware = (fn as any).$mst_middleware || [] - ;(fn as any).$mst_middleware.push(middleware) - return fn -} - -class CollectedMiddlewares { - private arrayIndex = 0 - private inArrayIndex = 0 - private middlewares: IMiddleware[][] = [] - - constructor(node: AnyObjectNode, fn: Function) { - // we just push middleware arrays into an array of arrays to avoid making copies - if ((fn as any).$mst_middleware) { - this.middlewares.push((fn as any).$mst_middleware) - } - let n: AnyObjectNode | null = node - // Find all middlewares. Optimization: cache this? - while (n) { - if (n.middlewares) this.middlewares.push(n.middlewares) - n = n.parent - } - } - - get isEmpty() { - return this.middlewares.length <= 0 - } - - getNextMiddleware(): IMiddleware | undefined { - const array = this.middlewares[this.arrayIndex] - if (!array) return undefined - const item = array[this.inArrayIndex++] - if (!item) { - this.arrayIndex++ - this.inArrayIndex = 0 - return this.getNextMiddleware() - } - return item - } -} - -function runMiddleWares( - node: AnyObjectNode, - baseCall: IMiddlewareEvent, - originalFn: Function -): any { - const middlewares = new CollectedMiddlewares(node, originalFn) - // Short circuit - if (middlewares.isEmpty) return mobxAction(originalFn).apply(null, baseCall.args) - - let result: any = null - - function runNextMiddleware(call: IMiddlewareEvent): any { - const middleware = middlewares.getNextMiddleware() - const handler = middleware && middleware.handler - - if (!handler) { - return mobxAction(originalFn).apply(null, call.args) - } - - // skip hooks if asked to - if (!middleware!.includeHooks && (Hook as any)[call.name]) { - return runNextMiddleware(call) - } - - let nextInvoked = false - function next(call2: IMiddlewareEvent, callback?: (value: any) => any): void { - nextInvoked = true - // the result can contain - // - the non manipulated return value from an action - // - the non manipulated abort value - // - one of the above but manipulated through the callback function - result = runNextMiddleware(call2) - if (callback) { - result = callback(result) - } - } - - let abortInvoked = false - function abort(value: any) { - abortInvoked = true - // overwrite the result - // can be manipulated through middlewares earlier in the queue using the callback fn - result = value - } - - handler(call, next, abort) - if (devMode()) { - if (!nextInvoked && !abortInvoked) { - const node2 = getStateTreeNode(call.tree) - throw fail( - `Neither the next() nor the abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} was invoked.` - ) - } else if (nextInvoked && abortInvoked) { - const node2 = getStateTreeNode(call.tree) - throw fail( - `The next() and abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} were invoked.` - ) - } - } - return result - } - return runNextMiddleware(baseCall) -} diff --git a/packages/mobx-state-tree/src/core/actionContext.ts b/packages/mobx-state-tree/src/core/actionContext.ts deleted file mode 100644 index 2f5aeeabf..000000000 --- a/packages/mobx-state-tree/src/core/actionContext.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { IAnyStateTreeNode, IMiddlewareEvent } from "../internal" -import { getCurrentActionContext } from "./action" - -export interface IActionContext { - /** Event name (action name for actions) */ - readonly name: string - - /** Event unique id */ - readonly id: number - - /** Parent action event object */ - readonly parentActionEvent: IMiddlewareEvent | undefined - - /** Event context (node where the action was invoked) */ - readonly context: IAnyStateTreeNode - /** Event tree (root node of the node where the action was invoked) */ - readonly tree: IAnyStateTreeNode - - /** Event arguments in an array (action arguments for actions) */ - readonly args: any[] -} - -/** - * Returns the currently executing MST action context, or undefined if none. - */ -export function getRunningActionContext(): IActionContext | undefined { - let current = getCurrentActionContext() - while (current && current.type !== "action") { - current = current.parentActionEvent - } - return current -} - -function _isActionContextThisOrChildOf( - actionContext: IActionContext, - sameOrParent: number | IActionContext | IMiddlewareEvent, - includeSame: boolean -) { - const parentId = typeof sameOrParent === "number" ? sameOrParent : sameOrParent.id - - let current: IActionContext | IMiddlewareEvent | undefined = includeSame - ? actionContext - : actionContext.parentActionEvent - while (current) { - if (current.id === parentId) { - return true - } - current = current.parentActionEvent - } - return false -} - -/** - * Returns if the given action context is a parent of this action context. - */ -export function isActionContextChildOf( - actionContext: IActionContext, - parent: number | IActionContext | IMiddlewareEvent -) { - return _isActionContextThisOrChildOf(actionContext, parent, false) -} - -/** - * Returns if the given action context is this or a parent of this action context. - */ -export function isActionContextThisOrChildOf( - actionContext: IActionContext, - parentOrThis: number | IActionContext | IMiddlewareEvent -) { - return _isActionContextThisOrChildOf(actionContext, parentOrThis, true) -} diff --git a/packages/mobx-state-tree/src/core/flow.ts b/packages/mobx-state-tree/src/core/flow.ts deleted file mode 100644 index f94aceb44..000000000 --- a/packages/mobx-state-tree/src/core/flow.ts +++ /dev/null @@ -1,204 +0,0 @@ -import { argsToArray, fail, setImmediateWithFallback } from "../utils" -import { - FunctionWithFlag, - getCurrentActionContext, - getNextActionId, - getParentActionContext, - IMiddlewareEventType, - runWithActionContext -} from "./action" - -/** - * @hidden - */ -export type FlowReturn = R extends Promise ? T : R - -/** - * See [asynchronous actions](concepts/async-actions.md). - * - * @returns The flow as a promise. - */ -export function flow( - generator: (...args: Args) => Generator, R, any> -): (...args: Args) => Promise> { - return createFlowSpawner(generator.name, generator) as any -} - -/** - * @deprecated Not needed since TS3.6. - * Used for TypeScript to make flows that return a promise return the actual promise result. - * - * @param val - * @returns - */ -export function castFlowReturn(val: T): T { - return val as any -} - -/** - * @experimental - * experimental api - might change on minor/patch releases - * - * Convert a promise-returning function to a generator-returning one. - * This is intended to allow for usage of `yield*` in async actions to - * retain the promise return type. - * - * Example: - * ```ts - * function getDataAsync(input: string): Promise { ... } - * const getDataGen = toGeneratorFunction(getDataAsync); - * - * const someModel.actions(self => ({ - * someAction: flow(function*() { - * // value is typed as number - * const value = yield* getDataGen("input value"); - * ... - * }) - * })) - * ``` - */ -export function toGeneratorFunction(p: (...args: Args) => Promise) { - return function* (...args: Args) { - return (yield p(...args)) as R - } -} - -/** - * @experimental - * experimental api - might change on minor/patch releases - * - * Convert a promise to a generator yielding that promise - * This is intended to allow for usage of `yield*` in async actions to - * retain the promise return type. - * - * Example: - * ```ts - * function getDataAsync(input: string): Promise { ... } - * - * const someModel.actions(self => ({ - * someAction: flow(function*() { - * // value is typed as number - * const value = yield* toGenerator(getDataAsync("input value")); - * ... - * }) - * })) - * ``` - */ -export function* toGenerator(p: Promise) { - return (yield p) as R -} - -/** - * @internal - * @hidden - */ -export function createFlowSpawner(name: string, generator: FunctionWithFlag) { - const spawner = function flowSpawner(this: any) { - // Implementation based on https://github.com/tj/co/blob/master/index.js - const runId = getNextActionId() - const parentContext = getCurrentActionContext()! - if (!parentContext) { - throw fail("a mst flow must always have a parent context") - } - const parentActionContext = getParentActionContext(parentContext) - if (!parentActionContext) { - throw fail("a mst flow must always have a parent action context") - } - - const contextBase = { - name, - id: runId, - tree: parentContext.tree, - context: parentContext.context, - parentId: parentContext.id, - allParentIds: [...parentContext.allParentIds, parentContext.id], - rootId: parentContext.rootId, - parentEvent: parentContext, - parentActionEvent: parentActionContext - } - - const args = arguments - - function wrap(fn: any, type: IMiddlewareEventType, arg: any) { - fn.$mst_middleware = (spawner as any).$mst_middleware // pick up any middleware attached to the flow - return runWithActionContext( - { - ...contextBase, - type, - args: [arg] - }, - fn - ) - } - - return new Promise(function (resolve, reject) { - let gen: any - const init = function asyncActionInit() { - gen = generator.apply(null, arguments) - onFulfilled(undefined) // kick off the flow - } - ; (init as any).$mst_middleware = (spawner as any).$mst_middleware - - runWithActionContext( - { - ...contextBase, - type: "flow_spawn", - args: argsToArray(args) - }, - init - ) - - function onFulfilled(res: any) { - let ret - try { - // prettier-ignore - const cancelError: any = wrap((r: any) => { ret = gen.next(r) }, "flow_resume", res) - if (cancelError instanceof Error) { - ret = gen.throw(cancelError); - } - } catch (e) { - // prettier-ignore - setImmediateWithFallback(() => { - wrap((r: any) => { reject(e) }, "flow_throw", e) - }) - return - } - next(ret) - return - } - - function onRejected(err: any) { - let ret - try { - // prettier-ignore - wrap((r: any) => { ret = gen.throw(r) }, "flow_resume_error", err) // or yieldError? - } catch (e) { - // prettier-ignore - setImmediateWithFallback(() => { - wrap((r: any) => { reject(e) }, "flow_throw", e) - }) - return - } - next(ret) - } - - function next(ret: any) { - if (ret.done) { - // prettier-ignore - setImmediateWithFallback(() => { - wrap((r: any) => { resolve(r) }, "flow_return", ret.value) - }) - return - } - // TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100 - if (!ret.value || typeof ret.value.then !== "function") { - // istanbul ignore next - throw fail("Only promises can be yielded to `async`, got: " + ret) - } - return ret.value.then(onFulfilled, onRejected) - } - }) - } - ;(spawner as FunctionWithFlag)._isFlowAction = true - return spawner -} diff --git a/packages/mobx-state-tree/src/core/json-patch.ts b/packages/mobx-state-tree/src/core/json-patch.ts deleted file mode 100644 index a87400e5d..000000000 --- a/packages/mobx-state-tree/src/core/json-patch.ts +++ /dev/null @@ -1,144 +0,0 @@ -import { fail, stringStartsWith } from "../internal" - -/** - * https://tools.ietf.org/html/rfc6902 - * http://jsonpatch.com/ - */ -export interface IJsonPatch { - readonly op: "replace" | "add" | "remove" - readonly path: string - readonly value?: any -} - -export interface IReversibleJsonPatch extends IJsonPatch { - readonly oldValue: any // This goes beyond JSON-patch, but makes sure each patch can be inverse applied -} - -/** - * @internal - * @hidden - */ -export function splitPatch(patch: IReversibleJsonPatch): [IJsonPatch, IJsonPatch] { - if (!("oldValue" in patch)) throw fail(`Patches without \`oldValue\` field cannot be inversed`) - return [stripPatch(patch), invertPatch(patch)] -} - -/** - * @internal - * @hidden - */ -export function stripPatch(patch: IReversibleJsonPatch): IJsonPatch { - // strips `oldvalue` information from the patch, so that it becomes a patch conform the json-patch spec - // this removes the ability to undo the patch - switch (patch.op) { - case "add": - return { op: "add", path: patch.path, value: patch.value } - case "remove": - return { op: "remove", path: patch.path } - case "replace": - return { op: "replace", path: patch.path, value: patch.value } - } -} - -function invertPatch(patch: IReversibleJsonPatch): IJsonPatch { - switch (patch.op) { - case "add": - return { - op: "remove", - path: patch.path - } - case "remove": - return { - op: "add", - path: patch.path, - value: patch.oldValue - } - case "replace": - return { - op: "replace", - path: patch.path, - value: patch.oldValue - } - } -} - -/** - * Simple simple check to check it is a number. - */ -function isNumber(x: string): boolean { - return typeof x === "number" -} - -/** - * Escape slashes and backslashes. - * - * http://tools.ietf.org/html/rfc6901 - */ -export function escapeJsonPath(path: string): string { - if (isNumber(path) === true) { - return "" + path - } - if (path.indexOf("/") === -1 && path.indexOf("~") === -1) return path - return path.replace(/~/g, "~0").replace(/\//g, "~1") -} - -/** - * Unescape slashes and backslashes. - */ -export function unescapeJsonPath(path: string): string { - return path.replace(/~1/g, "/").replace(/~0/g, "~") -} - -/** - * Generates a json-path compliant json path from path parts. - * - * @param path - * @returns - */ -export function joinJsonPath(path: string[]): string { - // `/` refers to property with an empty name, while `` refers to root itself! - if (path.length === 0) return "" - - const getPathStr = (p: string[]) => p.map(escapeJsonPath).join("/") - if (path[0] === "." || path[0] === "..") { - // relative - return getPathStr(path) - } else { - // absolute - return "/" + getPathStr(path) - } -} - -/** - * Splits and decodes a json path into several parts. - * - * @param path - * @returns - */ -export function splitJsonPath(path: string): string[] { - // `/` refers to property with an empty name, while `` refers to root itself! - const parts = path.split("/").map(unescapeJsonPath) - - const valid = - path === "" || - path === "." || - path === ".." || - stringStartsWith(path, "/") || - stringStartsWith(path, "./") || - stringStartsWith(path, "../") - if (!valid) { - throw fail(`a json path must be either rooted, empty or relative, but got '${path}'`) - } - - // '/a/b/c' -> ["a", "b", "c"] - // '../../b/c' -> ["..", "..", "b", "c"] - // '' -> [] - // '/' -> [''] - // './a' -> [".", "a"] - // /./a' -> [".", "a"] equivalent to './a' - - if (parts[0] === "") { - parts.shift() - } - return parts -} diff --git a/packages/mobx-state-tree/src/core/node/BaseNode.ts b/packages/mobx-state-tree/src/core/node/BaseNode.ts deleted file mode 100644 index a0d7c4c95..000000000 --- a/packages/mobx-state-tree/src/core/node/BaseNode.ts +++ /dev/null @@ -1,214 +0,0 @@ -import { - AnyObjectNode, - NodeLifeCycle, - Hook, - escapeJsonPath, - EventHandlers, - IAnyType, - IDisposer, - devMode -} from "../../internal" -import { createAtom, IAtom } from "mobx" - -type HookSubscribers = { - [Hook.afterAttach]: (node: AnyNode, hook: Hook) => void - [Hook.afterCreate]: (node: AnyNode, hook: Hook) => void - [Hook.afterCreationFinalization]: (node: AnyNode, hook: Hook) => void - [Hook.beforeDestroy]: (node: AnyNode, hook: Hook) => void - [Hook.beforeDetach]: (node: AnyNode, hook: Hook) => void -} - -/** - * @internal - * @hidden - */ -export abstract class BaseNode { - private _escapedSubpath?: string - - private _subpath!: string - get subpath() { - return this._subpath - } - - private _subpathUponDeath?: string - get subpathUponDeath() { - return this._subpathUponDeath - } - - private _pathUponDeath?: string - protected get pathUponDeath() { - return this._pathUponDeath - } - - storedValue!: any // usually the same type as the value, but not always (such as with references) - get value(): T { - return (this.type as any).getValue(this) - } - - private aliveAtom?: IAtom - private _state = NodeLifeCycle.INITIALIZING - get state() { - return this._state - } - set state(val: NodeLifeCycle) { - const wasAlive = this.isAlive - this._state = val - const isAlive = this.isAlive - - if (this.aliveAtom && wasAlive !== isAlive) { - this.aliveAtom.reportChanged() - } - } - - private _hookSubscribers?: EventHandlers - - protected abstract fireHook(name: Hook): void - - protected fireInternalHook(name: Hook) { - if (this._hookSubscribers) { - this._hookSubscribers.emit(name, this, name) - } - } - - registerHook(hook: H, hookHandler: HookSubscribers[H]): IDisposer { - if (!this._hookSubscribers) { - this._hookSubscribers = new EventHandlers() - } - return this._hookSubscribers.register(hook, hookHandler) - } - - private _parent!: AnyObjectNode | null - get parent() { - return this._parent - } - - constructor( - readonly type: IAnyType, - parent: AnyObjectNode | null, - subpath: string, - public environment: any - ) { - this.environment = environment - this.baseSetParent(parent, subpath) - } - - getReconciliationType() { - return this.type - } - - private pathAtom?: IAtom - protected baseSetParent(parent: AnyObjectNode | null, subpath: string) { - this._parent = parent - this._subpath = subpath - this._escapedSubpath = undefined // regenerate when needed - if (this.pathAtom) { - this.pathAtom.reportChanged() - } - } - - /* - * Returns (escaped) path representation as string - */ - get path(): string { - return this.getEscapedPath(true) - } - - protected getEscapedPath(reportObserved: boolean): string { - if (reportObserved) { - if (!this.pathAtom) { - this.pathAtom = createAtom(`path`) - } - this.pathAtom.reportObserved() - } - if (!this.parent) return "" - // regenerate escaped subpath if needed - if (this._escapedSubpath === undefined) { - this._escapedSubpath = !this._subpath ? "" : escapeJsonPath(this._subpath) - } - return this.parent.getEscapedPath(reportObserved) + "/" + this._escapedSubpath - } - - get isRoot(): boolean { - return this.parent === null - } - - abstract get root(): AnyObjectNode - - abstract setParent(newParent: AnyObjectNode | null, subpath: string | null): void - - abstract get snapshot(): S - abstract getSnapshot(): S - - get isAlive() { - return this.state !== NodeLifeCycle.DEAD - } - - get isDetaching() { - return this.state === NodeLifeCycle.DETACHING - } - - get observableIsAlive() { - if (!this.aliveAtom) { - this.aliveAtom = createAtom(`alive`) - } - this.aliveAtom.reportObserved() - return this.isAlive - } - - abstract die(): void - - abstract finalizeCreation(): void - - protected baseFinalizeCreation(whenFinalized?: () => void) { - if (devMode()) { - if (!this.isAlive) { - // istanbul ignore next - throw fail( - "assertion failed: cannot finalize the creation of a node that is already dead" - ) - } - } - - // goal: afterCreate hooks runs depth-first. After attach runs parent first, so on afterAttach the parent has completed already - if (this.state === NodeLifeCycle.CREATED) { - if (this.parent) { - if (this.parent.state !== NodeLifeCycle.FINALIZED) { - // parent not ready yet, postpone - return - } - this.fireHook(Hook.afterAttach) - } - - this.state = NodeLifeCycle.FINALIZED - - if (whenFinalized) { - whenFinalized() - } - } - } - - abstract finalizeDeath(): void - - protected baseFinalizeDeath() { - if (this._hookSubscribers) { - this._hookSubscribers.clearAll() - } - - this._subpathUponDeath = this._subpath - this._pathUponDeath = this.getEscapedPath(false) - this.baseSetParent(null, "") - this.state = NodeLifeCycle.DEAD - } - - abstract aboutToDie(): void - - protected baseAboutToDie() { - this.fireHook(Hook.beforeDestroy) - } -} - -/** - * @internal - * @hidden - */ -export type AnyNode = BaseNode diff --git a/packages/mobx-state-tree/src/core/node/Hook.ts b/packages/mobx-state-tree/src/core/node/Hook.ts deleted file mode 100644 index fc531f8a8..000000000 --- a/packages/mobx-state-tree/src/core/node/Hook.ts +++ /dev/null @@ -1,19 +0,0 @@ -/** - * @hidden - */ -export enum Hook { - afterCreate = "afterCreate", - afterAttach = "afterAttach", - afterCreationFinalization = "afterCreationFinalization", - beforeDetach = "beforeDetach", - beforeDestroy = "beforeDestroy" -} - -export interface IHooks { - [Hook.afterCreate]?: () => void - [Hook.afterAttach]?: () => void - [Hook.beforeDetach]?: () => void - [Hook.beforeDestroy]?: () => void -} - -export type IHooksGetter = (self: T) => IHooks diff --git a/packages/mobx-state-tree/src/core/node/create-node.ts b/packages/mobx-state-tree/src/core/node/create-node.ts deleted file mode 100644 index e949dd02f..000000000 --- a/packages/mobx-state-tree/src/core/node/create-node.ts +++ /dev/null @@ -1,66 +0,0 @@ -import { - fail, - ObjectNode, - ScalarNode, - AnyNode, - getStateTreeNodeSafe, - AnyObjectNode, - ComplexType, - SimpleType -} from "../../internal" - -/** - * @internal - * @hidden - */ -export function createObjectNode( - type: ComplexType, - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C | T -): ObjectNode { - const existingNode = getStateTreeNodeSafe(initialValue) - if (existingNode) { - if (existingNode.parent) { - // istanbul ignore next - throw fail( - `Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${ - parent ? parent.path : "" - }/${subpath}', but it lives already at '${existingNode.path}'` - ) - } - - if (parent) { - existingNode.setParent(parent, subpath) - } - // else it already has no parent since it is a pre-requisite - - return existingNode - } - - // not a node, a snapshot - return new ObjectNode(type, parent, subpath, environment, initialValue as C) -} - -/** - * @internal - * @hidden - */ -export function createScalarNode( - type: SimpleType, - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C -): ScalarNode { - return new ScalarNode(type, parent, subpath, environment, initialValue) -} - -/** - * @internal - * @hidden - */ -export function isNode(value: any): value is AnyNode { - return value instanceof ScalarNode || value instanceof ObjectNode -} diff --git a/packages/mobx-state-tree/src/core/node/identifier-cache.ts b/packages/mobx-state-tree/src/core/node/identifier-cache.ts deleted file mode 100644 index 17ee85688..000000000 --- a/packages/mobx-state-tree/src/core/node/identifier-cache.ts +++ /dev/null @@ -1,126 +0,0 @@ -import { IObservableArray, values, observable, entries } from "mobx" -import { fail, ObjectNode, mobxShallow, AnyObjectNode, IAnyComplexType } from "../../internal" - -let identifierCacheId = 0 - -/** - * @internal - * @hidden - */ -export class IdentifierCache { - private cacheId = identifierCacheId++ - - // n.b. in cache all identifiers are normalized to strings - private cache = observable.map>() - - // last time the cache (array) for a given time changed - // n.b. it is not really the time, but just an integer that gets increased after each modification to the array - private lastCacheModificationPerId = observable.map() - - constructor() {} - - private updateLastCacheModificationPerId(identifier: string) { - const lcm = this.lastCacheModificationPerId.get(identifier) - // we start at 1 since 0 means no update since cache creation - this.lastCacheModificationPerId.set(identifier, lcm === undefined ? 1 : lcm + 1) - } - - getLastCacheModificationPerId(identifier: string): string { - const modificationId = this.lastCacheModificationPerId.get(identifier) || 0 - return `${this.cacheId}-${modificationId}` - } - - addNodeToCache(node: AnyObjectNode, lastCacheUpdate = true): void { - if (node.identifierAttribute) { - const identifier = node.identifier! - if (!this.cache.has(identifier)) { - this.cache.set(identifier, observable.array([], mobxShallow)) - } - const set = this.cache.get(identifier)! - if (set.indexOf(node) !== -1) throw fail(`Already registered`) - set.push(node) - if (lastCacheUpdate) { - this.updateLastCacheModificationPerId(identifier) - } - } - } - - mergeCache(node: AnyObjectNode) { - values(node.identifierCache!.cache).forEach((nodes) => - nodes.forEach((child) => { - this.addNodeToCache(child) - }) - ) - } - - notifyDied(node: AnyObjectNode) { - if (node.identifierAttribute) { - const id = node.identifier! - const set = this.cache.get(id) - if (set) { - set.remove(node) - // remove empty sets from cache - if (!set.length) { - this.cache.delete(id) - } - this.updateLastCacheModificationPerId(node.identifier!) - } - } - } - - splitCache(splitNode: AnyObjectNode): IdentifierCache { - const newCache = new IdentifierCache() - // The slash is added here so we only match children of the splitNode. In version 5.1.8 and - // earlier there was no trailing slash, so non children that started with the same path string - // were being matched incorrectly. - const basePath = splitNode.path + "/" - entries(this.cache).forEach(([id, nodes]) => { - let modified = false - for (let i = nodes.length - 1; i >= 0; i--) { - const node = nodes[i] - if (node === splitNode || node.path.indexOf(basePath) === 0) { - newCache.addNodeToCache(node, false) // no need to update lastUpdated since it is a whole new cache - nodes.splice(i, 1) - // remove empty sets from cache - if (!nodes.length) { - this.cache.delete(id) - } - modified = true - } - } - if (modified) { - this.updateLastCacheModificationPerId(id) - } - }) - return newCache - } - - has(type: IAnyComplexType, identifier: string): boolean { - const set = this.cache.get(identifier) - if (!set) return false - return set.some((candidate) => type.isAssignableFrom(candidate.type)) - } - - resolve( - type: IT, - identifier: string - ): ObjectNode | null { - const set = this.cache.get(identifier) - if (!set) return null - const matches = set.filter((candidate) => type.isAssignableFrom(candidate.type)) - switch (matches.length) { - case 0: - return null - case 1: - return matches[0] - default: - throw fail( - `Cannot resolve a reference to type '${ - type.name - }' with id: '${identifier}' unambigously, there are multiple candidates: ${matches - .map((n) => n.path) - .join(", ")}` - ) - } - } -} diff --git a/packages/mobx-state-tree/src/core/node/node-utils.ts b/packages/mobx-state-tree/src/core/node/node-utils.ts deleted file mode 100644 index 122938c27..000000000 --- a/packages/mobx-state-tree/src/core/node/node-utils.ts +++ /dev/null @@ -1,217 +0,0 @@ -import { - fail, - ObjectNode, - splitJsonPath, - joinJsonPath, - ScalarNode, - IChildNodesMap, - EMPTY_ARRAY, - AnyObjectNode, - AnyNode, - IAnyType, - IType, - assertArg, - STNValue, - Instance, - IAnyComplexType -} from "../../internal" - -/** - * @internal - * @hidden - */ -export enum NodeLifeCycle { - INITIALIZING, // setting up - CREATED, // afterCreate has run - FINALIZED, // afterAttach has run - DETACHING, // being detached from the tree - DEAD // no coming back from this one -} - -/** @hidden */ -declare const $stateTreeNodeType: unique symbol - -/** - * Common interface that represents a node instance. - * @hidden - */ -export interface IStateTreeNode { - /** - * @internal - */ - readonly $treenode?: any - - // fake, will never be present, just for typing - // we use this weird trick to solve an issue with reference types - readonly [$stateTreeNodeType]?: [IT] | [any] -} - -/** @hidden */ -export type TypeOfValue = T extends IStateTreeNode - ? IT - : never - -/** - * Represents any state tree node instance. - * @hidden - */ -export interface IAnyStateTreeNode extends STNValue {} - -/** - * Returns true if the given value is a node in a state tree. - * More precisely, that is, if the value is an instance of a - * `types.model`, `types.array` or `types.map`. - * - * @param value - * @returns true if the value is a state tree node. - */ -export function isStateTreeNode( - value: any -): value is STNValue, IT> { - return !!(value && value.$treenode) -} - -/** - * @internal - * @hidden - */ -export function assertIsStateTreeNode( - value: IAnyStateTreeNode, - argNumber: number | number[] -): void { - assertArg(value, isStateTreeNode, "mobx-state-tree node", argNumber) -} - -/** - * @internal - * @hidden - */ -export function getStateTreeNode(value: IAnyStateTreeNode): AnyObjectNode { - if (!isStateTreeNode(value)) { - // istanbul ignore next - throw fail(`Value ${value} is no MST Node`) - } - return value.$treenode! -} - -/** - * @internal - * @hidden - */ -export function getStateTreeNodeSafe(value: IAnyStateTreeNode): AnyObjectNode | null { - return (value && value.$treenode) || null -} - -/** - * @internal - * @hidden - */ -export function toJSON(this: IStateTreeNode>): S { - return getStateTreeNode(this).snapshot -} - -const doubleDot = (_: any) => ".." - -/** - * @internal - * @hidden - */ -export function getRelativePathBetweenNodes(base: AnyObjectNode, target: AnyObjectNode): string { - // PRE condition target is (a child of) base! - if (base.root !== target.root) { - throw fail( - `Cannot calculate relative path: objects '${base}' and '${target}' are not part of the same object tree` - ) - } - - const baseParts = splitJsonPath(base.path) - const targetParts = splitJsonPath(target.path) - let common = 0 - for (; common < baseParts.length; common++) { - if (baseParts[common] !== targetParts[common]) break - } - // TODO: assert that no targetParts paths are "..", "." or ""! - return ( - baseParts.slice(common).map(doubleDot).join("/") + joinJsonPath(targetParts.slice(common)) - ) -} - -/** - * @internal - * @hidden - */ -export function resolveNodeByPath( - base: AnyObjectNode, - path: string, - failIfResolveFails: boolean = true -): AnyNode | undefined { - return resolveNodeByPathParts(base, splitJsonPath(path), failIfResolveFails) -} - -/** - * @internal - * @hidden - */ -export function resolveNodeByPathParts( - base: AnyObjectNode, - pathParts: string[], - failIfResolveFails: boolean = true -): AnyNode | undefined { - let current: AnyNode | null = base - try { - for (let i = 0; i < pathParts.length; i++) { - const part = pathParts[i] - if (part === "..") { - current = current!.parent - if (current) continue // not everything has a parent - } else if (part === ".") { - continue - } else if (current) { - if (current instanceof ScalarNode) { - // check if the value of a scalar resolves to a state tree node (e.g. references) - // then we can continue resolving... - const value: any = current.value - if (isStateTreeNode(value)) { - current = getStateTreeNode(value) - // fall through - } - } - if (current instanceof ObjectNode) { - const subType = current.getChildType(part) - if (subType) { - current = current.getChildNode(part) - if (current) continue - } - } - } - throw fail( - `Could not resolve '${part}' in path '${ - joinJsonPath(pathParts.slice(0, i)) || "/" - }' while resolving '${joinJsonPath(pathParts)}'` - ) - } - } catch (e) { - if (!failIfResolveFails) { - return undefined - } - throw e - } - return current! -} - -/** - * @internal - * @hidden - */ -export function convertChildNodesToArray(childNodes: IChildNodesMap | null): AnyNode[] { - if (!childNodes) return EMPTY_ARRAY as AnyNode[] - - const keys = Object.keys(childNodes) - if (!keys.length) return EMPTY_ARRAY as AnyNode[] - - const result = new Array(keys.length) as AnyNode[] - keys.forEach((key, index) => { - result[index] = childNodes![key] - }) - return result -} diff --git a/packages/mobx-state-tree/src/core/node/object-node.ts b/packages/mobx-state-tree/src/core/node/object-node.ts deleted file mode 100644 index 9624e1364..000000000 --- a/packages/mobx-state-tree/src/core/node/object-node.ts +++ /dev/null @@ -1,740 +0,0 @@ -// noinspection ES6UnusedImports -import { action, computed, IComputedValue, reaction, _allowStateChangesInsideComputed } from "mobx" -import { - addHiddenFinalProp, - ComplexType, - convertChildNodesToArray, - createActionInvoker, - EMPTY_OBJECT, - extend, - fail, - freeze, - IAnyType, - IdentifierCache, - IDisposer, - IJsonPatch, - IMiddleware, - IMiddlewareHandler, - IReversibleJsonPatch, - NodeLifeCycle, - resolveNodeByPathParts, - splitJsonPath, - splitPatch, - toJSON, - EventHandlers, - Hook, - BaseNode, - getLivelinessChecking, - normalizeIdentifier, - ReferenceIdentifier, - IMiddlewareEvent, - escapeJsonPath, - getPath, - warnError, - AnyNode, - IStateTreeNode, - ArgumentTypes, - IType, - devMode, - getCurrentActionContext -} from "../../internal" - -let nextNodeId = 1 - -const enum ObservableInstanceLifecycle { - // the actual observable instance has not been created yet - UNINITIALIZED, - // the actual observable instance is being created - CREATING, - // the actual observable instance has been created - CREATED -} - -const enum InternalEvents { - Dispose = "dispose", - Patch = "patch", - Snapshot = "snapshot" -} - -/** - * @internal - * @hidden - */ -export interface IChildNodesMap { - [key: string]: AnyNode -} - -const snapshotReactionOptions = { - onError(e: any) { - throw e - } -} - -type InternalEventHandlers = { - [InternalEvents.Dispose]: IDisposer - [InternalEvents.Patch]: (patch: IJsonPatch, reversePatch: IJsonPatch) => void - [InternalEvents.Snapshot]: (snapshot: S) => void -} - -/** - * @internal - * @hidden - */ -export class ObjectNode extends BaseNode { - declare readonly type: ComplexType - declare storedValue: T & IStateTreeNode> - - readonly nodeId = ++nextNodeId - readonly identifierAttribute?: string - readonly identifier: string | null // Identifier is always normalized to string, even if the identifier property isn't - readonly unnormalizedIdentifier: ReferenceIdentifier | null - - identifierCache?: IdentifierCache - isProtectionEnabled = true - middlewares?: IMiddleware[] - - private _applyPatches?: (patches: IJsonPatch[]) => void - - applyPatches(patches: IJsonPatch[]): void { - this.createObservableInstanceIfNeeded() - this._applyPatches!(patches) - } - - private _applySnapshot?: (snapshot: C) => void - - applySnapshot(snapshot: C): void { - this.createObservableInstanceIfNeeded() - this._applySnapshot!(snapshot) - } - - private _autoUnbox = true // unboxing is disabled when reading child nodes - _isRunningAction = false // only relevant for root - private _hasSnapshotReaction = false - - private _observableInstanceState = ObservableInstanceLifecycle.UNINITIALIZED - private _childNodes: IChildNodesMap - private _initialSnapshot: C - private _cachedInitialSnapshot?: S - private _cachedInitialSnapshotCreated = false - private _snapshotComputed: IComputedValue - - constructor( - complexType: ComplexType, - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C - ) { - super(complexType, parent, subpath, environment) - this._snapshotComputed = computed(() => freeze(this.getSnapshot())) - - this.unbox = this.unbox.bind(this) - - this._initialSnapshot = freeze(initialValue) - this.identifierAttribute = complexType.identifierAttribute - - if (!parent) { - this.identifierCache = new IdentifierCache() - } - - this._childNodes = complexType.initializeChildNodes(this, this._initialSnapshot) - - // identifier can not be changed during lifecycle of a node - // so we safely can read it from initial snapshot - this.identifier = null - this.unnormalizedIdentifier = null - if (this.identifierAttribute && this._initialSnapshot) { - let id = (this._initialSnapshot as any)[this.identifierAttribute] - if (id === undefined) { - // try with the actual node if not (for optional identifiers) - const childNode = this._childNodes[this.identifierAttribute] - if (childNode) { - id = childNode.value - } - } - - if (typeof id !== "string" && typeof id !== "number") { - throw fail( - `Instance identifier '${this.identifierAttribute}' for type '${this.type.name}' must be a string or a number` - ) - } - - // normalize internal identifier to string - this.identifier = normalizeIdentifier(id) - this.unnormalizedIdentifier = id - } - - if (!parent) { - this.identifierCache!.addNodeToCache(this) - } else { - parent.root.identifierCache!.addNodeToCache(this) - } - } - - createObservableInstanceIfNeeded(fireHooks = true): void { - if (this._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED) { - this.createObservableInstance(fireHooks) - } - } - - createObservableInstance(fireHooks = true): void { - if (devMode()) { - if (this.state !== NodeLifeCycle.INITIALIZING) { - // istanbul ignore next - throw fail( - "assertion failed: the creation of the observable instance must be done on the initializing phase" - ) - } - } - this._observableInstanceState = ObservableInstanceLifecycle.CREATING - - // make sure the parent chain is created as well - - // array with parent chain from parent to child - const parentChain = [] - - let parent = this.parent - // for performance reasons we never go back further than the most direct - // uninitialized parent - // this is done to avoid traversing the whole tree to the root when using - // the same reference again - while ( - parent && - parent._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED - ) { - parentChain.unshift(parent) - parent = parent.parent - } - - // initialize the uninitialized parent chain from parent to child - for (const p of parentChain) { - // delay firing hooks until after all parents have been created - p.createObservableInstanceIfNeeded(false) - } - - const type = this.type - - try { - this.storedValue = type.createNewInstance(this._childNodes) - this.preboot() - - this._isRunningAction = true - type.finalizeNewInstance(this, this.storedValue) - } catch (e) { - // short-cut to die the instance, to avoid the snapshot computed starting to throw... - this.state = NodeLifeCycle.DEAD - throw e - } finally { - this._isRunningAction = false - } - - this._observableInstanceState = ObservableInstanceLifecycle.CREATED - - // NOTE: we need to touch snapshot, because non-observable - // "_observableInstanceState" field was touched - ;(this._snapshotComputed as any).trackAndCompute() - - if (this.isRoot) this._addSnapshotReaction() - - this._childNodes = EMPTY_OBJECT - - this.state = NodeLifeCycle.CREATED - - if (fireHooks) { - this.fireHook(Hook.afterCreate) - // Note that the parent might not be finalized at this point - // so afterAttach won't be called until later in that case - this.finalizeCreation() - - // fire the hooks of the parents that we created - for (const p of parentChain.reverse()) { - p.fireHook(Hook.afterCreate) - // This will call afterAttach on the child if necessary - p.finalizeCreation() - } - } - } - - get root(): AnyObjectNode { - const parent = this.parent - return parent ? parent.root : this - } - - clearParent(): void { - if (!this.parent) return - - // detach if attached - this.fireHook(Hook.beforeDetach) - const previousState = this.state - this.state = NodeLifeCycle.DETACHING - - const root = this.root - const newEnv = root.environment - const newIdCache = root.identifierCache!.splitCache(this) - - try { - this.parent.removeChild(this.subpath) - this.baseSetParent(null, "") - this.environment = newEnv - this.identifierCache = newIdCache - } finally { - this.state = previousState - } - } - - setParent(newParent: AnyObjectNode, subpath: string): void { - const parentChanged = newParent !== this.parent - const subpathChanged = subpath !== this.subpath - - if (!parentChanged && !subpathChanged) { - return - } - - if (devMode()) { - if (!subpath) { - // istanbul ignore next - throw fail("assertion failed: subpath expected") - } - if (!newParent) { - // istanbul ignore next - throw fail("assertion failed: new parent expected") - } - - if (this.parent && parentChanged) { - throw fail( - `A node cannot exists twice in the state tree. Failed to add ${this} to path '${newParent.path}/${subpath}'.` - ) - } - if (!this.parent && newParent.root === this) { - throw fail( - `A state tree is not allowed to contain itself. Cannot assign ${this} to path '${newParent.path}/${subpath}'` - ) - } - if ( - !this.parent && - !!this.environment && - this.environment !== newParent.root.environment - ) { - throw fail( - `A state tree cannot be made part of another state tree as long as their environments are different.` - ) - } - } - - if (parentChanged) { - // attach to new parent - this.environment = undefined // will use root's - newParent.root.identifierCache!.mergeCache(this) - this.baseSetParent(newParent, subpath) - this.fireHook(Hook.afterAttach) - } else if (subpathChanged) { - // moving to a new subpath on the same parent - this.baseSetParent(this.parent, subpath) - } - } - - protected fireHook(name: Hook): void { - this.fireInternalHook(name) - - const fn = - this.storedValue && - typeof this.storedValue === "object" && - (this.storedValue as any)[name] - if (typeof fn === "function") { - // we check for it to allow old mobx peer dependencies that don't have the method to work (even when still bugged) - if (_allowStateChangesInsideComputed) { - _allowStateChangesInsideComputed(() => { - fn.apply(this.storedValue) - }) - } else { - fn.apply(this.storedValue) - } - } - } - - private _snapshotUponDeath?: S - - // advantage of using computed for a snapshot is that nicely respects transactions etc. - get snapshot(): S { - return this._snapshotComputed.get() - } - - // NOTE: we use this method to get snapshot without creating @computed overhead - getSnapshot(): S { - if (!this.isAlive) return this._snapshotUponDeath! - return this._observableInstanceState === ObservableInstanceLifecycle.CREATED - ? this._getActualSnapshot() - : this._getCachedInitialSnapshot() - } - - private _getActualSnapshot(): S { - return this.type.getSnapshot(this) - } - - private _getCachedInitialSnapshot(): S { - if (!this._cachedInitialSnapshotCreated) { - const type = this.type - const childNodes = this._childNodes - const snapshot = this._initialSnapshot - - this._cachedInitialSnapshot = type.processInitialSnapshot(childNodes, snapshot) - this._cachedInitialSnapshotCreated = true - } - - return this._cachedInitialSnapshot! - } - - private isRunningAction(): boolean { - if (this._isRunningAction) return true - if (this.isRoot) return false - return this.parent!.isRunningAction() - } - - assertAlive(context: AssertAliveContext): void { - const livelinessChecking = getLivelinessChecking() - if (!this.isAlive && livelinessChecking !== "ignore") { - const error = this._getAssertAliveError(context) - switch (livelinessChecking) { - case "error": - throw fail(error) - case "warn": - warnError(error) - } - } - } - - private _getAssertAliveError(context: AssertAliveContext): string { - const escapedPath = this.getEscapedPath(false) || this.pathUponDeath || "" - const subpath = (context.subpath && escapeJsonPath(context.subpath)) || "" - - let actionContext = context.actionContext || getCurrentActionContext() - - // try to use a real action context if possible since it includes the action name - if (actionContext && actionContext.type !== "action" && actionContext.parentActionEvent) { - actionContext = actionContext.parentActionEvent - } - - let actionFullPath = "" - if (actionContext && actionContext.name != null) { - // try to use the context, and if it not available use the node one - const actionPath = - (actionContext && actionContext.context && getPath(actionContext.context)) || - escapedPath - actionFullPath = `${actionPath}.${actionContext.name}()` - } - - return `You are trying to read or write to an object that is no longer part of a state tree. (Object type: '${this.type.name}', Path upon death: '${escapedPath}', Subpath: '${subpath}', Action: '${actionFullPath}'). Either detach nodes first, or don't use objects after removing / replacing them in the tree.` - } - - getChildNode(subpath: string): AnyNode { - this.assertAlive({ - subpath - }) - this._autoUnbox = false - try { - return this._observableInstanceState === ObservableInstanceLifecycle.CREATED - ? this.type.getChildNode(this, subpath) - : this._childNodes![subpath] - } finally { - this._autoUnbox = true - } - } - - getChildren(): ReadonlyArray { - this.assertAlive(EMPTY_OBJECT) - this._autoUnbox = false - try { - return this._observableInstanceState === ObservableInstanceLifecycle.CREATED - ? this.type.getChildren(this) - : convertChildNodesToArray(this._childNodes) - } finally { - this._autoUnbox = true - } - } - - getChildType(propertyName?: string): IAnyType { - return this.type.getChildType(propertyName) - } - - get isProtected(): boolean { - return this.root.isProtectionEnabled - } - - assertWritable(context: AssertAliveContext): void { - this.assertAlive(context) - if (!this.isRunningAction() && this.isProtected) { - throw fail( - `Cannot modify '${this}', the object is protected and can only be modified by using an action.` - ) - } - } - - removeChild(subpath: string): void { - this.type.removeChild(this, subpath) - } - - // bound on the constructor - unbox(childNode: AnyNode | undefined): AnyNode | undefined { - if (!childNode) return childNode - - this.assertAlive({ - subpath: childNode.subpath || childNode.subpathUponDeath - }) - return this._autoUnbox ? childNode.value : childNode - } - - toString(): string { - const path = (this.isAlive ? this.path : this.pathUponDeath) || "" - const identifier = this.identifier ? `(id: ${this.identifier})` : "" - return `${this.type.name}@${path}${identifier}${this.isAlive ? "" : " [dead]"}` - } - - finalizeCreation(): void { - this.baseFinalizeCreation(() => { - for (let child of this.getChildren()) { - child.finalizeCreation() - } - - this.fireInternalHook(Hook.afterCreationFinalization) - }) - } - - detach(): void { - if (!this.isAlive) throw fail(`Error while detaching, node is not alive.`) - - this.clearParent() - } - - private preboot(): void { - const self = this - this._applyPatches = createActionInvoker( - this.storedValue, - "@APPLY_PATCHES", - (patches: IJsonPatch[]) => { - patches.forEach((patch) => { - if (!patch.path) { - self.type.applySnapshot(self, patch.value) - return - } - const parts = splitJsonPath(patch.path) - const node = resolveNodeByPathParts(self, parts.slice(0, -1)) as AnyObjectNode - node.applyPatchLocally(parts[parts.length - 1], patch) - }) - } - ) - this._applySnapshot = createActionInvoker( - this.storedValue, - "@APPLY_SNAPSHOT", - (snapshot: C) => { - // if the snapshot is the same as the current one, avoid performing a reconcile - if (snapshot === (self.snapshot as any)) return - // else, apply it by calling the type logic - return self.type.applySnapshot(self, snapshot as any) - } - ) - - addHiddenFinalProp(this.storedValue, "$treenode", this) - addHiddenFinalProp(this.storedValue, "toJSON", toJSON) - } - - die(): void { - if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) return - this.aboutToDie() - this.finalizeDeath() - } - - aboutToDie(): void { - if (this._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED) { - return - } - - this.getChildren().forEach((node) => { - node.aboutToDie() - }) - - // beforeDestroy should run before the disposers since else we could end up in a situation where - // a disposer added with addDisposer at this stage (beforeDestroy) is actually never released - this.baseAboutToDie() - - this._internalEventsEmit(InternalEvents.Dispose) - this._internalEventsClear(InternalEvents.Dispose) - } - - finalizeDeath(): void { - // invariant: not called directly but from "die" - this.getChildren().forEach((node) => { - node.finalizeDeath() - }) - this.root.identifierCache!.notifyDied(this) - - // "kill" the computed prop and just store the last snapshot - const snapshot = this.snapshot - this._snapshotUponDeath = snapshot - - this._internalEventsClearAll() - - this.baseFinalizeDeath() - } - - onSnapshot(onChange: (snapshot: S) => void): IDisposer { - this._addSnapshotReaction() - return this._internalEventsRegister(InternalEvents.Snapshot, onChange) - } - - protected emitSnapshot(snapshot: S): void { - this._internalEventsEmit(InternalEvents.Snapshot, snapshot) - } - - onPatch(handler: (patch: IJsonPatch, reversePatch: IJsonPatch) => void): IDisposer { - return this._internalEventsRegister(InternalEvents.Patch, handler) - } - - emitPatch(basePatch: IReversibleJsonPatch, source: AnyNode): void { - if (this._internalEventsHasSubscribers(InternalEvents.Patch)) { - const localizedPatch: IReversibleJsonPatch = extend({}, basePatch, { - path: source.path.substr(this.path.length) + "/" + basePatch.path // calculate the relative path of the patch - }) - const [patch, reversePatch] = splitPatch(localizedPatch) - this._internalEventsEmit(InternalEvents.Patch, patch, reversePatch) - } - if (this.parent) this.parent.emitPatch(basePatch, source) - } - - hasDisposer(disposer: () => void): boolean { - return this._internalEventsHas(InternalEvents.Dispose, disposer) - } - - addDisposer(disposer: () => void): void { - if (!this.hasDisposer(disposer)) { - this._internalEventsRegister(InternalEvents.Dispose, disposer, true) - return - } - throw fail("cannot add a disposer when it is already registered for execution") - } - - removeDisposer(disposer: () => void): void { - if (!this._internalEventsHas(InternalEvents.Dispose, disposer)) { - throw fail("cannot remove a disposer which was never registered for execution") - } - this._internalEventsUnregister(InternalEvents.Dispose, disposer) - } - - private removeMiddleware(middleware: IMiddleware): void { - if (this.middlewares) { - const index = this.middlewares.indexOf(middleware) - if (index >= 0) { - this.middlewares.splice(index, 1) - } - } - } - - addMiddleWare(handler: IMiddlewareHandler, includeHooks: boolean = true): IDisposer { - const middleware = { handler, includeHooks } - if (!this.middlewares) this.middlewares = [middleware] - else this.middlewares.push(middleware) - - return () => { - this.removeMiddleware(middleware) - } - } - - applyPatchLocally(subpath: string, patch: IJsonPatch): void { - this.assertWritable({ - subpath - }) - this.createObservableInstanceIfNeeded() - this.type.applyPatchLocally(this, subpath, patch) - } - - private _addSnapshotReaction(): void { - if (!this._hasSnapshotReaction) { - const snapshotDisposer = reaction( - () => this.snapshot, - (snapshot) => this.emitSnapshot(snapshot), - snapshotReactionOptions - ) - this.addDisposer(snapshotDisposer) - this._hasSnapshotReaction = true - } - } - - // #region internal event handling - - private _internalEvents?: EventHandlers> - - // we proxy the methods to avoid creating an EventHandlers instance when it is not needed - - private _internalEventsHasSubscribers(event: InternalEvents): boolean { - return !!this._internalEvents && this._internalEvents.hasSubscribers(event) - } - - private _internalEventsRegister( - event: IE, - eventHandler: InternalEventHandlers[IE], - atTheBeginning = false - ): IDisposer { - if (!this._internalEvents) { - this._internalEvents = new EventHandlers() - } - return this._internalEvents.register(event, eventHandler, atTheBeginning) - } - - private _internalEventsHas( - event: IE, - eventHandler: InternalEventHandlers[IE] - ): boolean { - return !!this._internalEvents && this._internalEvents.has(event, eventHandler) - } - - private _internalEventsUnregister( - event: IE, - eventHandler: InternalEventHandlers[IE] - ): void { - if (this._internalEvents) { - this._internalEvents.unregister(event, eventHandler) - } - } - - private _internalEventsEmit( - event: IE, - ...args: ArgumentTypes[IE]> - ): void { - if (this._internalEvents) { - this._internalEvents.emit(event, ...args) - } - } - - private _internalEventsClear(event: InternalEvents): void { - if (this._internalEvents) { - this._internalEvents.clear(event) - } - } - - private _internalEventsClearAll(): void { - if (this._internalEvents) { - this._internalEvents.clearAll() - } - } - - // #endregion -} -ObjectNode.prototype.createObservableInstance = action( - ObjectNode.prototype.createObservableInstance -) -ObjectNode.prototype.detach = action(ObjectNode.prototype.detach) -ObjectNode.prototype.die = action(ObjectNode.prototype.die) - -/** - * @internal - * @hidden - */ -export type AnyObjectNode = ObjectNode - -/** - * @internal - * @hidden - */ -export interface AssertAliveContext { - subpath?: string - actionContext?: IMiddlewareEvent -} diff --git a/packages/mobx-state-tree/src/core/node/scalar-node.ts b/packages/mobx-state-tree/src/core/node/scalar-node.ts deleted file mode 100644 index d198de551..000000000 --- a/packages/mobx-state-tree/src/core/node/scalar-node.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { - fail, - freeze, - NodeLifeCycle, - Hook, - BaseNode, - AnyObjectNode, - SimpleType, - devMode -} from "../../internal" -import { action } from "mobx" - -/** - * @internal - * @hidden - */ -export class ScalarNode extends BaseNode { - // note about hooks: - // - afterCreate is not emmited in scalar nodes, since it would be emitted in the - // constructor, before it can be subscribed by anybody - // - afterCreationFinalization could be emitted, but there's no need for it right now - // - beforeDetach is never emitted for scalar nodes, since they cannot be detached - - declare readonly type: SimpleType - - constructor( - simpleType: SimpleType, - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialSnapshot: C - ) { - super(simpleType, parent, subpath, environment) - try { - this.storedValue = simpleType.createNewInstance(initialSnapshot) - } catch (e) { - // short-cut to die the instance, to avoid the snapshot computed starting to throw... - this.state = NodeLifeCycle.DEAD - throw e - } - - this.state = NodeLifeCycle.CREATED - // for scalar nodes there's no point in firing this event since it would fire on the constructor, before - // anybody can actually register for/listen to it - // this.fireHook(Hook.AfterCreate) - - this.finalizeCreation() - } - - get root(): AnyObjectNode { - // future optimization: store root ref in the node and maintain it - if (!this.parent) throw fail(`This scalar node is not part of a tree`) - return this.parent.root - } - - setParent(newParent: AnyObjectNode, subpath: string): void { - const parentChanged = this.parent !== newParent - const subpathChanged = this.subpath !== subpath - - if (!parentChanged && !subpathChanged) { - return - } - - if (devMode()) { - if (!subpath) { - // istanbul ignore next - throw fail("assertion failed: subpath expected") - } - if (!newParent) { - // istanbul ignore next - throw fail("assertion failed: parent expected") - } - if (parentChanged) { - // istanbul ignore next - throw fail("assertion failed: scalar nodes cannot change their parent") - } - } - - this.environment = undefined // use parent's - this.baseSetParent(this.parent, subpath) - } - - get snapshot(): S { - return freeze(this.getSnapshot()) - } - - getSnapshot(): S { - return this.type.getSnapshot(this) - } - - toString(): string { - const path = (this.isAlive ? this.path : this.pathUponDeath) || "" - return `${this.type.name}@${path}${this.isAlive ? "" : " [dead]"}` - } - - die(): void { - if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) return - this.aboutToDie() - this.finalizeDeath() - } - - finalizeCreation(): void { - this.baseFinalizeCreation() - } - - aboutToDie(): void { - this.baseAboutToDie() - } - - finalizeDeath(): void { - this.baseFinalizeDeath() - } - - protected fireHook(name: Hook): void { - this.fireInternalHook(name) - } -} -ScalarNode.prototype.die = action(ScalarNode.prototype.die) diff --git a/packages/mobx-state-tree/src/core/type/type-checker.ts b/packages/mobx-state-tree/src/core/type/type-checker.ts deleted file mode 100644 index 6f60e5dda..000000000 --- a/packages/mobx-state-tree/src/core/type/type-checker.ts +++ /dev/null @@ -1,188 +0,0 @@ -import { - fail, - EMPTY_ARRAY, - isPrimitive, - getStateTreeNode, - isStateTreeNode, - isPrimitiveType, - IAnyType, - ExtractCSTWithSTN, - isTypeCheckingEnabled, - devMode -} from "../../internal" - -/** Validation context entry, this is, where the validation should run against which type */ -export interface IValidationContextEntry { - /** Subpath where the validation should be run, or an empty string to validate it all */ - path: string - /** Type to validate the subpath against */ - type: IAnyType -} - -/** Array of validation context entries */ -export type IValidationContext = IValidationContextEntry[] - -/** Type validation error */ -export interface IValidationError { - /** Validation context */ - context: IValidationContext - /** Value that was being validated, either a snapshot or an instance */ - value: any - /** Error message */ - message?: string -} - -/** Type validation result, which is an array of type validation errors */ -export type IValidationResult = IValidationError[] - -function safeStringify(value: any) { - try { - return JSON.stringify(value) - } catch (e) { - // istanbul ignore next - return `` - } -} - -/** - * @internal - * @hidden - */ -export function prettyPrintValue(value: any) { - return typeof value === "function" - ? `` - : isStateTreeNode(value) - ? `<${value}>` - : `\`${safeStringify(value)}\`` -} - -function shortenPrintValue(valueInString: string) { - return valueInString.length < 280 - ? valueInString - : `${valueInString.substring(0, 272)}......${valueInString.substring( - valueInString.length - 8 - )}` -} - -function toErrorString(error: IValidationError): string { - const { value } = error - const type = error.context[error.context.length - 1].type! - const fullPath = error.context - .map(({ path }) => path) - .filter((path) => path.length > 0) - .join("/") - - const pathPrefix = fullPath.length > 0 ? `at path "/${fullPath}" ` : `` - - const currentTypename = isStateTreeNode(value) - ? `value of type ${getStateTreeNode(value).type.name}:` - : isPrimitive(value) - ? "value" - : "snapshot" - const isSnapshotCompatible = - type && isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot) - - return ( - `${pathPrefix}${currentTypename} ${prettyPrintValue(value)} is not assignable ${ - type ? `to type: \`${type.name}\`` : `` - }` + - (error.message ? ` (${error.message})` : "") + - (type - ? isPrimitiveType(type) || isPrimitive(value) - ? `.` - : `, expected an instance of \`${ - (type as IAnyType).name - }\` or a snapshot like \`${(type as IAnyType).describe()}\` instead.` + - (isSnapshotCompatible - ? " (Note that a snapshot of the provided value is compatible with the targeted type)" - : "") - : `.`) - ) -} - -/** - * @internal - * @hidden - */ -export function getContextForPath( - context: IValidationContext, - path: string, - type: IAnyType -): IValidationContext { - return context.concat([{ path, type }]) -} - -/** - * @internal - * @hidden - */ -export function typeCheckSuccess(): IValidationResult { - return EMPTY_ARRAY as any -} - -/** - * @internal - * @hidden - */ -export function typeCheckFailure( - context: IValidationContext, - value: any, - message?: string -): IValidationResult { - return [{ context, value, message }] -} - -/** - * @internal - * @hidden - */ -export function flattenTypeErrors(errors: IValidationResult[]): IValidationResult { - return errors.reduce((a, i) => a.concat(i), []) -} - -// TODO; doublecheck: typecheck should only needed to be invoked from: type.create and array / map / value.property will change -/** - * @internal - * @hidden - */ -export function typecheckInternal( - type: IAnyType, - value: ExtractCSTWithSTN -): void { - // runs typeChecking if it is in dev-mode or through a process.env.ENABLE_TYPE_CHECK flag - if (isTypeCheckingEnabled()) { - typecheck(type, value) - } -} - -/** - * Run's the typechecker for the given type on the given value, which can be a snapshot or an instance. - * Throws if the given value is not according the provided type specification. - * Use this if you need typechecks even in a production build (by default all automatic runtime type checks will be skipped in production builds) - * - * @param type Type to check against. - * @param value Value to be checked, either a snapshot or an instance. - */ -export function typecheck(type: IT, value: ExtractCSTWithSTN): void { - const errors = type.validate(value, [{ path: "", type }]) - - if (errors.length > 0) { - throw fail(validationErrorsToString(type, value, errors)) - } -} - -function validationErrorsToString( - type: IT, - value: ExtractCSTWithSTN, - errors: IValidationError[] -): string | undefined { - if (errors.length === 0) { - return undefined - } - - return ( - `Error while converting ${shortenPrintValue(prettyPrintValue(value))} to \`${ - type.name - }\`:\n\n ` + errors.map(toErrorString).join("\n ") - ) -} diff --git a/packages/mobx-state-tree/src/core/type/type.ts b/packages/mobx-state-tree/src/core/type/type.ts deleted file mode 100644 index 2aa9aea89..000000000 --- a/packages/mobx-state-tree/src/core/type/type.ts +++ /dev/null @@ -1,549 +0,0 @@ -import { action } from "mobx" - -import { - fail, - isMutable, - isStateTreeNode, - getStateTreeNode, - IValidationContext, - IValidationResult, - typecheckInternal, - typeCheckFailure, - typeCheckSuccess, - IStateTreeNode, - IJsonPatch, - getType, - ObjectNode, - IChildNodesMap, - ModelPrimitive, - normalizeIdentifier, - AnyObjectNode, - AnyNode, - BaseNode, - ScalarNode, - getStateTreeNodeSafe, - assertArg -} from "../../internal" - -/** - * @internal - * @hidden - */ -export enum TypeFlags { - String = 1, - Number = 1 << 1, - Boolean = 1 << 2, - Date = 1 << 3, - Literal = 1 << 4, - Array = 1 << 5, - Map = 1 << 6, - Object = 1 << 7, - Frozen = 1 << 8, - Optional = 1 << 9, - Reference = 1 << 10, - Identifier = 1 << 11, - Late = 1 << 12, - Refinement = 1 << 13, - Union = 1 << 14, - Null = 1 << 15, - Undefined = 1 << 16, - Integer = 1 << 17, - Custom = 1 << 18, - SnapshotProcessor = 1 << 19, - Lazy = 1 << 20, - Finite = 1 << 21, - Float = 1 << 22 -} - -/** - * @internal - * @hidden - */ -export const cannotDetermineSubtype = "cannotDetermine" - -/** - * A state tree node value. - * @hidden - */ -export type STNValue = T extends object ? T & IStateTreeNode : T - -/** @hidden */ -const $type: unique symbol = Symbol("$type") - -/** - * A type, either complex or simple. - */ -export interface IType { - // fake, will never be present, just for typing - /** @hidden */ - readonly [$type]: undefined - - /** - * Friendly type name. - */ - name: string - - /** - * Name of the identifier attribute or null if none. - */ - readonly identifierAttribute?: string - - /** - * Creates an instance for the type given an snapshot input. - * - * @returns An instance of that type. - */ - create(snapshot?: C, env?: any): this["Type"] - - /** - * Checks if a given snapshot / instance is of the given type. - * - * @param thing Snapshot or instance to be checked. - * @returns true if the value is of the current type, false otherwise. - */ - is(thing: any): thing is C | this["Type"] - - /** - * Run's the type's typechecker on the given value with the given validation context. - * - * @param thing Value to be checked, either a snapshot or an instance. - * @param context Validation context, an array of { subpaths, subtypes } that should be validated - * @returns The validation result, an array with the list of validation errors. - */ - validate(thing: C, context: IValidationContext): IValidationResult - - /** - * Gets the textual representation of the type as a string. - */ - describe(): string - - /** - * @deprecated use `Instance` instead. - * @hidden - */ - readonly Type: STNValue - - /** - * @deprecated do not use. - * @hidden - */ - readonly TypeWithoutSTN: T - - /** - * @deprecated use `SnapshotOut` instead. - * @hidden - */ - readonly SnapshotType: S - - /** - * @deprecated use `SnapshotIn` instead. - * @hidden - */ - readonly CreationType: C - - // Internal api's - - /** - * @internal - * @hidden - */ - flags: TypeFlags - /** - * @internal - * @hidden - */ - isType: true - /** - * @internal - * @hidden - */ - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C | T - ): BaseNode - /** - * @internal - * @hidden - */ - reconcile( - current: BaseNode, - newValue: C | T, - parent: AnyObjectNode, - subpath: string - ): BaseNode - /** - * @internal - * @hidden - */ - getSnapshot(node: BaseNode, applyPostProcess?: boolean): S - /** - * @internal - * @hidden - */ - isAssignableFrom(type: IAnyType): boolean - /** - * @internal - * @hidden - */ - getSubTypes(): IAnyType[] | IAnyType | null | typeof cannotDetermineSubtype -} - -/** - * Any kind of type. - */ -export interface IAnyType extends IType {} - -/** - * A simple type, this is, a type where the instance and the snapshot representation are the same. - */ -export interface ISimpleType extends IType {} - -/** @hidden */ -export type Primitives = ModelPrimitive | null | undefined - -/** - * A complex type. - * @deprecated just for compatibility with old versions, could be deprecated on the next major version - * @hidden - */ -export interface IComplexType extends IType {} - -/** - * Any kind of complex type. - */ -export interface IAnyComplexType extends IType {} - -/** @hidden */ -export type ExtractCSTWithoutSTN< - IT extends { [$type]: undefined; CreationType: any; SnapshotType: any; TypeWithoutSTN: any } -> = IT["CreationType"] | IT["SnapshotType"] | IT["TypeWithoutSTN"] -/** @hidden */ -export type ExtractCSTWithSTN< - IT extends { [$type]: undefined; CreationType: any; SnapshotType: any; Type: any } -> = IT["CreationType"] | IT["SnapshotType"] | IT["Type"] - -/** - * The instance representation of a given type. - */ -export type Instance = T extends { [$type]: undefined; Type: any } ? T["Type"] : T - -/** - * The input (creation) snapshot representation of a given type. - */ -export type SnapshotIn = T extends { [$type]: undefined; CreationType: any } - ? T["CreationType"] - : T extends IStateTreeNode - ? IT["CreationType"] - : T - -/** - * The output snapshot representation of a given type. - */ -export type SnapshotOut = T extends { [$type]: undefined; SnapshotType: any } - ? T["SnapshotType"] - : T extends IStateTreeNode - ? IT["SnapshotType"] - : T - -/** - * A type which is equivalent to the union of SnapshotIn and Instance types of a given typeof TYPE or typeof VARIABLE. - * For primitives it defaults to the primitive itself. - * - * For example: - * - `SnapshotOrInstance = SnapshotIn | Instance` - * - `SnapshotOrInstance = SnapshotIn | Instance` - * - * Usually you might want to use this when your model has a setter action that sets a property. - * - * Example: - * ```ts - * const ModelA = types.model({ - * n: types.number - * }) - * - * const ModelB = types.model({ - * innerModel: ModelA - * }).actions(self => ({ - * // this will accept as property both the snapshot and the instance, whichever is preferred - * setInnerModel(m: SnapshotOrInstance) { - * self.innerModel = cast(m) - * } - * })) - * ``` - */ -export type SnapshotOrInstance = SnapshotIn | Instance - -/** - * A base type produces a MST node (Node in the state tree) - * - * @internal - * @hidden - */ -export abstract class BaseType = BaseNode> - implements IType -{ - [$type]!: undefined - - // these are just to make inner types avaialable to inherited classes - readonly C!: C - readonly S!: S - readonly T!: T - readonly N!: N - - readonly isType = true - readonly name: string - - constructor(name: string) { - this.name = name - } - - create(snapshot?: C, environment?: any) { - typecheckInternal(this, snapshot) - return this.instantiate(null, "", environment, snapshot!).value - } - - getSnapshot(node: N, applyPostProcess?: boolean): S { - // istanbul ignore next - throw fail("unimplemented method") - } - - abstract reconcile(current: N, newValue: C | T, parent: AnyObjectNode, subpath: string): N - - abstract instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C | T - ): N - - declare abstract flags: TypeFlags - abstract describe(): string - - abstract isValidSnapshot(value: C, context: IValidationContext): IValidationResult - - isAssignableFrom(type: IAnyType): boolean { - return type === this - } - - validate(value: C | T, context: IValidationContext): IValidationResult { - const node = getStateTreeNodeSafe(value) - if (node) { - const valueType = getType(value) - return this.isAssignableFrom(valueType) - ? typeCheckSuccess() - : typeCheckFailure(context, value) - // it is tempting to compare snapshots, but in that case we should always clone on assignments... - } - return this.isValidSnapshot(value as C, context) - } - - is(thing: any): thing is any { - return this.validate(thing, [{ path: "", type: this }]).length === 0 - } - - get Type(): any { - // istanbul ignore next - throw fail( - "Factory.Type should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.Type`" - ) - } - get TypeWithoutSTN(): any { - // istanbul ignore next - throw fail( - "Factory.TypeWithoutSTN should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.TypeWithoutSTN`" - ) - } - get SnapshotType(): any { - // istanbul ignore next - throw fail( - "Factory.SnapshotType should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.SnapshotType`" - ) - } - get CreationType(): any { - // istanbul ignore next - throw fail( - "Factory.CreationType should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.CreationType`" - ) - } - - abstract getSubTypes(): IAnyType[] | IAnyType | null | typeof cannotDetermineSubtype -} -BaseType.prototype.create = action(BaseType.prototype.create) - -/** - * @internal - * @hidden - */ -export type AnyBaseType = BaseType - -/** - * @internal - * @hidden - */ -export type ExtractNodeType = IT extends BaseType - ? N - : never - -/** - * A complex type produces a MST node (Node in the state tree) - * - * @internal - * @hidden - */ -export abstract class ComplexType extends BaseType> { - identifierAttribute?: string - - constructor(name: string) { - super(name) - } - - create(snapshot: C = this.getDefaultSnapshot(), environment?: any) { - return super.create(snapshot, environment) - } - - getValue(node: this["N"]): T { - node.createObservableInstanceIfNeeded() - return node.storedValue - } - - abstract getDefaultSnapshot(): C - - abstract createNewInstance(childNodes: IChildNodesMap): T - abstract finalizeNewInstance(node: this["N"], instance: any): void - - abstract applySnapshot(node: this["N"], snapshot: C): void - abstract applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void - abstract processInitialSnapshot(childNodes: IChildNodesMap, snapshot: C): S - - abstract getChildren(node: this["N"]): ReadonlyArray - abstract getChildNode(node: this["N"], key: string): AnyNode - abstract getChildType(propertyName?: string): IAnyType - abstract initializeChildNodes(node: this["N"], snapshot: any): IChildNodesMap - abstract removeChild(node: this["N"], subpath: string): void - - isMatchingSnapshotId(current: this["N"], snapshot: C): boolean { - return ( - !current.identifierAttribute || - current.identifier === - normalizeIdentifier((snapshot as any)[current.identifierAttribute]) - ) - } - - private tryToReconcileNode(current: this["N"], newValue: C | T) { - if (current.isDetaching) return false - if ((current.snapshot as any) === newValue) { - // newValue is the current snapshot of the node, noop - return true - } - if (isStateTreeNode(newValue) && getStateTreeNode(newValue) === current) { - // the current node is the same as the new one - return true - } - if ( - current.type === this && - isMutable(newValue) && - !isStateTreeNode(newValue) && - this.isMatchingSnapshotId(current, newValue as any) - ) { - // the newValue has no node, so can be treated like a snapshot - // we can reconcile - current.applySnapshot(newValue as C) - return true - } - return false - } - - reconcile( - current: this["N"], - newValue: C | T, - parent: AnyObjectNode, - subpath: string - ): this["N"] { - const nodeReconciled = this.tryToReconcileNode(current, newValue) - if (nodeReconciled) { - current.setParent(parent, subpath) - return current - } - - // current node cannot be recycled in any way - current.die() // noop if detaching - // attempt to reuse the new one - if (isStateTreeNode(newValue) && this.isAssignableFrom(getType(newValue))) { - // newValue is a Node as well, move it here.. - const newNode = getStateTreeNode(newValue) - newNode.setParent(parent, subpath) - return newNode - } - // nothing to do, we have to create a new node - return this.instantiate(parent, subpath, undefined, newValue) - } - - getSubTypes() { - return null - } -} -ComplexType.prototype.create = action(ComplexType.prototype.create) - -/** - * @internal - * @hidden - */ -export abstract class SimpleType extends BaseType> { - abstract instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C - ): this["N"] - - createNewInstance(snapshot: C): T { - return snapshot as any - } - - getValue(node: this["N"]): T { - // if we ever find a case where scalar nodes can be accessed without iterating through its parent - // uncomment this to make sure the parent chain is created when this is accessed - // if (node.parent) { - // node.parent.createObservableInstanceIfNeeded() - // } - return node.storedValue - } - - getSnapshot(node: this["N"]): S { - return node.storedValue - } - - reconcile(current: this["N"], newValue: C, parent: AnyObjectNode, subpath: string): this["N"] { - // reconcile only if type and value are still the same, and only if the node is not detaching - if (!current.isDetaching && current.type === this && current.storedValue === newValue) { - return current - } - const res = this.instantiate(parent, subpath, undefined, newValue) - current.die() // noop if detaching - return res - } - - getSubTypes() { - return null - } -} - -/** - * Returns if a given value represents a type. - * - * @param value Value to check. - * @returns `true` if the value is a type. - */ -export function isType(value: any): value is IAnyType { - return typeof value === "object" && value && value.isType === true -} - -/** - * @internal - * @hidden - */ -export function assertIsType(type: IAnyType, argNumber: number | number[]) { - assertArg(type, isType, "mobx-state-tree type", argNumber) -} diff --git a/packages/mobx-state-tree/src/index.ts b/packages/mobx-state-tree/src/index.ts deleted file mode 100644 index 329897d6b..000000000 --- a/packages/mobx-state-tree/src/index.ts +++ /dev/null @@ -1,154 +0,0 @@ -// tslint:disable-next-line:no_unused-variable -import { IObservableArray, ObservableMap } from "mobx" - -/* all code is initially loaded through internal, to avoid circular dep issues */ -export { - IModelType, - IAnyModelType, - IDisposer, - IMSTMap, - IMapType, - IMSTArray, - IArrayType, - IType, - IAnyType, - ModelPrimitive, - ISimpleType, - IComplexType, - IAnyComplexType, - IReferenceType, - _CustomCSProcessor, - _CustomOrOther, - _CustomJoin, - _NotCustomized, - typecheck, - escapeJsonPath, - unescapeJsonPath, - joinJsonPath, - splitJsonPath, - IJsonPatch, - IReversibleJsonPatch, - decorate, - addMiddleware, - IMiddlewareEvent, - IActionTrackingMiddleware2Call, - IMiddlewareHandler, - IMiddlewareEventType, - IActionTrackingMiddlewareHooks, - IActionTrackingMiddleware2Hooks, - process, - isStateTreeNode, - IStateTreeNode, - IAnyStateTreeNode, - flow, - castFlowReturn, - applyAction, - onAction, - IActionRecorder, - ISerializedActionCall, - recordActions, - createActionTrackingMiddleware, - createActionTrackingMiddleware2, - setLivelinessChecking, - getLivelinessChecking, - LivelinessMode, - setLivelynessChecking, // to be deprecated - LivelynessMode, // to be deprecated - ModelSnapshotType, - ModelCreationType, - ModelSnapshotType2, - ModelCreationType2, - ModelInstanceType, - ModelInstanceTypeProps, - ModelPropertiesDeclarationToProperties, - ModelProperties, - ModelPropertiesDeclaration, - ModelActions, - ITypeUnion, - CustomTypeOptions, - UnionOptions, - Instance, - SnapshotIn, - SnapshotOut, - SnapshotOrInstance, - TypeOrStateTreeNodeToStateTreeNode, - UnionStringArray, - getType, - getChildType, - onPatch, - onSnapshot, - applyPatch, - IPatchRecorder, - recordPatches, - protect, - unprotect, - isProtected, - applySnapshot, - getSnapshot, - hasParent, - getParent, - hasParentOfType, - getParentOfType, - getRoot, - getPath, - getPathParts, - isRoot, - resolvePath, - resolveIdentifier, - getIdentifier, - tryResolve, - getRelativePath, - clone, - detach, - destroy, - isAlive, - addDisposer, - getEnv, - walk, - IModelReflectionData, - IModelReflectionPropertiesData, - IMaybeIType, - IMaybe, - IMaybeNull, - IOptionalIType, - OptionalDefaultValueOrFunction, - ValidOptionalValue, - ValidOptionalValues, - getMembers, - getPropertyMembers, - TypeOfValue, - cast, - castToSnapshot, - castToReferenceSnapshot, - isType, - isArrayType, - isFrozenType, - isIdentifierType, - isLateType, - isLiteralType, - isMapType, - isModelType, - isOptionalType, - isPrimitiveType, - isReferenceType, - isRefinementType, - isUnionType, - tryReference, - isValidReference, - OnReferenceInvalidated, - OnReferenceInvalidatedEvent, - ReferenceOptions, - ReferenceOptionsGetSet, - ReferenceOptionsOnInvalidated, - ReferenceIdentifier, - ISnapshotProcessor, - ISnapshotProcessors, - getNodeId, - IActionContext, - getRunningActionContext, - isActionContextChildOf, - isActionContextThisOrChildOf, - types, - toGeneratorFunction, - toGenerator -} from "./internal" diff --git a/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts b/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts deleted file mode 100644 index c588f384c..000000000 --- a/packages/mobx-state-tree/src/middlewares/create-action-tracking-middleware.ts +++ /dev/null @@ -1,92 +0,0 @@ -import { IMiddlewareEvent, IMiddlewareHandler } from "../internal" - -const runningActions = new Map() - -export interface IActionTrackingMiddlewareHooks { - filter?: (call: IMiddlewareEvent) => boolean - onStart: (call: IMiddlewareEvent) => T - onResume: (call: IMiddlewareEvent, context: T) => void - onSuspend: (call: IMiddlewareEvent, context: T) => void - onSuccess: (call: IMiddlewareEvent, context: T, result: any) => void - onFail: (call: IMiddlewareEvent, context: T, error: any) => void -} - -/** - * Note: Consider migrating to `createActionTrackingMiddleware2`, it is easier to use. - * - * Convenience utility to create action based middleware that supports async processes more easily. - * All hooks are called for both synchronous and asynchronous actions. Except that either `onSuccess` or `onFail` is called - * - * The create middleware tracks the process of an action (assuming it passes the `filter`). - * `onResume` can return any value, which will be passed as second argument to any other hook. This makes it possible to keep state during a process. - * - * See the `atomic` middleware for an example - * - * @param hooks - * @returns - */ -export function createActionTrackingMiddleware( - hooks: IActionTrackingMiddlewareHooks -): IMiddlewareHandler { - return function actionTrackingMiddleware( - call: IMiddlewareEvent, - next: (actionCall: IMiddlewareEvent) => any, - abort: (value: any) => any - ) { - switch (call.type) { - case "action": { - if (!hooks.filter || hooks.filter(call) === true) { - const context = hooks.onStart(call) - hooks.onResume(call, context) - runningActions.set(call.id, { - call, - context, - async: false - }) - try { - const res = next(call) - hooks.onSuspend(call, context) - if (runningActions.get(call.id)!.async === false) { - runningActions.delete(call.id) - hooks.onSuccess(call, context, res) - } - return res - } catch (e) { - runningActions.delete(call.id) - hooks.onFail(call, context, e) - throw e - } - } else { - return next(call) - } - } - case "flow_spawn": { - const root = runningActions.get(call.rootId)! - root.async = true - return next(call) - } - case "flow_resume": - case "flow_resume_error": { - const root = runningActions.get(call.rootId)! - hooks.onResume(call, root.context) - try { - return next(call) - } finally { - hooks.onSuspend(call, root.context) - } - } - case "flow_throw": { - const root = runningActions.get(call.rootId)! - runningActions.delete(call.rootId) - hooks.onFail(call, root.context, call.args[0]) - return next(call) - } - case "flow_return": { - const root = runningActions.get(call.rootId)! - runningActions.delete(call.rootId) - hooks.onSuccess(call, root.context, call.args[0]) - return next(call) - } - } - } -} diff --git a/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts b/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts deleted file mode 100644 index 698d359c5..000000000 --- a/packages/mobx-state-tree/src/middlewares/createActionTrackingMiddleware2.ts +++ /dev/null @@ -1,156 +0,0 @@ -import { IMiddlewareEvent, IMiddlewareHandler, IActionContext } from "../internal" - -type Omit = Pick> - -export interface IActionTrackingMiddleware2Call extends Readonly { - env: TEnv | undefined - readonly parentCall?: IActionTrackingMiddleware2Call -} - -export interface IActionTrackingMiddleware2Hooks { - filter?: (call: IActionTrackingMiddleware2Call) => boolean - onStart: (call: IActionTrackingMiddleware2Call) => void - onFinish: (call: IActionTrackingMiddleware2Call, error?: any) => void -} - -class RunningAction { - private flowsPending = 0 - private running = true - - constructor( - public readonly hooks: IActionTrackingMiddleware2Hooks | undefined, - readonly call: IActionTrackingMiddleware2Call - ) { - if (hooks) { - hooks.onStart(call) - } - } - - finish(error?: any) { - if (this.running) { - this.running = false - if (this.hooks) { - this.hooks.onFinish(this.call, error) - } - } - } - - incFlowsPending() { - this.flowsPending++ - } - - decFlowsPending() { - this.flowsPending-- - } - - get hasFlowsPending() { - return this.flowsPending > 0 - } -} - -/** - * Convenience utility to create action based middleware that supports async processes more easily. - * The flow is like this: - * - for each action: if filter passes -> `onStart` -> (inner actions recursively) -> `onFinish` - * - * Example: if we had an action `a` that called inside an action `b1`, then `b2` the flow would be: - * - `filter(a)` - * - `onStart(a)` - * - `filter(b1)` - * - `onStart(b1)` - * - `onFinish(b1)` - * - `filter(b2)` - * - `onStart(b2)` - * - `onFinish(b2)` - * - `onFinish(a)` - * - * The flow is the same no matter if the actions are sync or async. - * - * See the `atomic` middleware for an example - * - * @param hooks - * @returns - */ -export function createActionTrackingMiddleware2( - middlewareHooks: IActionTrackingMiddleware2Hooks -): IMiddlewareHandler { - const runningActions = new Map() - - return function actionTrackingMiddleware( - call: IMiddlewareEvent, - next: (actionCall: IMiddlewareEvent) => any - ) { - // find parentRunningAction - const parentRunningAction = call.parentActionEvent - ? runningActions.get(call.parentActionEvent.id) - : undefined - - if (call.type === "action") { - const newCall: IActionTrackingMiddleware2Call = { - ...call, - // make a shallow copy of the parent action env - env: parentRunningAction && parentRunningAction.call.env, - parentCall: parentRunningAction && parentRunningAction.call - } - - const passesFilter = !middlewareHooks.filter || middlewareHooks.filter(newCall) - const hooks = passesFilter ? middlewareHooks : undefined - - const runningAction = new RunningAction(hooks, newCall) - runningActions.set(call.id, runningAction) - - let res - try { - res = next(call) - } catch (e) { - runningActions.delete(call.id) - runningAction.finish(e) - throw e - } - // sync action finished - if (!runningAction.hasFlowsPending) { - runningActions.delete(call.id) - runningAction.finish() - } - return res - } else { - if (!parentRunningAction) { - return next(call) - } - - switch (call.type) { - case "flow_spawn": { - parentRunningAction.incFlowsPending() - return next(call) - } - case "flow_resume": - case "flow_resume_error": { - return next(call) - } - case "flow_throw": { - const error = call.args[0] - try { - return next(call) - } finally { - parentRunningAction.decFlowsPending() - if (!parentRunningAction.hasFlowsPending) { - runningActions.delete(call.parentActionEvent!.id) - parentRunningAction.finish(error) - } - } - } - case "flow_return": { - try { - return next(call) - } finally { - parentRunningAction.decFlowsPending() - if (!parentRunningAction.hasFlowsPending) { - runningActions.delete(call.parentActionEvent!.id) - parentRunningAction.finish() - } - } - } - } - } - } -} diff --git a/packages/mobx-state-tree/src/middlewares/on-action.ts b/packages/mobx-state-tree/src/middlewares/on-action.ts deleted file mode 100644 index 52ae5bc0a..000000000 --- a/packages/mobx-state-tree/src/middlewares/on-action.ts +++ /dev/null @@ -1,266 +0,0 @@ -import { runInAction } from "mobx" - -import { - getStateTreeNode, - isStateTreeNode, - addMiddleware, - tryResolve, - applyPatch, - getType, - applySnapshot, - isRoot, - isProtected, - fail, - isPlainObject, - isPrimitive, - IDisposer, - isArray, - asArray, - getRelativePathBetweenNodes, - IAnyStateTreeNode, - warnError, - AnyNode, - assertIsStateTreeNode, - devMode, - assertArg, - IActionContext, - getRunningActionContext -} from "../internal" - -export interface ISerializedActionCall { - name: string - path?: string - args?: any[] -} - -export interface IActionRecorder { - actions: ReadonlyArray - readonly recording: boolean - stop(): void - resume(): void - replay(target: IAnyStateTreeNode): void -} - -function serializeArgument(node: AnyNode, actionName: string, index: number, arg: any): any { - if (arg instanceof Date) return { $MST_DATE: arg.getTime() } - if (isPrimitive(arg)) return arg - // We should not serialize MST nodes, even if we can, because we don't know if the receiving party can handle a raw snapshot instead of an - // MST type instance. So if one wants to serialize a MST node that was pass in, either explitly pass: 1: an id, 2: a (relative) path, 3: a snapshot - if (isStateTreeNode(arg)) return serializeTheUnserializable(`[MSTNode: ${getType(arg).name}]`) - if (typeof arg === "function") return serializeTheUnserializable(`[function]`) - if (typeof arg === "object" && !isPlainObject(arg) && !isArray(arg)) - return serializeTheUnserializable( - `[object ${ - (arg && (arg as any).constructor && (arg as any).constructor.name) || - "Complex Object" - }]` - ) - try { - // Check if serializable, cycle free etc... - // MWE: there must be a better way.... - JSON.stringify(arg) // or throws - return arg - } catch (e) { - return serializeTheUnserializable("" + e) - } -} - -function deserializeArgument(adm: AnyNode, value: any): any { - if (value && typeof value === "object" && "$MST_DATE" in value) - return new Date(value["$MST_DATE"]) - return value -} - -function serializeTheUnserializable(baseType: string) { - return { - $MST_UNSERIALIZABLE: true, - type: baseType - } -} - -/** - * Applies an action or a series of actions in a single MobX transaction. - * Does not return any value - * Takes an action description as produced by the `onAction` middleware. - * - * @param target - * @param actions - */ -export function applyAction( - target: IAnyStateTreeNode, - actions: ISerializedActionCall | ISerializedActionCall[] -): void { - // check all arguments - assertIsStateTreeNode(target, 1) - assertArg(actions, (a) => typeof a === "object", "object or array", 2) - - runInAction(() => { - asArray(actions).forEach((action) => baseApplyAction(target, action)) - }) -} - -function baseApplyAction(target: IAnyStateTreeNode, action: ISerializedActionCall): any { - const resolvedTarget = tryResolve(target, action.path || "") - if (!resolvedTarget) throw fail(`Invalid action path: ${action.path || ""}`) - const node = getStateTreeNode(resolvedTarget) - - // Reserved functions - if (action.name === "@APPLY_PATCHES") { - return applyPatch.call(null, resolvedTarget, action.args![0]) - } - if (action.name === "@APPLY_SNAPSHOT") { - return applySnapshot.call(null, resolvedTarget, action.args![0]) - } - - if (!(typeof resolvedTarget[action.name] === "function")) - throw fail(`Action '${action.name}' does not exist in '${node.path}'`) - return resolvedTarget[action.name].apply( - resolvedTarget, - action.args ? action.args.map((v) => deserializeArgument(node, v)) : [] - ) -} - -/** - * Small abstraction around `onAction` and `applyAction`, attaches an action listener to a tree and records all the actions emitted. - * Returns an recorder object with the following signature: - * - * Example: - * ```ts - * export interface IActionRecorder { - * // the recorded actions - * actions: ISerializedActionCall[] - * // true if currently recording - * recording: boolean - * // stop recording actions - * stop(): void - * // resume recording actions - * resume(): void - * // apply all the recorded actions on the given object - * replay(target: IAnyStateTreeNode): void - * } - * ``` - * - * The optional filter function allows to skip recording certain actions. - * - * @param subject - * @returns - */ -export function recordActions( - subject: IAnyStateTreeNode, - filter?: (action: ISerializedActionCall, actionContext: IActionContext | undefined) => boolean -): IActionRecorder { - // check all arguments - assertIsStateTreeNode(subject, 1) - - const actions: ISerializedActionCall[] = [] - const listener = (call: ISerializedActionCall) => { - const recordThis = filter ? filter(call, getRunningActionContext()) : true - if (recordThis) { - actions.push(call) - } - } - - let disposer: IDisposer | undefined - const recorder: IActionRecorder = { - actions, - get recording() { - return !!disposer - }, - stop() { - if (disposer) { - disposer() - disposer = undefined - } - }, - resume() { - if (disposer) return - disposer = onAction(subject, listener) - }, - replay(target) { - applyAction(target, actions) - } - } - - recorder.resume() - return recorder -} - -/** - * Registers a function that will be invoked for each action that is called on the provided model instance, or to any of its children. - * See [actions](https://github.com/mobxjs/mobx-state-tree#actions) for more details. onAction events are emitted only for the outermost called action in the stack. - * Action can also be intercepted by middleware using addMiddleware to change the function call before it will be run. - * - * Not all action arguments might be serializable. For unserializable arguments, a struct like `{ $MST_UNSERIALIZABLE: true, type: "someType" }` will be generated. - * MST Nodes are considered non-serializable as well (they could be serialized as there snapshot, but it is uncertain whether an replaying party will be able to handle such a non-instantiated snapshot). - * Rather, when using `onAction` middleware, one should consider in passing arguments which are 1: an id, 2: a (relative) path, or 3: a snapshot. Instead of a real MST node. - * - * Example: - * ```ts - * const Todo = types.model({ - * task: types.string - * }) - * - * const TodoStore = types.model({ - * todos: types.array(Todo) - * }).actions(self => ({ - * add(todo) { - * self.todos.push(todo); - * } - * })) - * - * const s = TodoStore.create({ todos: [] }) - * - * let disposer = onAction(s, (call) => { - * console.log(call); - * }) - * - * s.add({ task: "Grab a coffee" }) - * // Logs: { name: "add", path: "", args: [{ task: "Grab a coffee" }] } - * ``` - * - * @param target - * @param listener - * @param attachAfter (default false) fires the listener *after* the action has executed instead of before. - * @returns - */ -export function onAction( - target: IAnyStateTreeNode, - listener: (call: ISerializedActionCall) => void, - attachAfter = false -): IDisposer { - // check all arguments - assertIsStateTreeNode(target, 1) - if (devMode()) { - if (!isRoot(target)) - warnError( - "Warning: Attaching onAction listeners to non root nodes is dangerous: No events will be emitted for actions initiated higher up in the tree." - ) - if (!isProtected(target)) - warnError( - "Warning: Attaching onAction listeners to non protected nodes is dangerous: No events will be emitted for direct modifications without action." - ) - } - - return addMiddleware(target, function handler(rawCall, next) { - if (rawCall.type === "action" && rawCall.id === rawCall.rootId) { - const sourceNode = getStateTreeNode(rawCall.context) - const info = { - name: rawCall.name, - path: getRelativePathBetweenNodes(getStateTreeNode(target), sourceNode), - args: rawCall.args.map((arg: any, index: number) => - serializeArgument(sourceNode, rawCall.name, index, arg) - ) - } - if (attachAfter) { - const res = next(rawCall) - listener(info) - return res - } else { - listener(info) - return next(rawCall) - } - } else { - return next(rawCall) - } - }) -} diff --git a/packages/mobx-state-tree/src/types/complex-types/array.ts b/packages/mobx-state-tree/src/types/complex-types/array.ts deleted file mode 100644 index bb28f8cb3..000000000 --- a/packages/mobx-state-tree/src/types/complex-types/array.ts +++ /dev/null @@ -1,505 +0,0 @@ -import { - _getAdministration, - action, - IArrayDidChange, - IArraySplice, - IArrayWillChange, - IArrayWillSplice, - intercept, - IObservableArray, - observable, - observe -} from "mobx" -import { - addHiddenFinalProp, - addHiddenWritableProp, - AnyNode, - AnyObjectNode, - assertIsType, - ComplexType, - convertChildNodesToArray, - createActionInvoker, - createObjectNode, - devMode, - EMPTY_ARRAY, - EMPTY_OBJECT, - ExtractCSTWithSTN, - fail, - flattenTypeErrors, - getContextForPath, - getStateTreeNode, - IAnyStateTreeNode, - IAnyType, - IChildNodesMap, - IHooksGetter, - IJsonPatch, - isArray, - isNode, - isPlainObject, - isStateTreeNode, - IStateTreeNode, - isType, - IType, - IValidationContext, - IValidationResult, - mobxShallow, - normalizeIdentifier, - ObjectNode, - typeCheckFailure, - typecheckInternal, - TypeFlags -} from "../../internal" - -/** @hidden */ -export interface IMSTArray extends IObservableArray { - // needs to be split or else it will complain about not being compatible with the array interface - push(...items: IT["Type"][]): number - push(...items: ExtractCSTWithSTN[]): number - - concat(...items: ConcatArray[]): IT["Type"][] - concat(...items: ConcatArray>[]): IT["Type"][] - - concat(...items: (IT["Type"] | ConcatArray)[]): IT["Type"][] - concat(...items: (ExtractCSTWithSTN | ConcatArray>)[]): IT["Type"][] - - splice(start: number, deleteCount?: number): IT["Type"][] - splice(start: number, deleteCount: number, ...items: IT["Type"][]): IT["Type"][] - splice(start: number, deleteCount: number, ...items: ExtractCSTWithSTN[]): IT["Type"][] - - unshift(...items: IT["Type"][]): number - unshift(...items: ExtractCSTWithSTN[]): number -} - -/** @hidden */ -export interface IArrayType - extends IType> { - hooks(hooks: IHooksGetter>): IArrayType -} - -/** - * @internal - * @hidden - */ -export class ArrayType extends ComplexType< - readonly IT["CreationType"][] | undefined, - IT["SnapshotType"][], - IMSTArray -> { - readonly flags = TypeFlags.Array - private readonly hookInitializers: Array>> = [] - constructor( - name: string, - private readonly _subType: IT, - hookInitializers: Array>> = [] - ) { - super(name) - this.hookInitializers = hookInitializers - } - - hooks(hooks: IHooksGetter>) { - const hookInitializers = - this.hookInitializers.length > 0 ? this.hookInitializers.concat(hooks) : [hooks] - return new ArrayType(this.name, this._subType, hookInitializers) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - return createObjectNode(this, parent, subpath, environment, initialValue) - } - - initializeChildNodes(objNode: this["N"], snapshot: this["C"] = []): IChildNodesMap { - const subType = (objNode.type as this)._subType - const result: IChildNodesMap = {} - snapshot.forEach((item, index) => { - const subpath = "" + index - result[subpath] = subType.instantiate(objNode, subpath, undefined, item) - }) - return result - } - - createNewInstance(childNodes: IChildNodesMap): this["T"] { - const options = { ...mobxShallow, name: this.name } - return observable.array(convertChildNodesToArray(childNodes), options) as this["T"] - } - - finalizeNewInstance(node: this["N"], instance: this["T"]): void { - _getAdministration(instance).dehancer = node.unbox - - const type = node.type as this - type.hookInitializers.forEach((initializer) => { - const hooks = initializer(instance) - Object.keys(hooks).forEach((name) => { - const hook = hooks[name as keyof typeof hooks]! - const actionInvoker = createActionInvoker(instance as IAnyStateTreeNode, name, hook) - ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)( - instance, - name, - actionInvoker - ) - }) - }) - - intercept(instance as IObservableArray, this.willChange) - observe(instance as IObservableArray, this.didChange) - } - - describe() { - return this.name - } - - getChildren(node: this["N"]): AnyNode[] { - return node.storedValue.slice() - } - - getChildNode(node: this["N"], key: string): AnyNode { - const index = Number(key) - if (index < node.storedValue.length) return node.storedValue[index] - throw fail("Not a child: " + key) - } - - willChange( - change: IArrayWillChange | IArrayWillSplice - ): IArrayWillChange | IArrayWillSplice | null { - const node = getStateTreeNode(change.object as IStateTreeNode) - node.assertWritable({ subpath: "" + change.index }) - const subType = (node.type as this)._subType - const childNodes = node.getChildren() - - switch (change.type) { - case "update": - { - if (change.newValue === change.object[change.index]) return null - - const updatedNodes = reconcileArrayChildren( - node, - subType, - [childNodes[change.index]], - [change.newValue], - [change.index] - ) - if (!updatedNodes) { - return null - } - change.newValue = updatedNodes[0] - } - break - case "splice": - { - const { index, removedCount, added } = change - - const addedNodes = reconcileArrayChildren( - node, - subType, - childNodes.slice(index, index + removedCount), - added, - added.map((_, i) => index + i) - ) - if (!addedNodes) { - return null - } - change.added = addedNodes - - // update paths of remaining items - for (let i = index + removedCount; i < childNodes.length; i++) { - childNodes[i].setParent(node, "" + (i + added.length - removedCount)) - } - } - break - } - return change - } - - getSnapshot(node: this["N"]): this["S"] { - return node.getChildren().map((childNode) => childNode.snapshot) - } - - processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { - const processed: this["S"] = [] - Object.keys(childNodes).forEach((key) => { - processed.push(childNodes[key].getSnapshot()) - }) - return processed - } - - didChange(change: IArrayDidChange | IArraySplice): void { - const node = getStateTreeNode(change.object as IAnyStateTreeNode) - switch (change.type) { - case "update": - return void node.emitPatch( - { - op: "replace", - path: "" + change.index, - value: change.newValue.snapshot, - oldValue: change.oldValue ? change.oldValue.snapshot : undefined - }, - node - ) - case "splice": - for (let i = change.removedCount - 1; i >= 0; i--) - node.emitPatch( - { - op: "remove", - path: "" + (change.index + i), - oldValue: change.removed[i].snapshot - }, - node - ) - for (let i = 0; i < change.addedCount; i++) - node.emitPatch( - { - op: "add", - path: "" + (change.index + i), - value: node.getChildNode("" + (change.index + i)).snapshot, - oldValue: undefined - }, - node - ) - return - } - } - - applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { - const target = node.storedValue - const index = subpath === "-" ? target.length : Number(subpath) - switch (patch.op) { - case "replace": - target[index] = patch.value - break - case "add": - target.splice(index, 0, patch.value) - break - case "remove": - target.splice(index, 1) - break - } - } - - applySnapshot(node: this["N"], snapshot: this["C"]): void { - typecheckInternal(this, snapshot) - const target = node.storedValue - target.replace(snapshot as any) - } - - getChildType(): IAnyType { - return this._subType - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (!isArray(value)) { - return typeCheckFailure(context, value, "Value is not an array") - } - - return flattenTypeErrors( - value.map((item, index) => - this._subType.validate(item, getContextForPath(context, "" + index, this._subType)) - ) - ) - } - - getDefaultSnapshot(): this["C"] { - return EMPTY_ARRAY as this["C"] - } - - removeChild(node: this["N"], subpath: string) { - node.storedValue.splice(Number(subpath), 1) - } -} -ArrayType.prototype.applySnapshot = action(ArrayType.prototype.applySnapshot) - -/** - * `types.array` - Creates an index based collection type who's children are all of a uniform declared type. - * - * This type will always produce [observable arrays](https://mobx.js.org/api.html#observablearray) - * - * Example: - * ```ts - * const Todo = types.model({ - * task: types.string - * }) - * - * const TodoStore = types.model({ - * todos: types.array(Todo) - * }) - * - * const s = TodoStore.create({ todos: [] }) - * unprotect(s) // needed to allow modifying outside of an action - * s.todos.push({ task: "Grab coffee" }) - * console.log(s.todos[0]) // prints: "Grab coffee" - * ``` - * - * @param subtype - * @returns - */ -export function array(subtype: IT): IArrayType { - assertIsType(subtype, 1) - return new ArrayType(`${subtype.name}[]`, subtype) -} - -function reconcileArrayChildren( - parent: AnyObjectNode, - childType: IType, - oldNodes: AnyNode[], - newValues: TT[], - newPaths: (string | number)[] -): AnyNode[] | null { - let nothingChanged = true - - for (let i = 0; ; i++) { - const hasNewNode = i <= newValues.length - 1 - const oldNode = oldNodes[i] - let newValue = hasNewNode ? newValues[i] : undefined - const newPath = "" + newPaths[i] - - // for some reason, instead of newValue we got a node, fallback to the storedValue - // TODO: https://github.com/mobxjs/mobx-state-tree/issues/340#issuecomment-325581681 - if (isNode(newValue)) newValue = newValue.storedValue - - if (!oldNode && !hasNewNode) { - // both are empty, end - break - } else if (!hasNewNode) { - // new one does not exists - nothingChanged = false - oldNodes.splice(i, 1) - if (oldNode instanceof ObjectNode) { - // since it is going to be returned by pop/splice/shift better create it before killing it - // so it doesn't end up in an undead state - oldNode.createObservableInstanceIfNeeded() - } - oldNode.die() - i-- - } else if (!oldNode) { - // there is no old node, create it - // check if already belongs to the same parent. if so, avoid pushing item in. only swapping can occur. - if (isStateTreeNode(newValue) && getStateTreeNode(newValue).parent === parent) { - // this node is owned by this parent, but not in the reconcilable set, so it must be double - throw fail( - `Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${ - parent.path - }/${newPath}', but it lives already at '${getStateTreeNode(newValue).path}'` - ) - } - nothingChanged = false - const newNode = valueAsNode(childType, parent, newPath, newValue) - oldNodes.splice(i, 0, newNode) - } else if (areSame(oldNode, newValue)) { - // both are the same, reconcile - oldNodes[i] = valueAsNode(childType, parent, newPath, newValue, oldNode) - } else { - // nothing to do, try to reorder - let oldMatch = undefined - - // find a possible candidate to reuse - for (let j = i; j < oldNodes.length; j++) { - if (areSame(oldNodes[j], newValue)) { - oldMatch = oldNodes.splice(j, 1)[0] - break - } - } - - nothingChanged = false - const newNode = valueAsNode(childType, parent, newPath, newValue, oldMatch) - oldNodes.splice(i, 0, newNode) - } - } - - return nothingChanged ? null : oldNodes -} - -/** - * Convert a value to a node at given parent and subpath. Attempts to reuse old node if possible and given. - */ -function valueAsNode( - childType: IAnyType, - parent: AnyObjectNode, - subpath: string, - newValue: any, - oldNode?: AnyNode -) { - // ensure the value is valid-ish - typecheckInternal(childType, newValue) - - function getNewNode() { - // the new value has a MST node - if (isStateTreeNode(newValue)) { - const childNode = getStateTreeNode(newValue) - childNode.assertAlive(EMPTY_OBJECT) - - // the node lives here - if (childNode.parent !== null && childNode.parent === parent) { - childNode.setParent(parent, subpath) - return childNode - } - } - // there is old node and new one is a value/snapshot - if (oldNode) { - return childType.reconcile(oldNode, newValue, parent, subpath) - } - - // nothing to do, create from scratch - return childType.instantiate(parent, subpath, undefined, newValue) - } - - const newNode = getNewNode() - if (oldNode && oldNode !== newNode) { - if (oldNode instanceof ObjectNode) { - // since it is going to be returned by pop/splice/shift better create it before killing it - // so it doesn't end up in an undead state - oldNode.createObservableInstanceIfNeeded() - } - oldNode.die() - } - return newNode -} - -/** - * Check if a node holds a value. - */ -function areSame(oldNode: AnyNode, newValue: any) { - // never consider dead old nodes for reconciliation - if (!oldNode.isAlive) { - return false - } - - // the new value has the same node - if (isStateTreeNode(newValue)) { - const newNode = getStateTreeNode(newValue) - return newNode.isAlive && newNode === oldNode - } - - // the provided value is the snapshot of the old node - if (oldNode.snapshot === newValue) { - return true - } - - // Non object nodes don't get reconciled - if (!(oldNode instanceof ObjectNode)) { - return false - } - - const oldNodeType = oldNode.getReconciliationType() - // new value is a snapshot with the correct identifier - return ( - oldNode.identifier !== null && - oldNode.identifierAttribute && - isPlainObject(newValue) && - oldNodeType.is(newValue) && - (oldNodeType as any).isMatchingSnapshotId(oldNode, newValue) - ) -} - -/** - * Returns if a given value represents an array type. - * - * @param type - * @returns `true` if the type is an array type. - */ -export function isArrayType( - type: IAnyType -): type is IArrayType { - return isType(type) && (type.flags & TypeFlags.Array) > 0 -} diff --git a/packages/mobx-state-tree/src/types/complex-types/map.ts b/packages/mobx-state-tree/src/types/complex-types/map.ts deleted file mode 100644 index e4fb0fb46..000000000 --- a/packages/mobx-state-tree/src/types/complex-types/map.ts +++ /dev/null @@ -1,528 +0,0 @@ -import { - _interceptReads, - action, - IInterceptor, - IKeyValueMap, - IMapDidChange, - IMapWillChange, - intercept, - Lambda, - observable, - ObservableMap, - observe, - values, - IObservableMapInitialValues, -} from "mobx" -import { - ComplexType, - createObjectNode, - escapeJsonPath, - fail, - flattenTypeErrors, - getContextForPath, - getStateTreeNode, - IAnyStateTreeNode, - IAnyType, - IChildNodesMap, - IValidationContext, - IJsonPatch, - isMutable, - isPlainObject, - isStateTreeNode, - isType, - IType, - IValidationResult, - ModelType, - ObjectNode, - typecheckInternal, - typeCheckFailure, - TypeFlags, - EMPTY_OBJECT, - normalizeIdentifier, - AnyObjectNode, - AnyNode, - IAnyModelType, - asArray, - cannotDetermineSubtype, - getSnapshot, - isValidIdentifier, - ExtractCSTWithSTN, - devMode, - createActionInvoker, - addHiddenFinalProp, - addHiddenWritableProp, - IHooksGetter -} from "../../internal" - -/** @hidden */ -export interface IMapType - extends IType< - IKeyValueMap | undefined, - IKeyValueMap, - IMSTMap - > { - hooks(hooks: IHooksGetter>): IMapType -} - -/** @hidden */ -export interface IMSTMap { - // bases on ObservableMap, but fine tuned to the auto snapshot conversion of MST - - clear(): void - delete(key: string): boolean - forEach( - callbackfn: (value: IT["Type"], key: string | number, map: this) => void, - thisArg?: any - ): void - get(key: string | number): IT["Type"] | undefined - has(key: string | number): boolean - set(key: string | number, value: ExtractCSTWithSTN): this - readonly size: number - put(value: ExtractCSTWithSTN): IT["Type"] - keys(): IterableIterator - values(): IterableIterator - entries(): IterableIterator<[string, IT["Type"]]> - [Symbol.iterator](): IterableIterator<[string, IT["Type"]]> - /** Merge another object into this map, returns self. */ - merge( - other: - | IMSTMap> - | IKeyValueMap> - | any - ): this - replace( - values: - | IMSTMap> - | IKeyValueMap> - | any - ): this - - toJSON(): IKeyValueMap - - toString(): string - [Symbol.toStringTag]: "Map" - - /** - * Observes this object. Triggers for the events 'add', 'update' and 'delete'. - * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe - * for callback details - */ - observe( - listener: (changes: IMapDidChange) => void, - fireImmediately?: boolean - ): Lambda - intercept(handler: IInterceptor>): Lambda -} - -const needsIdentifierError = `Map.put can only be used to store complex values that have an identifier type attribute` - -function tryCollectModelTypes(type: IAnyType, modelTypes: Array): boolean { - const subtypes = type.getSubTypes() - if (subtypes === cannotDetermineSubtype) { - return false - } - if (subtypes) { - const subtypesArray = asArray(subtypes) - for (const subtype of subtypesArray) { - if (!tryCollectModelTypes(subtype, modelTypes)) return false - } - } - if (type instanceof ModelType) { - modelTypes.push(type) - } - return true -} - -/** - * @internal - * @hidden - */ -export enum MapIdentifierMode { - UNKNOWN, - YES, - NO -} - -class MSTMap extends ObservableMap { - constructor( - initialData?: IObservableMapInitialValues | undefined, - name?: string - ) { - super(initialData, (observable.ref as any).enhancer, name) - } - - get(key: string): IT["Type"] | undefined { - // maybe this is over-enthousiastic? normalize numeric keys to strings - return super.get("" + key) - } - - has(key: string) { - return super.has("" + key) - } - - delete(key: string) { - return super.delete("" + key) - } - - set(key: string, value: ExtractCSTWithSTN): this { - return super.set("" + key, value) - } - - put(value: ExtractCSTWithSTN): IT["Type"] { - if (!value) throw fail(`Map.put cannot be used to set empty values`) - if (isStateTreeNode(value)) { - const node = getStateTreeNode(value) - if (devMode()) { - if (!node.identifierAttribute) { - throw fail(needsIdentifierError) - } - } - if (node.identifier === null) { - throw fail(needsIdentifierError) - } - this.set(node.identifier, value) - return value as any - } else if (!isMutable(value)) { - throw fail(`Map.put can only be used to store complex values`) - } else { - const mapNode = getStateTreeNode(this as IAnyStateTreeNode) - const mapType = mapNode.type as MapType - - if (mapType.identifierMode !== MapIdentifierMode.YES) { - throw fail(needsIdentifierError) - } - - const idAttr = mapType.mapIdentifierAttribute! - const id = (value as any)[idAttr] - if (!isValidIdentifier(id)) { - // try again but this time after creating a node for the value - // since it might be an optional identifier - const newNode = this.put(mapType.getChildType().create(value, mapNode.environment)) - return this.put(getSnapshot(newNode)) - } - const key = normalizeIdentifier(id) - this.set(key, value) - return this.get(key) as any - } - } -} - -/** - * @internal - * @hidden - */ -export class MapType extends ComplexType< - IKeyValueMap | undefined, - IKeyValueMap, - IMSTMap -> { - identifierMode: MapIdentifierMode = MapIdentifierMode.UNKNOWN - mapIdentifierAttribute: string | undefined = undefined - readonly flags = TypeFlags.Map - - private readonly hookInitializers: Array>> = [] - - constructor( - name: string, - private readonly _subType: IAnyType, - hookInitializers: Array>> = [] - ) { - super(name) - this._determineIdentifierMode() - this.hookInitializers = hookInitializers - } - - hooks(hooks: IHooksGetter>) { - const hookInitializers = - this.hookInitializers.length > 0 ? this.hookInitializers.concat(hooks) : [hooks] - return new MapType(this.name, this._subType, hookInitializers) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - this._determineIdentifierMode() - return createObjectNode(this, parent, subpath, environment, initialValue) - } - - private _determineIdentifierMode() { - if (this.identifierMode !== MapIdentifierMode.UNKNOWN) { - return - } - - const modelTypes: IAnyModelType[] = [] - if (tryCollectModelTypes(this._subType, modelTypes)) { - const identifierAttribute: string | undefined = modelTypes.reduce( - (current: IAnyModelType["identifierAttribute"], type) => { - if (!type.identifierAttribute) return current - if (current && current !== type.identifierAttribute) { - throw fail( - `The objects in a map should all have the same identifier attribute, expected '${current}', but child of type '${type.name}' declared attribute '${type.identifierAttribute}' as identifier` - ) - } - return type.identifierAttribute - }, - undefined as IAnyModelType["identifierAttribute"] - ) - - if (identifierAttribute) { - this.identifierMode = MapIdentifierMode.YES - this.mapIdentifierAttribute = identifierAttribute - } else { - this.identifierMode = MapIdentifierMode.NO - } - } - } - - initializeChildNodes(objNode: this["N"], initialSnapshot: this["C"] = {}): IChildNodesMap { - const subType = (objNode.type as this)._subType - const result: IChildNodesMap = {} - Object.keys(initialSnapshot!).forEach((name) => { - result[name] = subType.instantiate(objNode, name, undefined, initialSnapshot[name]) - }) - - return result - } - - createNewInstance(childNodes: IChildNodesMap): this["T"] { - return new MSTMap(childNodes, this.name) as any - } - - finalizeNewInstance(node: this["N"], instance: ObservableMap): void { - _interceptReads(instance, node.unbox) - - const type = node.type as this - type.hookInitializers.forEach((initializer) => { - const hooks = initializer(instance as unknown as IMSTMap) - Object.keys(hooks).forEach((name) => { - const hook = hooks[name as keyof typeof hooks]! - const actionInvoker = createActionInvoker(instance as IAnyStateTreeNode, name, hook) - ; (!devMode() ? addHiddenFinalProp : addHiddenWritableProp)( - instance, - name, - actionInvoker - ) - }) - }) - - intercept(instance, this.willChange) - observe(instance, this.didChange) - } - - describe() { - return this.name - } - - getChildren(node: this["N"]): ReadonlyArray { - // return (node.storedValue as ObservableMap).values() - return values(node.storedValue) - } - - getChildNode(node: this["N"], key: string): AnyNode { - const childNode = node.storedValue.get("" + key) - if (!childNode) throw fail("Not a child " + key) - return childNode - } - - willChange(change: IMapWillChange): IMapWillChange | null { - const node = getStateTreeNode(change.object as IAnyStateTreeNode) - const key = change.name - node.assertWritable({ subpath: key }) - const mapType = node.type as this - const subType = mapType._subType - - switch (change.type) { - case "update": - { - const { newValue } = change - const oldValue = change.object.get(key) - if (newValue === oldValue) return null - typecheckInternal(subType, newValue) - change.newValue = subType.reconcile( - node.getChildNode(key), - change.newValue, - node, - key - ) - mapType.processIdentifier(key, change.newValue) - } - break - case "add": - { - typecheckInternal(subType, change.newValue) - change.newValue = subType.instantiate(node, key, undefined, change.newValue) - mapType.processIdentifier(key, change.newValue) - } - break - } - return change - } - - private processIdentifier(expected: string, node: AnyNode): void { - if (this.identifierMode === MapIdentifierMode.YES && node instanceof ObjectNode) { - const identifier = node.identifier! - if (identifier !== expected) - throw fail( - `A map of objects containing an identifier should always store the object under their own identifier. Trying to store key '${identifier}', but expected: '${expected}'` - ) - } - } - - getSnapshot(node: this["N"]): this["S"] { - const res: any = {} - node.getChildren().forEach((childNode) => { - res[childNode.subpath] = childNode.snapshot - }) - return res - } - - processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { - const processed: any = {} - Object.keys(childNodes).forEach((key) => { - processed[key] = childNodes[key].getSnapshot() - }) - return processed - } - - didChange(change: IMapDidChange): void { - const node = getStateTreeNode(change.object as IAnyStateTreeNode) - switch (change.type) { - case "update": - return void node.emitPatch( - { - op: "replace", - path: escapeJsonPath(change.name), - value: change.newValue.snapshot, - oldValue: change.oldValue ? change.oldValue.snapshot : undefined - }, - node - ) - case "add": - return void node.emitPatch( - { - op: "add", - path: escapeJsonPath(change.name), - value: change.newValue.snapshot, - oldValue: undefined - }, - node - ) - case "delete": - // a node got deleted, get the old snapshot and make the node die - const oldSnapshot = change.oldValue.snapshot - change.oldValue.die() - // emit the patch - return void node.emitPatch( - { - op: "remove", - path: escapeJsonPath(change.name), - oldValue: oldSnapshot - }, - node - ) - } - } - - applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { - const target = node.storedValue - switch (patch.op) { - case "add": - case "replace": - target.set(subpath, patch.value) - break - case "remove": - target.delete(subpath) - break - } - } - - applySnapshot(node: this["N"], snapshot: this["C"]): void { - typecheckInternal(this, snapshot) - const target = node.storedValue - const currentKeys: { [key: string]: boolean } = {} - Array.from(target.keys()).forEach((key) => { - currentKeys[key] = false - }) - if (snapshot) { - // Don't use target.replace, as it will throw away all existing items first - for (let key in snapshot) { - target.set(key, snapshot[key]) - currentKeys["" + key] = true - } - } - Object.keys(currentKeys).forEach((key) => { - if (currentKeys[key] === false) target.delete(key) - }) - } - - getChildType(): IAnyType { - return this._subType - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (!isPlainObject(value)) { - return typeCheckFailure(context, value, "Value is not a plain object") - } - - return flattenTypeErrors( - Object.keys(value).map((path) => - this._subType.validate(value[path], getContextForPath(context, path, this._subType)) - ) - ) - } - - getDefaultSnapshot(): this["C"] { - return EMPTY_OBJECT as this["C"] - } - - removeChild(node: this["N"], subpath: string) { - node.storedValue.delete(subpath) - } -} -MapType.prototype.applySnapshot = action(MapType.prototype.applySnapshot) - -/** - * `types.map` - Creates a key based collection type who's children are all of a uniform declared type. - * If the type stored in a map has an identifier, it is mandatory to store the child under that identifier in the map. - * - * This type will always produce [observable maps](https://mobx.js.org/api.html#observablemap) - * - * Example: - * ```ts - * const Todo = types.model({ - * id: types.identifier, - * task: types.string - * }) - * - * const TodoStore = types.model({ - * todos: types.map(Todo) - * }) - * - * const s = TodoStore.create({ todos: {} }) - * unprotect(s) - * s.todos.set(17, { task: "Grab coffee", id: 17 }) - * s.todos.put({ task: "Grab cookie", id: 18 }) // put will infer key from the identifier - * console.log(s.todos.get(17).task) // prints: "Grab coffee" - * ``` - * - * @param subtype - * @returns - */ -export function map(subtype: IT): IMapType { - return new MapType(`Map`, subtype) -} - -/** - * Returns if a given value represents a map type. - * - * @param type - * @returns `true` if it is a map type. - */ -export function isMapType( - type: IAnyType -): type is IMapType { - return isType(type) && (type.flags & TypeFlags.Map) > 0 -} diff --git a/packages/mobx-state-tree/src/types/complex-types/model.ts b/packages/mobx-state-tree/src/types/complex-types/model.ts deleted file mode 100644 index fed4ee27b..000000000 --- a/packages/mobx-state-tree/src/types/complex-types/model.ts +++ /dev/null @@ -1,859 +0,0 @@ -import { - _getAdministration, - _interceptReads, - action, - computed, - defineProperty, - intercept, - getAtom, - IObjectWillChange, - observable, - observe, - set, - IObjectDidChange, - makeObservable -} from "mobx" -import { - addHiddenFinalProp, - addHiddenWritableProp, - ArrayType, - ComplexType, - createActionInvoker, - createObjectNode, - EMPTY_ARRAY, - EMPTY_OBJECT, - escapeJsonPath, - fail, - flattenTypeErrors, - freeze, - getContextForPath, - getPrimitiveFactoryFromValue, - getStateTreeNode, - IAnyType, - IChildNodesMap, - IValidationContext, - IJsonPatch, - isPlainObject, - isPrimitive, - isStateTreeNode, - isType, - IType, - IValidationResult, - mobxShallow, - optional, - MapType, - typecheckInternal, - typeCheckFailure, - TypeFlags, - Hook, - AnyObjectNode, - AnyNode, - _CustomOrOther, - _NotCustomized, - Instance, - devMode, - assertIsString, - assertArg, - FunctionWithFlag -} from "../../internal" -import { ComputedValue } from "mobx/dist/internal" - -const PRE_PROCESS_SNAPSHOT = "preProcessSnapshot" -const POST_PROCESS_SNAPSHOT = "postProcessSnapshot" - -/** @hidden */ -export interface ModelProperties { - [key: string]: IAnyType -} - -/** @hidden */ -export type ModelPrimitive = string | number | boolean | Date - -/** @hidden */ -export interface ModelPropertiesDeclaration { - [key: string]: ModelPrimitive | IAnyType -} - -/** - * Unmaps syntax property declarations to a map of { propName: IType } - * - * @hidden - */ -export type ModelPropertiesDeclarationToProperties = - T extends { [k: string]: IAnyType } // optimization to reduce nesting - ? T - : { - [K in keyof T]: T[K] extends IAnyType // keep IAnyType check on the top to reduce nesting - ? T[K] - : T[K] extends string - ? IType - : T[K] extends number - ? IType - : T[K] extends boolean - ? IType - : T[K] extends Date - ? IType - : never - } - -/** - * Checks if a value is optional (undefined, any or unknown). - * @hidden - * - * Examples: - * - string = false - * - undefined = true - * - string | undefined = true - * - string & undefined = false, but we don't care - * - any = true - * - unknown = true - */ -type IsOptionalValue = undefined extends C ? TV : FV - -// type _A = IsOptionalValue // false -// type _B = IsOptionalValue // true -// type _C = IsOptionalValue // true -// type _D = IsOptionalValue // false, but we don't care -// type _E = IsOptionalValue // true -// type _F = IsOptionalValue // true - -/** - * Name of the properties of an object that can't be set to undefined, any or unknown - * @hidden - */ -type DefinablePropsNames = { [K in keyof T]: IsOptionalValue }[keyof T] - -/** @hidden */ -export declare const $nonEmptyObject: unique symbol - -/** @hidden */ -export interface NonEmptyObject { - [$nonEmptyObject]?: any -} - -/** @hidden */ -export type ExtractCFromProps

= { [k in keyof P]: P[k]["CreationType"] } - -/** @hidden */ -export type ModelCreationType = { [P in DefinablePropsNames]: PC[P] } & Partial & - NonEmptyObject - -/** @hidden */ -export type ModelCreationType2

= _CustomOrOther< - CustomC, - ModelCreationType> -> - -/** @hidden */ -export type ModelSnapshotType

= { - [K in keyof P]: P[K]["SnapshotType"] -} & NonEmptyObject - -/** @hidden */ -export type ModelSnapshotType2

= _CustomOrOther< - CustomS, - ModelSnapshotType

-> - -/** - * @hidden - * we keep this separate from ModelInstanceType to shorten model instance types generated declarations - */ -export type ModelInstanceTypeProps

= { - [K in keyof P]: P[K]["Type"] -} & NonEmptyObject - -/** - * @hidden - * do not transform this to an interface or model instance type generated declarations will be longer - */ -export type ModelInstanceType

= ModelInstanceTypeProps

& O - -/** @hidden */ -export interface ModelActions { - [key: string]: FunctionWithFlag -} - -export interface IModelType< - PROPS extends ModelProperties, - OTHERS, - CustomC = _NotCustomized, - CustomS = _NotCustomized -> extends IType< - ModelCreationType2, - ModelSnapshotType2, - ModelInstanceType - > { - readonly properties: PROPS - - named(newName: string): IModelType - - // warning: redefining props after a process snapshot is used ends up on the fixed (custom) C, S typings being overridden - // so it is recommended to use pre/post process snapshot after all props have been defined - props( - props: PROPS2 - ): IModelType, OTHERS, CustomC, CustomS> - - views( - fn: (self: Instance) => V - ): IModelType - - actions( - fn: (self: Instance) => A - ): IModelType - - volatile( - fn: (self: Instance) => TP - ): IModelType - - extend( - fn: (self: Instance) => { actions?: A; views?: V; state?: VS } - ): IModelType - - preProcessSnapshot>( - fn: (snapshot: NewC) => ModelCreationType2 - ): IModelType - - postProcessSnapshot>( - fn: (snapshot: ModelSnapshotType2) => NewS - ): IModelType -} - -/** - * Any model type. - */ -export interface IAnyModelType extends IModelType {} - -/** @hidden */ -export type ExtractProps = T extends IModelType - ? P - : never -/** @hidden */ -export type ExtractOthers = T extends IModelType - ? O - : never - -function objectTypeToString(this: any) { - return getStateTreeNode(this).toString() -} - -/** - * @internal - * @hidden - */ -export interface ModelTypeConfig { - name?: string - properties?: ModelPropertiesDeclaration - initializers?: ReadonlyArray<(instance: any) => any> - preProcessor?: (snapshot: any) => any - postProcessor?: (snapshot: any) => any -} - -const defaultObjectOptions = { - name: "AnonymousModel", - properties: {}, - initializers: EMPTY_ARRAY -} - -function toPropertiesObject(declaredProps: ModelPropertiesDeclaration): ModelProperties { - const keysList = Object.keys(declaredProps) - const alreadySeenKeys: { [key: string]: boolean } = {} - keysList.forEach((key) => { - if (alreadySeenKeys[key]) { - throw fail(`${key} is declared twice in the model. Model should not contain same keys`) - } else { - alreadySeenKeys[key] = true - } - }) - // loop through properties and ensures that all items are types - return keysList.reduce((props, key) => { - // warn if user intended a HOOK - if (key in Hook) - throw fail( - `Hook '${key}' was defined as property. Hooks should be defined as part of the actions` - ) - - // the user intended to use a view - const descriptor = Object.getOwnPropertyDescriptor(props, key)! - if ("get" in descriptor) { - throw fail("Getters are not supported as properties. Please use views instead") - } - // undefined and null are not valid - const value = descriptor.value - if (value === null || value === undefined) { - throw fail( - "The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean `types.maybe(someType)`?" - ) - // its a primitive, convert to its type - } else if (isPrimitive(value)) { - return Object.assign({}, props, { - [key]: optional(getPrimitiveFactoryFromValue(value), value) - }) - // map defaults to empty object automatically for models - } else if (value instanceof MapType) { - return Object.assign({}, props, { - [key]: optional(value, {}) - }) - } else if (value instanceof ArrayType) { - return Object.assign({}, props, { [key]: optional(value, []) }) - // its already a type - } else if (isType(value)) { - return props - // its a function, maybe the user wanted a view? - } else if (devMode() && typeof value === "function") { - throw fail( - `Invalid type definition for property '${key}', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?` - ) - // no other complex values - } else if (devMode() && typeof value === "object") { - throw fail( - `Invalid type definition for property '${key}', it looks like you passed an object. Try passing another model type or a types.frozen.` - ) - // WTF did you pass in mate? - } else { - throw fail( - `Invalid type definition for property '${key}', cannot infer a type from a value like '${value}' (${typeof value})` - ) - } - }, declaredProps as any) -} - -/** - * @internal - * @hidden - */ -export class ModelType< - PROPS extends ModelProperties, - OTHERS, - CustomC, - CustomS, - MT extends IModelType - > - extends ComplexType< - ModelCreationType2, - ModelSnapshotType2, - ModelInstanceType - > - implements IModelType -{ - readonly flags = TypeFlags.Object - - /* - * The original object definition - */ - public readonly initializers!: ((instance: any) => any)[] - public readonly properties!: PROPS - - private preProcessor!: (snapshot: any) => any | undefined - private postProcessor!: (snapshot: any) => any | undefined - private readonly propertyNames: string[] - - constructor(opts: ModelTypeConfig) { - super(opts.name || defaultObjectOptions.name) - Object.assign(this, defaultObjectOptions, opts) - // ensures that any default value gets converted to its related type - this.properties = toPropertiesObject(this.properties) as PROPS - freeze(this.properties) // make sure nobody messes with it - this.propertyNames = Object.keys(this.properties) - this.identifierAttribute = this._getIdentifierAttribute() - } - - private _getIdentifierAttribute(): string | undefined { - let identifierAttribute: string | undefined = undefined - this.forAllProps((propName, propType) => { - if (propType.flags & TypeFlags.Identifier) { - if (identifierAttribute) - throw fail( - `Cannot define property '${propName}' as object identifier, property '${identifierAttribute}' is already defined as identifier property` - ) - identifierAttribute = propName - } - }) - return identifierAttribute - } - - cloneAndEnhance(opts: ModelTypeConfig): IAnyModelType { - return new ModelType({ - name: opts.name || this.name, - properties: Object.assign({}, this.properties, opts.properties), - initializers: this.initializers.concat(opts.initializers || []), - preProcessor: opts.preProcessor || this.preProcessor, - postProcessor: opts.postProcessor || this.postProcessor - }) - } - - actions(fn: (self: Instance) => A) { - const actionInitializer = (self: Instance) => { - this.instantiateActions(self, fn(self)) - return self - } - return this.cloneAndEnhance({ initializers: [actionInitializer] }) - } - - private instantiateActions(self: this["T"], actions: ModelActions): void { - // check if return is correct - if (!isPlainObject(actions)) - throw fail(`actions initializer should return a plain object containing actions`) - - // bind actions to the object created - Object.keys(actions).forEach((name) => { - // warn if preprocessor was given - if (name === PRE_PROCESS_SNAPSHOT) - throw fail( - `Cannot define action '${PRE_PROCESS_SNAPSHOT}', it should be defined using 'type.preProcessSnapshot(fn)' instead` - ) - // warn if postprocessor was given - if (name === POST_PROCESS_SNAPSHOT) - throw fail( - `Cannot define action '${POST_PROCESS_SNAPSHOT}', it should be defined using 'type.postProcessSnapshot(fn)' instead` - ) - - let action2 = actions[name] - - // apply hook composition - let baseAction = (self as any)[name] - if (name in Hook && baseAction) { - let specializedAction = action2 - action2 = function () { - baseAction.apply(null, arguments) - specializedAction.apply(null, arguments) - } - } - - // the goal of this is to make sure actions using "this" can call themselves, - // while still allowing the middlewares to register them - const middlewares = (action2 as any).$mst_middleware // make sure middlewares are not lost - let boundAction = action2.bind(actions) - boundAction._isFlowAction = (action2 as FunctionWithFlag)._isFlowAction || false - boundAction.$mst_middleware = middlewares - const actionInvoker = createActionInvoker(self as any, name, boundAction) - actions[name] = actionInvoker - - // See #646, allow models to be mocked - ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(self, name, actionInvoker) - }) - } - - named: MT["named"] = (name) => { - return this.cloneAndEnhance({ name }) - } - - props: MT["props"] = (properties) => { - return this.cloneAndEnhance({ properties }) - } - - volatile(fn: (self: Instance) => TP) { - if (typeof fn !== "function") { - throw fail( - `You passed an ${typeof fn} to volatile state as an argument, when function is expected` - ) - } - const stateInitializer = (self: Instance) => { - this.instantiateVolatileState(self, fn(self)) - return self - } - return this.cloneAndEnhance({ initializers: [stateInitializer] }) - } - - private instantiateVolatileState( - self: this["T"], - state: { - [key: string]: any - } - ): void { - // check views return - if (!isPlainObject(state)) - throw fail(`volatile state initializer should return a plain object containing state`) - set(self, state) - } - - extend( - fn: (self: Instance) => { actions?: A; views?: V; state?: VS } - ) { - const initializer = (self: Instance) => { - const { actions, views, state, ...rest } = fn(self) - for (let key in rest) - throw fail( - `The \`extend\` function should return an object with a subset of the fields 'actions', 'views' and 'state'. Found invalid key '${key}'` - ) - if (state) this.instantiateVolatileState(self, state) - if (views) this.instantiateViews(self, views) - if (actions) this.instantiateActions(self, actions) - return self - } - return this.cloneAndEnhance({ initializers: [initializer] }) - } - - views(fn: (self: Instance) => V) { - const viewInitializer = (self: Instance) => { - this.instantiateViews(self, fn(self)) - return self - } - return this.cloneAndEnhance({ initializers: [viewInitializer] }) - } - - private instantiateViews(self: this["T"], views: Object): void { - // check views return - if (!isPlainObject(views)) - throw fail(`views initializer should return a plain object containing views`) - Object.getOwnPropertyNames(views).forEach((key) => { - // is this a computed property? - const descriptor = Object.getOwnPropertyDescriptor(views, key)! - if ("get" in descriptor) { - defineProperty(self, key, descriptor) - makeObservable(self, { [key]: computed } as any) - } else if (typeof descriptor.value === "function") { - // this is a view function, merge as is! - // See #646, allow models to be mocked - ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)( - self, - key, - descriptor.value - ) - } else { - throw fail(`A view member should either be a function or getter based property`) - } - }) - } - - preProcessSnapshot: MT["preProcessSnapshot"] = (preProcessor) => { - const currentPreprocessor = this.preProcessor - if (!currentPreprocessor) return this.cloneAndEnhance({ preProcessor }) - else - return this.cloneAndEnhance({ - preProcessor: (snapshot) => currentPreprocessor(preProcessor(snapshot)) - }) - } - - postProcessSnapshot: MT["postProcessSnapshot"] = (postProcessor) => { - const currentPostprocessor = this.postProcessor - if (!currentPostprocessor) return this.cloneAndEnhance({ postProcessor }) - else - return this.cloneAndEnhance({ - postProcessor: (snapshot) => postProcessor(currentPostprocessor(snapshot)) - }) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - const value = isStateTreeNode(initialValue) - ? initialValue - : this.applySnapshotPreProcessor(initialValue) - return createObjectNode(this, parent, subpath, environment, value) - // Optimization: record all prop- view- and action names after first construction, and generate an optimal base class - // that pre-reserves all these fields for fast object-member lookups - } - - initializeChildNodes(objNode: this["N"], initialSnapshot: any = {}): IChildNodesMap { - const type = objNode.type as this - const result: IChildNodesMap = {} - type.forAllProps((name, childType) => { - result[name] = childType.instantiate( - objNode, - name, - undefined, - (initialSnapshot as any)[name] - ) - }) - return result - } - - createNewInstance(childNodes: IChildNodesMap): this["T"] { - const options = { ...mobxShallow, name: this.name } - return observable.object(childNodes, EMPTY_OBJECT, options) as any - } - - finalizeNewInstance(node: this["N"], instance: this["T"]): void { - addHiddenFinalProp(instance, "toString", objectTypeToString) - - this.forAllProps((name) => { - _interceptReads(instance, name, node.unbox) - }) - - this.initializers.reduce((self, fn) => fn(self), instance) - intercept(instance, this.willChange) - observe(instance, this.didChange) - } - - private willChange(chg: IObjectWillChange): IObjectWillChange | null { - // TODO: mobx typings don't seem to take into account that newValue can be set even when removing a prop - const change = chg as IObjectWillChange & { newValue?: any } - - const node = getStateTreeNode(change.object) - const subpath = change.name as string - node.assertWritable({ subpath }) - const childType = (node.type as this).properties[subpath] - // only properties are typed, state are stored as-is references - if (childType) { - typecheckInternal(childType, change.newValue) - change.newValue = childType.reconcile( - node.getChildNode(subpath), - change.newValue, - node, - subpath - ) - } - return change - } - - private didChange(chg: IObjectDidChange) { - // TODO: mobx typings don't seem to take into account that newValue can be set even when removing a prop - const change = chg as IObjectWillChange & { newValue?: any; oldValue?: any } - - const childNode = getStateTreeNode(change.object) - const childType = (childNode.type as this).properties[change.name as string] - if (!childType) { - // don't emit patches for volatile state - return - } - const oldChildValue = change.oldValue ? change.oldValue.snapshot : undefined - childNode.emitPatch( - { - op: "replace", - path: escapeJsonPath(change.name as string), - value: change.newValue.snapshot, - oldValue: oldChildValue - }, - childNode - ) - } - - getChildren(node: this["N"]): ReadonlyArray { - const res: AnyNode[] = [] - this.forAllProps((name) => { - res.push(this.getChildNode(node, name)) - }) - return res - } - - getChildNode(node: this["N"], key: string): AnyNode { - if (!(key in this.properties)) throw fail("Not a value property: " + key) - const adm = _getAdministration(node.storedValue, key) - const childNode = adm.raw?.() - if (!childNode) throw fail("Node not available for property " + key) - return childNode - } - - getSnapshot(node: this["N"], applyPostProcess = true): this["S"] { - const res = {} as any - this.forAllProps((name, type) => { - try { - // TODO: FIXME, make sure the observable ref is used! - const atom = getAtom(node.storedValue, name) - ;(atom as any).reportObserved() - } catch (e) { - throw fail(`${name} property is declared twice`) - } - res[name] = this.getChildNode(node, name).snapshot - }) - if (applyPostProcess) { - return this.applySnapshotPostProcessor(res) - } - return res - } - - processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { - const processed = {} as any - Object.keys(childNodes).forEach((key) => { - processed[key] = childNodes[key].getSnapshot() - }) - return this.applySnapshotPostProcessor(processed) - } - - applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { - if (!(patch.op === "replace" || patch.op === "add")) { - throw fail(`object does not support operation ${patch.op}`) - } - ;(node.storedValue as any)[subpath] = patch.value - } - - applySnapshot(node: this["N"], snapshot: this["C"]): void { - typecheckInternal(this, snapshot) - const preProcessedSnapshot = this.applySnapshotPreProcessor(snapshot) - this.forAllProps((name) => { - ;(node.storedValue as any)[name] = preProcessedSnapshot[name] - }) - } - - applySnapshotPreProcessor(snapshot: any) { - const processor = this.preProcessor - return processor ? processor.call(null, snapshot) : snapshot - } - - applySnapshotPostProcessor(snapshot: any) { - const postProcessor = this.postProcessor - if (postProcessor) return postProcessor.call(null, snapshot) - return snapshot - } - - getChildType(propertyName: string): IAnyType { - assertIsString(propertyName, 1) - - return this.properties[propertyName] - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - let snapshot = this.applySnapshotPreProcessor(value) - - if (!isPlainObject(snapshot)) { - return typeCheckFailure(context, snapshot, "Value is not a plain object") - } - - return flattenTypeErrors( - this.propertyNames.map((key) => - this.properties[key].validate( - snapshot[key], - getContextForPath(context, key, this.properties[key]) - ) - ) - ) - } - - private forAllProps(fn: (name: string, type: IAnyType) => void) { - this.propertyNames.forEach((key) => fn(key, this.properties[key])) - } - - describe() { - // optimization: cache - return ( - "{ " + - this.propertyNames - .map((key) => key + ": " + this.properties[key].describe()) - .join("; ") + - " }" - ) - } - - getDefaultSnapshot(): this["C"] { - return EMPTY_OBJECT as this["C"] - } - - removeChild(node: this["N"], subpath: string) { - ;(node.storedValue as any)[subpath] = undefined - } -} -ModelType.prototype.applySnapshot = action(ModelType.prototype.applySnapshot) - -export function model

( - name: string, - properties?: P -): IModelType, {}> -export function model

( - properties?: P -): IModelType, {}> -/** - * `types.model` - Creates a new model type by providing a name, properties, volatile state and actions. - * - * See the [model type](/concepts/trees#creating-models) description or the [getting started](intro/getting-started.md#getting-started-1) tutorial. - */ -export function model(...args: any[]): any { - if (devMode() && typeof args[0] !== "string" && args[1]) { - throw fail( - "Model creation failed. First argument must be a string when two arguments are provided" - ) - } - - const name = typeof args[0] === "string" ? args.shift() : "AnonymousModel" - const properties = args.shift() || {} - return new ModelType({ name, properties }) -} - -// TODO: this can be simplified in TS3, since we can transform _NotCustomized to unknown, since unkonwn & X = X -// and then back unknown to _NotCustomized if needed -/** @hidden */ -export type _CustomJoin = A extends _NotCustomized ? B : A & B - -// generated with C:\VSProjects\github\mobx-state-tree-upstream\packages\mobx-state-tree\scripts\generate-compose-type.js -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType): IModelType, _CustomJoin> -// prettier-ignore -export function compose(A: IModelType, B: IModelType): IModelType, _CustomJoin> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType): IModelType>, _CustomJoin>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType): IModelType>, _CustomJoin>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType): IModelType>>, _CustomJoin>>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType): IModelType>>, _CustomJoin>>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType): IModelType>>>, _CustomJoin>>>> -// prettier-ignore -export function compose(A: - IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType): IModelType>>>, _CustomJoin>>>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType): IModelType>>>>, _CustomJoin>>>>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType): IModelType>>>>, _CustomJoin>>>>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType): IModelType>>>>>, _CustomJoin>>>>>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType): IModelType>>>>>, _CustomJoin>>>>>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType): IModelType>>>>>>, _CustomJoin>>>>>>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType): IModelType>>>>>>, _CustomJoin>>>>>>> -// prettier-ignore -export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType, I: IModelType): IModelType>>>>>>>, _CustomJoin>>>>>>>> -// prettier-ignore -export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType, I: IModelType): IModelType>>>>>>>, _CustomJoin>>>>>>>> - -/** - * `types.compose` - Composes a new model from one or more existing model types. - * This method can be invoked in two forms: - * Given 2 or more model types, the types are composed into a new Type. - * Given first parameter as a string and 2 or more model types, - * the types are composed into a new Type with the given name - */ -export function compose(...args: any[]): any { - // TODO: just join the base type names if no name is provided - const hasTypename = typeof args[0] === "string" - const typeName: string = hasTypename ? args[0] : "AnonymousModel" - if (hasTypename) { - args.shift() - } - - // check all parameters - if (devMode()) { - args.forEach((type, i) => { - assertArg(type, isModelType, "mobx-state-tree model type", hasTypename ? i + 2 : i + 1) - }) - } - - return args - .reduce((prev, cur) => - prev.cloneAndEnhance({ - name: prev.name + "_" + cur.name, - properties: cur.properties, - initializers: cur.initializers, - preProcessor: (snapshot: any) => - cur.applySnapshotPreProcessor(prev.applySnapshotPreProcessor(snapshot)), - postProcessor: (snapshot: any) => - cur.applySnapshotPostProcessor(prev.applySnapshotPostProcessor(snapshot)) - }) - ) - .named(typeName) -} - -/** - * Returns if a given value represents a model type. - * - * @param type - * @returns - */ -export function isModelType(type: IAnyType): type is IT { - return isType(type) && (type.flags & TypeFlags.Object) > 0 -} diff --git a/packages/mobx-state-tree/src/types/index.ts b/packages/mobx-state-tree/src/types/index.ts deleted file mode 100644 index bca56f476..000000000 --- a/packages/mobx-state-tree/src/types/index.ts +++ /dev/null @@ -1,64 +0,0 @@ -// we import the types to re-export them inside types. -import { - enumeration, - model, - compose, - custom, - reference, - safeReference, - union, - optional, - literal, - maybe, - maybeNull, - refinement, - string, - boolean, - number, - integer, - float, - finite, - DatePrimitive, - map, - array, - frozen, - identifier, - identifierNumber, - late, - lazy, - undefinedType, - nullType, - snapshotProcessor -} from "../internal" - -export const types = { - enumeration, - model, - compose, - custom, - reference, - safeReference, - union, - optional, - literal, - maybe, - maybeNull, - refinement, - string, - boolean, - number, - integer, - float, - finite, - Date: DatePrimitive, - map, - array, - frozen, - identifier, - identifierNumber, - late, - lazy, - undefined: undefinedType, - null: nullType, - snapshotProcessor -} diff --git a/packages/mobx-state-tree/src/types/utility-types/custom.ts b/packages/mobx-state-tree/src/types/utility-types/custom.ts deleted file mode 100644 index 9298b0c32..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/custom.ts +++ /dev/null @@ -1,142 +0,0 @@ -import { - createScalarNode, - SimpleType, - IType, - TypeFlags, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - AnyObjectNode -} from "../../internal" - -export interface CustomTypeOptions { - /** Friendly name */ - name: string - /** given a serialized value and environment, how to turn it into the target type */ - fromSnapshot(snapshot: S, env?: any): T - /** return the serialization of the current value */ - toSnapshot(value: T): S - /** if true, this is a converted value, if false, it's a snapshot */ - isTargetType(value: T | S): boolean - /** a non empty string is assumed to be a validation error */ - getValidationMessage(snapshot: S): string - // TODO: isSnapshotEqual - // TODO: isValueEqual -} - -/** - * `types.custom` - Creates a custom type. Custom types can be used for arbitrary immutable values, that have a serializable representation. For example, to create your own Date representation, Decimal type etc. - * - * The signature of the options is: - * ```ts - * export interface CustomTypeOptions { - * // Friendly name - * name: string - * // given a serialized value and environment, how to turn it into the target type - * fromSnapshot(snapshot: S, env: any): T - * // return the serialization of the current value - * toSnapshot(value: T): S - * // if true, this is a converted value, if false, it's a snapshot - * isTargetType(value: T | S): value is T - * // a non empty string is assumed to be a validation error - * getValidationMessage?(snapshot: S): string - * } - * ``` - * - * Example: - * ```ts - * const DecimalPrimitive = types.custom({ - * name: "Decimal", - * fromSnapshot(value: string) { - * return new Decimal(value) - * }, - * toSnapshot(value: Decimal) { - * return value.toString() - * }, - * isTargetType(value: string | Decimal): boolean { - * return value instanceof Decimal - * }, - * getValidationMessage(value: string): string { - * if (/^-?\d+\.\d+$/.test(value)) return "" // OK - * return `'${value}' doesn't look like a valid decimal number` - * } - * }) - * - * const Wallet = types.model({ - * balance: DecimalPrimitive - * }) - * ``` - * - * @param options - * @returns - */ -export function custom(options: CustomTypeOptions): IType { - return new CustomType(options) -} - -/** - * @internal - * @hidden - */ -export class CustomType extends SimpleType { - readonly flags = TypeFlags.Custom - - constructor(protected readonly options: CustomTypeOptions) { - super(options.name) - } - - describe() { - return this.name - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (this.options.isTargetType(value)) return typeCheckSuccess() - - const typeError: string = this.options.getValidationMessage(value as S) - if (typeError) { - return typeCheckFailure( - context, - value, - `Invalid value for type '${this.name}': ${typeError}` - ) - } - return typeCheckSuccess() - } - - getSnapshot(node: this["N"]): S { - return this.options.toSnapshot(node.storedValue) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: S | T - ): this["N"] { - const valueToStore: T = this.options.isTargetType(initialValue) - ? (initialValue as T) - : this.options.fromSnapshot(initialValue as S, parent && parent.root.environment) - return createScalarNode(this, parent, subpath, environment, valueToStore) - } - - reconcile(current: this["N"], value: S | T, parent: AnyObjectNode, subpath: string): this["N"] { - const isSnapshot = !this.options.isTargetType(value) - // in theory customs use scalar nodes which cannot be detached, but still... - if (!current.isDetaching) { - const unchanged = - current.type === this && - (isSnapshot ? value === current.snapshot : value === current.storedValue) - if (unchanged) { - current.setParent(parent, subpath) - return current - } - } - const valueToStore: T = isSnapshot - ? this.options.fromSnapshot(value as S, parent.root.environment) - : (value as T) - const newNode = this.instantiate(parent, subpath, undefined, valueToStore) - current.die() // noop if detaching - return newNode - } -} diff --git a/packages/mobx-state-tree/src/types/utility-types/identifier.ts b/packages/mobx-state-tree/src/types/utility-types/identifier.ts deleted file mode 100644 index aceafc3a6..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/identifier.ts +++ /dev/null @@ -1,166 +0,0 @@ -import { - fail, - createScalarNode, - SimpleType, - TypeFlags, - isType, - IValidationContext, - IValidationResult, - typeCheckFailure, - ModelType, - typeCheckSuccess, - ISimpleType, - AnyObjectNode, - ScalarNode, - assertArg -} from "../../internal" - -abstract class BaseIdentifierType extends SimpleType { - readonly flags = TypeFlags.Identifier - - constructor(name: string, private readonly validType: "string" | "number") { - super(name) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] - ): this["N"] { - if (!parent || !(parent.type instanceof ModelType)) - throw fail(`Identifier types can only be instantiated as direct child of a model type`) - - return createScalarNode(this, parent, subpath, environment, initialValue) - } - - reconcile(current: this["N"], newValue: this["C"], parent: AnyObjectNode, subpath: string) { - // we don't consider detaching here since identifier are scalar nodes, and scalar nodes cannot be detached - if (current.storedValue !== newValue) - throw fail( - `Tried to change identifier from '${current.storedValue}' to '${newValue}'. Changing identifiers is not allowed.` - ) - current.setParent(parent, subpath) - return current - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (typeof value !== this.validType) { - return typeCheckFailure( - context, - value, - `Value is not a valid ${this.describe()}, expected a ${this.validType}` - ) - } - return typeCheckSuccess() - } -} - -/** - * @internal - * @hidden - */ -export class IdentifierType extends BaseIdentifierType { - readonly flags = TypeFlags.Identifier - - constructor() { - super(`identifier`, "string") - } - - describe() { - return `identifier` - } -} - -/** - * @internal - * @hidden - */ -export class IdentifierNumberType extends BaseIdentifierType { - constructor() { - super("identifierNumber", "number") - } - - getSnapshot(node: ScalarNode): number { - return node.storedValue - } - - describe() { - return `identifierNumber` - } -} - -/** - * `types.identifier` - Identifiers are used to make references, lifecycle events and reconciling works. - * Inside a state tree, for each type can exist only one instance for each given identifier. - * For example there couldn't be 2 instances of user with id 1. If you need more, consider using references. - * Identifier can be used only as type property of a model. - * This type accepts as parameter the value type of the identifier field that can be either string or number. - * - * Example: - * ```ts - * const Todo = types.model("Todo", { - * id: types.identifier, - * title: types.string - * }) - * ``` - * - * @returns - */ -export const identifier: ISimpleType = new IdentifierType() - -/** - * `types.identifierNumber` - Similar to `types.identifier`. This one will serialize from / to a number when applying snapshots - * - * Example: - * ```ts - * const Todo = types.model("Todo", { - * id: types.identifierNumber, - * title: types.string - * }) - * ``` - * - * @returns - */ -export const identifierNumber: ISimpleType = new IdentifierNumberType() - -/** - * Returns if a given value represents an identifier type. - * - * @param type - * @returns - */ -export function isIdentifierType( - type: IT -): type is IT { - return isType(type) && (type.flags & TypeFlags.Identifier) > 0 -} - -/** - * Valid types for identifiers. - */ -export type ReferenceIdentifier = string | number - -/** - * @internal - * @hidden - */ -export function normalizeIdentifier(id: ReferenceIdentifier): string { - return "" + id -} - -/** - * @internal - * @hidden - */ -export function isValidIdentifier(id: any): id is ReferenceIdentifier { - return typeof id === "string" || typeof id === "number" -} - -/** - * @internal - * @hidden - */ -export function assertIsValidIdentifier(id: ReferenceIdentifier, argNumber: number | number[]) { - assertArg(id, isValidIdentifier, "string or number (identifier)", argNumber) -} diff --git a/packages/mobx-state-tree/src/types/utility-types/late.ts b/packages/mobx-state-tree/src/types/utility-types/late.ts deleted file mode 100644 index 56f46fe05..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/late.ts +++ /dev/null @@ -1,143 +0,0 @@ -import { - fail, - BaseType, - IValidationContext, - IValidationResult, - TypeFlags, - isType, - IAnyType, - typeCheckSuccess, - AnyObjectNode, - ExtractNodeType, - cannotDetermineSubtype, - devMode -} from "../../internal" - -class Late extends BaseType< - IT["CreationType"], - IT["SnapshotType"], - IT["TypeWithoutSTN"], - ExtractNodeType -> { - private _subType?: IT - - get flags() { - return (this._subType ? this._subType.flags : 0) | TypeFlags.Late - } - - getSubType(mustSucceed: true): IT - getSubType(mustSucceed: false): IT | undefined - getSubType(mustSucceed: boolean): IT | undefined { - if (!this._subType) { - let t = undefined - try { - t = this._definition() - } catch (e) { - if (e instanceof ReferenceError) - // can happen in strict ES5 code when a definition is self refering - t = undefined - else throw e - } - if (mustSucceed && t === undefined) - throw fail( - "Late type seems to be used too early, the definition (still) returns undefined" - ) - if (t) { - if (devMode() && !isType(t)) - throw fail( - "Failed to determine subtype, make sure types.late returns a type definition." - ) - this._subType = t - } - } - return this._subType - } - - constructor(name: string, private readonly _definition: () => IT) { - super(name) - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - return this.getSubType(true).instantiate(parent, subpath, environment, initialValue) as any - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - return this.getSubType(true).reconcile(current, newValue, parent, subpath) as any - } - - describe() { - const t = this.getSubType(false) - return t ? t.name : "" - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - const t = this.getSubType(false) - if (!t) { - // See #916; the variable the definition closure is pointing to wasn't defined yet, so can't be evaluted yet here - return typeCheckSuccess() - } - return t.validate(value, context) - } - - isAssignableFrom(type: IAnyType) { - const t = this.getSubType(false) - return t ? t.isAssignableFrom(type) : false - } - - getSubTypes() { - const subtype = this.getSubType(false) - return subtype ? subtype : cannotDetermineSubtype - } -} - -export function late(type: () => T): T -export function late(name: string, type: () => T): T -/** - * `types.late` - Defines a type that gets implemented later. This is useful when you have to deal with circular dependencies. - * Please notice that when defining circular dependencies TypeScript isn't smart enough to inference them. - * - * Example: - * ```ts - * // TypeScript isn't smart enough to infer self referencing types. - * const Node = types.model({ - * children: types.array(types.late((): IAnyModelType => Node)) // then typecast each array element to Instance - * }) - * ``` - * - * @param name The name to use for the type that will be returned. - * @param type A function that returns the type that will be defined. - * @returns - */ -export function late(nameOrType: any, maybeType?: () => IAnyType): IAnyType { - const name = typeof nameOrType === "string" ? nameOrType : `late(${nameOrType.toString()})` - const type = typeof nameOrType === "string" ? maybeType : nameOrType - // checks that the type is actually a late type - if (devMode()) { - if (!(typeof type === "function" && type.length === 0)) - throw fail( - "Invalid late type, expected a function with zero arguments that returns a type, got: " + - type - ) - } - return new Late(name, type) -} - -/** - * Returns if a given value represents a late type. - * - * @param type - * @returns - */ -export function isLateType(type: IT): type is IT { - return isType(type) && (type.flags & TypeFlags.Late) > 0 -} diff --git a/packages/mobx-state-tree/src/types/utility-types/lazy.ts b/packages/mobx-state-tree/src/types/utility-types/lazy.ts deleted file mode 100644 index 3fd6570fd..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/lazy.ts +++ /dev/null @@ -1,120 +0,0 @@ -import { action, IObservableArray, observable, when } from "mobx" -import { AnyNode } from "../../core/node/BaseNode" -import { IType } from "../../core/type/type" -import { - IValidationContext, - IValidationResult, - TypeFlags, - typeCheckSuccess, - AnyObjectNode, - SimpleType, - createScalarNode, - deepFreeze, - isSerializable, - typeCheckFailure -} from "../../internal" - -interface LazyOptions, U> { - loadType: () => Promise - shouldLoadPredicate: (parent: U) => boolean -} - -export function lazy, U>( - name: string, - options: LazyOptions -): T { - // TODO: fix this unknown casting to be stricter - return new Lazy(name, options) as unknown as T -} - -/** - * @internal - * @hidden - */ -export class Lazy, U> extends SimpleType { - flags = TypeFlags.Lazy - - private loadedType: T | null = null - private pendingNodeList: IObservableArray = observable.array() - - constructor(name: string, private readonly options: LazyOptions) { - super(name) - - when( - () => - this.pendingNodeList.length > 0 && - this.pendingNodeList.some( - (node) => - node.isAlive && - this.options.shouldLoadPredicate(node.parent ? node.parent.value : null) - ), - () => { - this.options.loadType().then( - action((type: T) => { - this.loadedType = type - this.pendingNodeList.forEach((node) => { - if (!node.parent) return - if (!this.loadedType) return - - node.parent.applyPatches([ - { - op: "replace", - path: `/${node.subpath}`, - value: node.snapshot - } - ]) - }) - }) - ) - } - ) - } - - describe() { - return `` - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - value: this["C"] - ): this["N"] { - if (this.loadedType) { - return this.loadedType.instantiate(parent, subpath, environment, value) as this["N"] - } - - const node = createScalarNode(this, parent, subpath, environment, deepFreeze(value)) - this.pendingNodeList.push(node) - - when( - () => !node.isAlive, - () => this.pendingNodeList.splice(this.pendingNodeList.indexOf(node), 1) - ) - - return node - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (this.loadedType) { - return this.loadedType.validate(value, context) - } - if (!isSerializable(value)) { - return typeCheckFailure(context, value, "Value is not serializable and cannot be lazy") - } - return typeCheckSuccess() - } - - reconcile(current: this["N"], value: T, parent: AnyObjectNode, subpath: string): this["N"] { - if (this.loadedType) { - current.die() - return this.loadedType.instantiate( - parent, - subpath, - parent.environment, - value - ) as this["N"] - } - return super.reconcile(current, value, parent, subpath) - } -} diff --git a/packages/mobx-state-tree/src/types/utility-types/literal.ts b/packages/mobx-state-tree/src/types/utility-types/literal.ts deleted file mode 100644 index f6a3be9b6..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/literal.ts +++ /dev/null @@ -1,88 +0,0 @@ -import { - fail, - isPrimitive, - createScalarNode, - ISimpleType, - TypeFlags, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - isType, - Primitives, - AnyObjectNode, - SimpleType, - devMode -} from "../../internal" -import { assertArg } from "../../utils" - -/** - * @internal - * @hidden - */ -export class Literal extends SimpleType { - readonly value: T - readonly flags = TypeFlags.Literal - - constructor(value: T) { - super(JSON.stringify(value)) - this.value = value - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] - ): this["N"] { - return createScalarNode(this, parent, subpath, environment, initialValue) - } - - describe() { - return JSON.stringify(this.value) - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (isPrimitive(value) && value === this.value) { - return typeCheckSuccess() - } - return typeCheckFailure( - context, - value, - `Value is not a literal ${JSON.stringify(this.value)}` - ) - } -} - -/** - * `types.literal` - The literal type will return a type that will match only the exact given type. - * The given value must be a primitive, in order to be serialized to a snapshot correctly. - * You can use literal to match exact strings for example the exact male or female string. - * - * Example: - * ```ts - * const Person = types.model({ - * name: types.string, - * gender: types.union(types.literal('male'), types.literal('female')) - * }) - * ``` - * - * @param value The value to use in the strict equal check - * @returns - */ -export function literal(value: S): ISimpleType { - // check that the given value is a primitive - assertArg(value, isPrimitive, "primitive", 1) - - return new Literal(value) -} - -/** - * Returns if a given value represents a literal type. - * - * @param type - * @returns - */ -export function isLiteralType>(type: IT): type is IT { - return isType(type) && (type.flags & TypeFlags.Literal) > 0 -} diff --git a/packages/mobx-state-tree/src/types/utility-types/optional.ts b/packages/mobx-state-tree/src/types/utility-types/optional.ts deleted file mode 100644 index 9cefe6f69..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/optional.ts +++ /dev/null @@ -1,236 +0,0 @@ -import { - isStateTreeNode, - IType, - TypeFlags, - isType, - IValidationContext, - IValidationResult, - typecheckInternal, - typeCheckSuccess, - fail, - IAnyType, - AnyObjectNode, - BaseType, - assertIsType, - ExtractCSTWithSTN, - devMode -} from "../../internal" - -type IFunctionReturn = () => T - -type IOptionalValue = C | IFunctionReturn - -/** @hidden */ -export type ValidOptionalValue = string | boolean | number | null | undefined - -/** @hidden */ -export type ValidOptionalValues = [ValidOptionalValue, ...ValidOptionalValue[]] - -/** - * @hidden - * @internal - */ -export class OptionalValue< - IT extends IAnyType, - OptionalVals extends ValidOptionalValues -> extends BaseType< - IT["CreationType"] | OptionalVals[number], - IT["SnapshotType"], - IT["TypeWithoutSTN"] -> { - get flags() { - return this._subtype.flags | TypeFlags.Optional - } - - constructor( - private readonly _subtype: IT, - private readonly _defaultValue: IOptionalValue, - readonly optionalValues: OptionalVals - ) { - super(_subtype.name) - } - - describe() { - return this._subtype.describe() + "?" - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - if (this.optionalValues.indexOf(initialValue) >= 0) { - const defaultInstanceOrSnapshot = this.getDefaultInstanceOrSnapshot() - return this._subtype.instantiate( - parent, - subpath, - environment, - defaultInstanceOrSnapshot - ) - } - return this._subtype.instantiate(parent, subpath, environment, initialValue) - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - return this._subtype.reconcile( - current, - this.optionalValues.indexOf(newValue) < 0 && this._subtype.is(newValue) - ? newValue - : this.getDefaultInstanceOrSnapshot(), - parent, - subpath - ) - } - - getDefaultInstanceOrSnapshot(): this["C"] | this["T"] { - const defaultInstanceOrSnapshot = - typeof this._defaultValue === "function" - ? (this._defaultValue as IFunctionReturn)() - : this._defaultValue - - // while static values are already snapshots and checked on types.optional - // generator functions must always be rechecked just in case - if (typeof this._defaultValue === "function") { - typecheckInternal(this, defaultInstanceOrSnapshot) - } - - return defaultInstanceOrSnapshot - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - // defaulted values can be skipped - if (this.optionalValues.indexOf(value) >= 0) { - return typeCheckSuccess() - } - // bounce validation to the sub-type - return this._subtype.validate(value, context) - } - - isAssignableFrom(type: IAnyType) { - return this._subtype.isAssignableFrom(type) - } - - getSubTypes() { - return this._subtype - } -} - -/** @hidden */ -export type OptionalDefaultValueOrFunction = - | IT["CreationType"] - | IT["SnapshotType"] - | (() => ExtractCSTWithSTN) - -/** @hidden */ -export interface IOptionalIType - extends IType< - IT["CreationType"] | OptionalVals[number], - IT["SnapshotType"], - IT["TypeWithoutSTN"] - > {} - -function checkOptionalPreconditions( - type: IAnyType, - defaultValueOrFunction: OptionalDefaultValueOrFunction -) { - // make sure we never pass direct instances - if (typeof defaultValueOrFunction !== "function" && isStateTreeNode(defaultValueOrFunction)) { - throw fail( - "default value cannot be an instance, pass a snapshot or a function that creates an instance/snapshot instead" - ) - } - assertIsType(type, 1) - if (devMode()) { - // we only check default values if they are passed directly - // if they are generator functions they will be checked once they are generated - // we don't check generator function results here to avoid generating a node just for type-checking purposes - // which might generate side-effects - if (typeof defaultValueOrFunction !== "function") { - typecheckInternal(type, defaultValueOrFunction) - } - } -} - -export function optional( - type: IT, - defaultValueOrFunction: OptionalDefaultValueOrFunction -): IOptionalIType -export function optional( - type: IT, - defaultValueOrFunction: OptionalDefaultValueOrFunction, - optionalValues: OptionalVals -): IOptionalIType -/** - * `types.optional` - Can be used to create a property with a default value. - * - * Depending on the third argument (`optionalValues`) there are two ways of operation: - * - If the argument is not provided, then if a value is not provided in the snapshot (`undefined` or missing), - * it will default to the provided `defaultValue` - * - If the argument is provided, then if the value in the snapshot matches one of the optional values inside the array then it will - * default to the provided `defaultValue`. Additionally, if one of the optional values inside the array is `undefined` then a missing - * property is also valid. - * - * Note that it is also possible to include values of the same type as the intended subtype as optional values, - * in this case the optional value will be transformed into the `defaultValue` (e.g. `types.optional(types.string, "unnamed", [undefined, ""])` - * will transform the snapshot values `undefined` (and therefore missing) and empty strings into the string `"unnamed"` when it gets - * instantiated). - * - * If `defaultValue` is a function, the function will be invoked for every new instance. - * Applying a snapshot in which the optional value is one of the optional values (or `undefined`/_not_ present if none are provided) causes the - * value to be reset. - * - * Example: - * ```ts - * const Todo = types.model({ - * title: types.string, - * subtitle1: types.optional(types.string, "", [null]), - * subtitle2: types.optional(types.string, "", [null, undefined]), - * done: types.optional(types.boolean, false), - * created: types.optional(types.Date, () => new Date()), - * }) - * - * // if done is missing / undefined it will become false - * // if created is missing / undefined it will get a freshly generated timestamp - * // if subtitle1 is null it will default to "", but it cannot be missing or undefined - * // if subtitle2 is null or undefined it will default to ""; since it can be undefined it can also be missing - * const todo = Todo.create({ title: "Get coffee", subtitle1: null }) - * ``` - * - * @param type - * @param defaultValueOrFunction - * @param optionalValues an optional array with zero or more primitive values (string, number, boolean, null or undefined) - * that will be converted into the default. `[ undefined ]` is assumed when none is provided - * @returns - */ -export function optional( - type: IT, - defaultValueOrFunction: OptionalDefaultValueOrFunction, - optionalValues?: OptionalVals -): IOptionalIType { - checkOptionalPreconditions(type, defaultValueOrFunction) - - return new OptionalValue( - type, - defaultValueOrFunction, - optionalValues ? optionalValues : undefinedAsOptionalValues - ) -} - -const undefinedAsOptionalValues: [undefined] = [undefined] - -/** - * Returns if a value represents an optional type. - * - * @template IT - * @param type - * @returns - */ -export function isOptionalType(type: IT): type is IT { - return isType(type) && (type.flags & TypeFlags.Optional) > 0 -} diff --git a/packages/mobx-state-tree/src/types/utility-types/reference.ts b/packages/mobx-state-tree/src/types/utility-types/reference.ts deleted file mode 100644 index 27609a082..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/reference.ts +++ /dev/null @@ -1,591 +0,0 @@ -import { - getStateTreeNode, - isStateTreeNode, - createScalarNode, - IType, - TypeFlags, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - fail, - IAnyType, - IAnyStateTreeNode, - IAnyComplexType, - Hook, - IDisposer, - maybe, - isModelType, - IMaybe, - NodeLifeCycle, - ReferenceIdentifier, - normalizeIdentifier, - getIdentifier, - applyPatch, - AnyNode, - AnyObjectNode, - SimpleType, - assertIsType, - isValidIdentifier, - IStateTreeNode, - devMode -} from "../../internal" - -export type OnReferenceInvalidatedEvent = { - parent: IAnyStateTreeNode - invalidTarget: STN | undefined - invalidId: ReferenceIdentifier - replaceRef: (newRef: STN | null | undefined) => void - removeRef: () => void - cause: "detach" | "destroy" | "invalidSnapshotReference" -} - -export type OnReferenceInvalidated = ( - event: OnReferenceInvalidatedEvent -) => void - -function getInvalidationCause(hook: Hook): "detach" | "destroy" | undefined { - switch (hook) { - case Hook.beforeDestroy: - return "destroy" - case Hook.beforeDetach: - return "detach" - default: - return undefined - } -} - -/** @hidden */ -export type ReferenceT = IT["TypeWithoutSTN"] & - IStateTreeNode> - -class StoredReference { - readonly identifier!: ReferenceIdentifier - node!: AnyNode - - private resolvedReference?: { - node: AnyObjectNode - lastCacheModification: string - } - - constructor(value: ReferenceT | ReferenceIdentifier, private readonly targetType: IT) { - if (isValidIdentifier(value)) { - this.identifier = value - } else if (isStateTreeNode(value)) { - const targetNode = getStateTreeNode(value) - if (!targetNode.identifierAttribute) - throw fail(`Can only store references with a defined identifier attribute.`) - const id = targetNode.unnormalizedIdentifier - if (id === null || id === undefined) { - throw fail(`Can only store references to tree nodes with a defined identifier.`) - } - this.identifier = id - } else { - throw fail(`Can only store references to tree nodes or identifiers, got: '${value}'`) - } - } - - private updateResolvedReference(node: AnyNode) { - const normalizedId = normalizeIdentifier(this.identifier) - const root = node.root - const lastCacheModification = root.identifierCache!.getLastCacheModificationPerId( - normalizedId - ) - if ( - !this.resolvedReference || - this.resolvedReference.lastCacheModification !== lastCacheModification - ) { - const { targetType } = this - // reference was initialized with the identifier of the target - - const target = root.identifierCache!.resolve(targetType, normalizedId) - - if (!target) { - throw new InvalidReferenceError( - `[mobx-state-tree] Failed to resolve reference '${this.identifier}' to type '${this.targetType.name}' (from node: ${node.path})` - ) - } - - this.resolvedReference = { - node: target!, - lastCacheModification: lastCacheModification - } - } - } - - get resolvedValue(): ReferenceT { - this.updateResolvedReference(this.node) - return this.resolvedReference!.node.value - } -} - -/** - * @internal - * @hidden - */ -export class InvalidReferenceError extends Error { - constructor(m: string) { - super(m) - - Object.setPrototypeOf(this, InvalidReferenceError.prototype) - } -} - -/** - * @internal - * @hidden - */ -export abstract class BaseReferenceType extends SimpleType< - ReferenceIdentifier, - ReferenceIdentifier, - IT["TypeWithoutSTN"] -> { - readonly flags = TypeFlags.Reference - - constructor( - protected readonly targetType: IT, - private readonly onInvalidated?: OnReferenceInvalidated> - ) { - super(`reference(${targetType.name})`) - } - - describe() { - return this.name - } - - isAssignableFrom(type: IAnyType): boolean { - return this.targetType.isAssignableFrom(type) - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - return isValidIdentifier(value) - ? typeCheckSuccess() - : typeCheckFailure( - context, - value, - "Value is not a valid identifier, which is a string or a number" - ) - } - - private fireInvalidated( - cause: "detach" | "destroy" | "invalidSnapshotReference", - storedRefNode: this["N"], - referenceId: ReferenceIdentifier, - refTargetNode: AnyObjectNode | null - ) { - // to actually invalidate a reference we need an alive parent, - // since it is a scalar value (immutable-ish) and we need to change it - // from the parent - const storedRefParentNode = storedRefNode.parent - if (!storedRefParentNode || !storedRefParentNode.isAlive) { - return - } - const storedRefParentValue = storedRefParentNode.storedValue - if (!storedRefParentValue) { - return - } - this.onInvalidated!({ - cause, - parent: storedRefParentValue, - invalidTarget: refTargetNode ? refTargetNode.storedValue : undefined, - invalidId: referenceId, - replaceRef(newRef) { - applyPatch(storedRefNode.root.storedValue, { - op: "replace", - value: newRef, - path: storedRefNode.path - }) - }, - removeRef() { - if (isModelType(storedRefParentNode.type)) { - this.replaceRef(undefined as any) - } else { - applyPatch(storedRefNode.root.storedValue, { - op: "remove", - path: storedRefNode.path - }) - } - } - }) - } - - private addTargetNodeWatcher( - storedRefNode: this["N"], - referenceId: ReferenceIdentifier - ): IDisposer | undefined { - // this will make sure the target node becomes created - const refTargetValue = this.getValue(storedRefNode) - if (!refTargetValue) { - return undefined - } - const refTargetNode = getStateTreeNode(refTargetValue) - - const hookHandler = (_: AnyNode, refTargetNodeHook: Hook) => { - const cause = getInvalidationCause(refTargetNodeHook) - if (!cause) { - return - } - this.fireInvalidated(cause, storedRefNode, referenceId, refTargetNode) - } - - const refTargetDetachHookDisposer = refTargetNode.registerHook( - Hook.beforeDetach, - hookHandler - ) - const refTargetDestroyHookDisposer = refTargetNode.registerHook( - Hook.beforeDestroy, - hookHandler - ) - - return () => { - refTargetDetachHookDisposer() - refTargetDestroyHookDisposer() - } - } - - protected watchTargetNodeForInvalidations( - storedRefNode: this["N"], - identifier: ReferenceIdentifier, - customGetSet: ReferenceOptionsGetSet | undefined - ) { - if (!this.onInvalidated) { - return - } - - let onRefTargetDestroyedHookDisposer: IDisposer | undefined - - // get rid of the watcher hook when the stored ref node is destroyed - // detached is ignored since scalar nodes (where the reference resides) cannot be detached - storedRefNode.registerHook(Hook.beforeDestroy, () => { - if (onRefTargetDestroyedHookDisposer) { - onRefTargetDestroyedHookDisposer() - } - }) - - const startWatching = (sync: boolean) => { - // re-create hook in case the stored ref gets reattached - if (onRefTargetDestroyedHookDisposer) { - onRefTargetDestroyedHookDisposer() - } - - // make sure the target node is actually there and initialized - const storedRefParentNode = storedRefNode.parent - const storedRefParentValue = storedRefParentNode && storedRefParentNode.storedValue - if (storedRefParentNode && storedRefParentNode.isAlive && storedRefParentValue) { - let refTargetNodeExists: boolean - if (customGetSet) { - refTargetNodeExists = !!customGetSet.get(identifier, storedRefParentValue) - } else { - refTargetNodeExists = storedRefNode.root.identifierCache!.has( - this.targetType, - normalizeIdentifier(identifier) - ) - } - - if (!refTargetNodeExists) { - // we cannot change the reference in sync mode - // since we are in the middle of a reconciliation/instantiation and the change would be overwritten - // for those cases just let the wrong reference be assigned and fail upon usage - // (like current references do) - // this means that effectively this code will only run when it is created from a snapshot - if (!sync) { - this.fireInvalidated( - "invalidSnapshotReference", - storedRefNode, - identifier, - null - ) - } - } else { - onRefTargetDestroyedHookDisposer = this.addTargetNodeWatcher( - storedRefNode, - identifier - ) - } - } - } - - if (storedRefNode.state === NodeLifeCycle.FINALIZED) { - // already attached, so the whole tree is ready - startWatching(true) - } else { - if (!storedRefNode.isRoot) { - // start watching once the whole tree is ready - storedRefNode.root.registerHook(Hook.afterCreationFinalization, () => { - // make sure to attach it so it can start listening - if (storedRefNode.parent) { - storedRefNode.parent.createObservableInstanceIfNeeded() - } - }) - } - // start watching once the node is attached somewhere / parent changes - storedRefNode.registerHook(Hook.afterAttach, () => { - startWatching(false) - }) - } - } -} - -/** - * @internal - * @hidden - */ -export class IdentifierReferenceType extends BaseReferenceType { - constructor(targetType: IT, onInvalidated?: OnReferenceInvalidated>) { - super(targetType, onInvalidated) - } - - getValue(storedRefNode: this["N"]) { - if (!storedRefNode.isAlive) return undefined - const storedRef: StoredReference = storedRefNode.storedValue - return storedRef.resolvedValue as any - } - - getSnapshot(storedRefNode: this["N"]) { - const ref: StoredReference = storedRefNode.storedValue - return ref.identifier - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - const identifier = isStateTreeNode(initialValue) - ? getIdentifier(initialValue)! - : initialValue - const storedRef = new StoredReference(initialValue, this.targetType as any) - const storedRefNode: this["N"] = createScalarNode( - this, - parent, - subpath, - environment, - storedRef as any - ) - storedRef.node = storedRefNode - this.watchTargetNodeForInvalidations(storedRefNode, identifier as string, undefined) - return storedRefNode - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - if (!current.isDetaching && current.type === this) { - const compareByValue = isStateTreeNode(newValue) - const ref: StoredReference = current.storedValue - if ( - (!compareByValue && ref.identifier === newValue) || - (compareByValue && ref.resolvedValue === newValue) - ) { - current.setParent(parent, subpath) - return current - } - } - const newNode = this.instantiate(parent, subpath, undefined, newValue) - current.die() // noop if detaching - return newNode - } -} - -/** - * @internal - * @hidden - */ -export class CustomReferenceType extends BaseReferenceType { - constructor( - targetType: IT, - private readonly options: ReferenceOptionsGetSet, - onInvalidated?: OnReferenceInvalidated> - ) { - super(targetType, onInvalidated) - } - - getValue(storedRefNode: this["N"]) { - if (!storedRefNode.isAlive) return undefined as any - const referencedNode = this.options.get( - storedRefNode.storedValue, - storedRefNode.parent ? storedRefNode.parent.storedValue : null - ) - return referencedNode - } - - getSnapshot(storedRefNode: this["N"]) { - return storedRefNode.storedValue - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - newValue: this["C"] | this["T"] - ): this["N"] { - const identifier = isStateTreeNode(newValue) - ? this.options.set(newValue as any, parent ? parent.storedValue : null) - : newValue - const storedRefNode: this["N"] = createScalarNode( - this, - parent, - subpath, - environment, - identifier as any - ) - this.watchTargetNodeForInvalidations(storedRefNode, identifier as string, this.options) - return storedRefNode - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - const newIdentifier = isStateTreeNode(newValue) - ? this.options.set(newValue as any, current ? current.storedValue : null) - : newValue - if ( - !current.isDetaching && - current.type === this && - current.storedValue === newIdentifier - ) { - current.setParent(parent, subpath) - return current - } - const newNode = this.instantiate(parent, subpath, undefined, newIdentifier) - current.die() // noop if detaching - return newNode - } -} - -export interface ReferenceOptionsGetSet { - get(identifier: ReferenceIdentifier, parent: IAnyStateTreeNode | null): ReferenceT - set(value: ReferenceT, parent: IAnyStateTreeNode | null): ReferenceIdentifier -} - -export interface ReferenceOptionsOnInvalidated { - // called when the current reference is about to become invalid - onInvalidated: OnReferenceInvalidated> -} - -export type ReferenceOptions = - | ReferenceOptionsGetSet - | ReferenceOptionsOnInvalidated - | (ReferenceOptionsGetSet & ReferenceOptionsOnInvalidated) - -/** @hidden */ -export interface IReferenceType - extends IType {} - -/** - * `types.reference` - Creates a reference to another type, which should have defined an identifier. - * See also the [reference and identifiers](https://github.com/mobxjs/mobx-state-tree#references-and-identifiers) section. - */ -export function reference( - subType: IT, - options?: ReferenceOptions -): IReferenceType { - assertIsType(subType, 1) - if (devMode()) { - if (arguments.length === 2 && typeof arguments[1] === "string") { - // istanbul ignore next - throw fail( - "References with base path are no longer supported. Please remove the base path." - ) - } - } - - const getSetOptions = options ? (options as ReferenceOptionsGetSet) : undefined - const onInvalidated = options - ? (options as ReferenceOptionsOnInvalidated).onInvalidated - : undefined - - if (getSetOptions && (getSetOptions.get || getSetOptions.set)) { - if (devMode()) { - if (!getSetOptions.get || !getSetOptions.set) { - throw fail( - "reference options must either contain both a 'get' and a 'set' method or none of them" - ) - } - } - - return new CustomReferenceType( - subType, - { - get: getSetOptions.get, - set: getSetOptions.set - }, - onInvalidated - ) - } else { - return new IdentifierReferenceType(subType, onInvalidated) - } -} - -/** - * Returns if a given value represents a reference type. - * - * @param type - * @returns - */ -export function isReferenceType>(type: IT): type is IT { - return (type.flags & TypeFlags.Reference) > 0 -} - -export function safeReference( - subType: IT, - options: (ReferenceOptionsGetSet | {}) & { - acceptsUndefined: false - onInvalidated?: OnReferenceInvalidated> - } -): IReferenceType -export function safeReference( - subType: IT, - options?: (ReferenceOptionsGetSet | {}) & { - acceptsUndefined?: boolean - onInvalidated?: OnReferenceInvalidated> - } -): IMaybe> -/** - * `types.safeReference` - A safe reference is like a standard reference, except that it accepts the undefined value by default - * and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps - * when the reference it is pointing to gets detached/destroyed. - * - * The optional options parameter object accepts a parameter named `acceptsUndefined`, which is set to true by default, so it is suitable - * for model properties. - * When used inside collections (arrays/maps), it is recommended to set this option to false so it can't take undefined as value, - * which is usually the desired in those cases. - * Additionally, the optional options parameter object accepts a parameter named `onInvalidated`, which will be called when the reference target node that the reference is pointing to is about to be detached/destroyed - * - * Strictly speaking it is a `types.maybe(types.reference(X))` (when `acceptsUndefined` is set to true, the default) and - * `types.reference(X)` (when `acceptsUndefined` is set to false), both of them with a customized `onInvalidated` option. - * - * @param subType - * @param options - * @returns - */ -export function safeReference( - subType: IT, - options?: (ReferenceOptionsGetSet | {}) & { - acceptsUndefined?: boolean - onInvalidated?: OnReferenceInvalidated> - } -): IReferenceType | IMaybe> { - const refType = reference(subType, { - ...options, - onInvalidated(ev) { - if (options && options.onInvalidated) { - options.onInvalidated(ev) - } - ev.removeRef() - } - }) - - if (options && options.acceptsUndefined === false) { - return refType - } else { - return maybe(refType) - } -} diff --git a/packages/mobx-state-tree/src/types/utility-types/refinement.ts b/packages/mobx-state-tree/src/types/utility-types/refinement.ts deleted file mode 100644 index 97f0fb331..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/refinement.ts +++ /dev/null @@ -1,128 +0,0 @@ -import { - isStateTreeNode, - getStateTreeNode, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - isType, - fail, - TypeFlags, - IAnyType, - AnyObjectNode, - BaseType, - ExtractNodeType, - assertIsType, - devMode -} from "../../internal" -import { assertIsString, assertIsFunction } from "../../utils" - -class Refinement extends BaseType< - IT["CreationType"], - IT["SnapshotType"], - IT["TypeWithoutSTN"], - ExtractNodeType -> { - get flags() { - return this._subtype.flags | TypeFlags.Refinement - } - - constructor( - name: string, - private readonly _subtype: IT, - private readonly _predicate: (v: IT["CreationType"]) => boolean, - private readonly _message: (v: IT["CreationType"]) => string - ) { - super(name) - } - - describe() { - return this.name - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - // create the child type - return this._subtype.instantiate(parent, subpath, environment, initialValue) as any - } - - isAssignableFrom(type: IAnyType) { - return this._subtype.isAssignableFrom(type) - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - const subtypeErrors = this._subtype.validate(value, context) - if (subtypeErrors.length > 0) return subtypeErrors - - const snapshot = isStateTreeNode(value) ? getStateTreeNode(value).snapshot : value - - if (!this._predicate(snapshot)) { - return typeCheckFailure(context, value, this._message(value)) - } - - return typeCheckSuccess() - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - return this._subtype.reconcile(current, newValue, parent, subpath) as any - } - - getSubTypes() { - return this._subtype - } -} - -export function refinement( - name: string, - type: IT, - predicate: (snapshot: IT["CreationType"]) => boolean, - message?: string | ((v: IT["CreationType"]) => string) -): IT -export function refinement( - type: IT, - predicate: (snapshot: IT["CreationType"]) => boolean, - message?: string | ((v: IT["CreationType"]) => string) -): IT - -/** - * `types.refinement` - Creates a type that is more specific than the base type, e.g. `types.refinement(types.string, value => value.length > 5)` to create a type of strings that can only be longer then 5. - * - * @param name - * @param type - * @param predicate - * @returns - */ -export function refinement(...args: any[]): IAnyType { - const name = typeof args[0] === "string" ? args.shift() : isType(args[0]) ? args[0].name : null - const type = args[0] - const predicate = args[1] - const message = args[2] - ? args[2] - : (v: any) => "Value does not respect the refinement predicate" - // ensures all parameters are correct - assertIsType(type, [1, 2]) - assertIsString(name, 1) - assertIsFunction(predicate, [2, 3]) - assertIsFunction(message, [3, 4]) - - return new Refinement(name, type, predicate, message) -} - -/** - * Returns if a given value is a refinement type. - * - * @param type - * @returns - */ -export function isRefinementType(type: IT): type is IT { - return (type.flags & TypeFlags.Refinement) > 0 -} diff --git a/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts b/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts deleted file mode 100644 index 2b0e91a58..000000000 --- a/packages/mobx-state-tree/src/types/utility-types/snapshotProcessor.ts +++ /dev/null @@ -1,268 +0,0 @@ -import { - IType, - IAnyType, - BaseType, - isStateTreeNode, - IValidationContext, - IValidationResult, - AnyObjectNode, - TypeFlags, - ExtractNodeType, - assertIsType, - isType, - getSnapshot, - devMode, - ComplexType, - typeCheckFailure, - isUnionType -} from "../../internal" - -/** @hidden */ -declare const $mstNotCustomized: unique symbol - -/** @hidden */ -const $preProcessorFailed: unique symbol = Symbol("$preProcessorFailed") - -/** @hidden */ -// tslint:disable-next-line:class-name -export interface _NotCustomized { - // only for typings - readonly [$mstNotCustomized]: undefined -} -/** @hidden */ -export type _CustomOrOther = Custom extends _NotCustomized ? Other : Custom - -class SnapshotProcessor extends BaseType< - _CustomOrOther, - _CustomOrOther, - IT["TypeWithoutSTN"], - ExtractNodeType -> { - get flags() { - return this._subtype.flags | TypeFlags.SnapshotProcessor - } - - constructor( - private readonly _subtype: IT, - private readonly _processors: ISnapshotProcessors< - IT["CreationType"], - CustomC, - IT["SnapshotType"], - CustomS - >, - name?: string - ) { - super(name || _subtype.name) - } - - describe() { - return `snapshotProcessor(${this._subtype.describe()})` - } - - private preProcessSnapshot(sn: this["C"]): IT["CreationType"] { - if (this._processors.preProcessor) { - return this._processors.preProcessor.call(null, sn) - } - return sn as any - } - - private preProcessSnapshotSafe(sn: this["C"]): IT["CreationType"] | typeof $preProcessorFailed { - try { - return this.preProcessSnapshot(sn) - } catch (e) { - return $preProcessorFailed - } - } - - private postProcessSnapshot(sn: IT["SnapshotType"]): this["S"] { - if (this._processors.postProcessor) { - return this._processors.postProcessor.call(null, sn) as any - } - return sn - } - - private _fixNode(node: this["N"]): void { - // the node has to use these methods rather than the original type ones - proxyNodeTypeMethods(node.type, this, "create") - - const oldGetSnapshot = node.getSnapshot - node.getSnapshot = () => { - return this.postProcessSnapshot(oldGetSnapshot.call(node)) as any - } - if (!isUnionType(this._subtype)) { - node.getReconciliationType = () => { - return this - } - } - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - const processedInitialValue = isStateTreeNode(initialValue) - ? initialValue - : this.preProcessSnapshot(initialValue) - const node = this._subtype.instantiate( - parent, - subpath, - environment, - processedInitialValue - ) as any - this._fixNode(node) - return node - } - - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - const node = this._subtype.reconcile( - current, - isStateTreeNode(newValue) ? newValue : this.preProcessSnapshot(newValue), - parent, - subpath - ) as any - if (node !== current) { - this._fixNode(node) - } - return node - } - - getSnapshot(node: this["N"], applyPostProcess: boolean = true): this["S"] { - const sn = this._subtype.getSnapshot(node) - return applyPostProcess ? this.postProcessSnapshot(sn) : sn - } - - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - const processedSn = this.preProcessSnapshotSafe(value) - if (processedSn === $preProcessorFailed) { - return typeCheckFailure(context, value, "Failed to preprocess value") - } - return this._subtype.validate(processedSn, context) - } - - getSubTypes() { - return this._subtype - } - - is(thing: any): thing is any { - const value = isType(thing) - ? this._subtype - : isStateTreeNode(thing) - ? getSnapshot(thing, false) - : this.preProcessSnapshotSafe(thing) - if (value === $preProcessorFailed) { - return false - } - return this._subtype.validate(value, [{ path: "", type: this._subtype }]).length === 0 - } - - isAssignableFrom(type: IAnyType): boolean { - return this._subtype.isAssignableFrom(type) - } - - isMatchingSnapshotId(current: this["N"], snapshot: this["C"]): boolean { - if (!(this._subtype instanceof ComplexType)) { - return false - } - const processedSn = this.preProcessSnapshot(snapshot) - return this._subtype.isMatchingSnapshotId(current as any, processedSn) - } -} - -function proxyNodeTypeMethods( - nodeType: any, - snapshotProcessorType: any, - ...methods: (keyof SnapshotProcessor)[] -) { - for (const method of methods) { - nodeType[method] = snapshotProcessorType[method].bind(snapshotProcessorType) - } -} - -// public API - -/** - * A type that has its snapshots processed. - */ -export interface ISnapshotProcessor - extends IType< - _CustomOrOther, - _CustomOrOther, - IT["TypeWithoutSTN"] - > {} - -/** - * Snapshot processors. - */ -export interface ISnapshotProcessors { - /** - * Function that transforms an input snapshot. - */ - preProcessor?(snapshot: CustomC): C - /** - * Function that transforms an output snapshot. - * @param snapshot - */ - postProcessor?(snapshot: S): CustomS -} - -/** - * `types.snapshotProcessor` - Runs a pre/post snapshot processor before/after serializing a given type. - * - * Example: - * ```ts - * const Todo1 = types.model({ text: types.string }) - * // in the backend the text type must be null when empty - * interface BackendTodo { - * text: string | null - * } - * const Todo2 = types.snapshotProcessor(Todo1, { - * // from snapshot to instance - * preProcessor(sn: BackendTodo) { - * return { - * text: sn.text || ""; - * } - * }, - * // from instance to snapshot - * postProcessor(sn): BackendTodo { - * return { - * text: !sn.text ? null : sn.text - * } - * } - * }) - * ``` - * - * @param type Type to run the processors over. - * @param processors Processors to run. - * @param name Type name, or undefined to inherit the inner type one. - * @returns - */ -export function snapshotProcessor< - IT extends IAnyType, - CustomC = _NotCustomized, - CustomS = _NotCustomized ->( - type: IT, - processors: ISnapshotProcessors, - name?: string -): ISnapshotProcessor { - assertIsType(type, 1) - if (devMode()) { - if (processors.postProcessor && typeof processors.postProcessor !== "function") { - // istanbul ignore next - throw fail("postSnapshotProcessor must be a function") - } - if (processors.preProcessor && typeof processors.preProcessor !== "function") { - // istanbul ignore next - throw fail("preSnapshotProcessor must be a function") - } - } - - return new SnapshotProcessor(type, processors, name) -} diff --git a/packages/mobx-state-tree/src/utils.ts b/packages/mobx-state-tree/src/utils.ts deleted file mode 100644 index d23016100..000000000 --- a/packages/mobx-state-tree/src/utils.ts +++ /dev/null @@ -1,504 +0,0 @@ -import { - isObservableArray, - isObservableObject, - _getGlobalState, - defineProperty as mobxDefineProperty -} from "mobx" -import { Primitives } from "./core/type/type" - -const plainObjectString = Object.toString() - -/** - * @internal - * @hidden - */ -declare const global: any - -/** - * @internal - * @hidden - */ -export const EMPTY_ARRAY: ReadonlyArray = Object.freeze([]) - -/** - * @internal - * @hidden - */ -export const EMPTY_OBJECT: {} = Object.freeze({}) - -/** - * @internal - * @hidden - */ -export const mobxShallow = _getGlobalState().useProxies - ? { deep: false } - : { deep: false, proxy: false } -Object.freeze(mobxShallow) - -/** - * A generic disposer. - */ -export type IDisposer = () => void - -/** - * @internal - * @hidden - */ -export function fail(message = "Illegal state"): Error { - return new Error("[mobx-state-tree] " + message) -} - -/** - * @internal - * @hidden - */ -export function identity(_: any): any { - return _ -} - -/** - * @internal - * @hidden - */ -export function noop() {} - -/** - * @internal - * @hidden - */ -export const isInteger = Number.isInteger - -/** - * @internal - * @hidden - */ -export function isFloat(val: any) { - return Number(val) === val && val % 1 !== 0 -} - -/** - * @internal - * @hidden - */ -export function isFinite(val: any) { - return Number.isFinite(val) -} - -/** - * @internal - * @hidden - */ -export function isArray(val: any): val is any[] { - return Array.isArray(val) || isObservableArray(val) -} - -/** - * @internal - * @hidden - */ -export function asArray(val: undefined | null | T | T[] | ReadonlyArray): T[] { - if (!val) return EMPTY_ARRAY as any as T[] - if (isArray(val)) return val as T[] - return [val] as T[] -} - -/** - * @internal - * @hidden - */ -export function extend(a: A, b: B): A & B -/** - * @internal - * @hidden - */ -export function extend(a: A, b: B, c: C): A & B & C -/** - * @internal - * @hidden - */ -export function extend(a: A, b: B, c: C, d: D): A & B & C & D -/** - * @internal - * @hidden - */ -export function extend(a: any, ...b: any[]): any -/** - * @internal - * @hidden - */ -export function extend(a: any, ...b: any[]) { - for (let i = 0; i < b.length; i++) { - const current = b[i] - for (let key in current) a[key] = current[key] - } - return a -} - -/** - * @internal - * @hidden - */ -export function isPlainObject(value: any): value is { [k: string]: any } { - if (value === null || typeof value !== "object") return false - const proto = Object.getPrototypeOf(value) - if (proto == null) return true - return proto.constructor?.toString() === plainObjectString -} - -/** - * @internal - * @hidden - */ -export function isMutable(value: any) { - return ( - value !== null && - typeof value === "object" && - !(value instanceof Date) && - !(value instanceof RegExp) - ) -} - -/** - * @internal - * @hidden - */ -export function isPrimitive(value: any, includeDate = true): value is Primitives { - return ( - value === null || - value === undefined || - typeof value === "string" || - typeof value === "number" || - typeof value === "boolean" || - (includeDate && value instanceof Date) - ) -} - -/** - * @internal - * @hidden - * Freeze a value and return it (if not in production) - */ -export function freeze(value: T): T { - if (!devMode()) return value - return isPrimitive(value) || isObservableArray(value) ? value : Object.freeze(value) -} - -/** - * @internal - * @hidden - * Recursively freeze a value (if not in production) - */ -export function deepFreeze(value: T): T { - if (!devMode()) return value - freeze(value) - - if (isPlainObject(value)) { - Object.keys(value).forEach((propKey) => { - if ( - !isPrimitive((value as any)[propKey]) && - !Object.isFrozen((value as any)[propKey]) - ) { - deepFreeze((value as any)[propKey]) - } - }) - } - - return value -} - -/** - * @internal - * @hidden - */ -export function isSerializable(value: any) { - return typeof value !== "function" -} - -/** - * @internal - * @hidden - */ -export function defineProperty(object: any, key: PropertyKey, descriptor: PropertyDescriptor) { - isObservableObject(object) - ? mobxDefineProperty(object, key, descriptor) - : Object.defineProperty(object, key, descriptor) -} - -/** - * @internal - * @hidden - */ -export function addHiddenFinalProp(object: any, propName: string, value: any) { - defineProperty(object, propName, { - enumerable: false, - writable: false, - configurable: true, - value - }) -} - -/** - * @internal - * @hidden - */ -export function addHiddenWritableProp(object: any, propName: string, value: any) { - defineProperty(object, propName, { - enumerable: false, - writable: true, - configurable: true, - value - }) -} - -/** - * @internal - * @hidden - */ -export type ArgumentTypes = F extends (...args: infer A) => any ? A : never - -/** - * @internal - * @hidden - */ -class EventHandler { - private handlers: F[] = [] - - get hasSubscribers(): boolean { - return this.handlers.length > 0 - } - - register(fn: F, atTheBeginning = false): IDisposer { - if (atTheBeginning) { - this.handlers.unshift(fn) - } else { - this.handlers.push(fn) - } - return () => { - this.unregister(fn) - } - } - - has(fn: F): boolean { - return this.handlers.indexOf(fn) >= 0 - } - - unregister(fn: F) { - const index = this.handlers.indexOf(fn) - if (index >= 0) { - this.handlers.splice(index, 1) - } - } - - clear() { - this.handlers.length = 0 - } - - emit(...args: ArgumentTypes) { - // make a copy just in case it changes - const handlers = this.handlers.slice() - handlers.forEach((f) => f(...args)) - } -} - -/** - * @internal - * @hidden - */ -export class EventHandlers { - private eventHandlers?: { [k in keyof E]?: EventHandler } - - hasSubscribers(event: keyof E): boolean { - const handler = this.eventHandlers && this.eventHandlers[event] - return !!handler && handler!.hasSubscribers - } - - register(event: N, fn: E[N], atTheBeginning = false): IDisposer { - if (!this.eventHandlers) { - this.eventHandlers = {} - } - let handler = this.eventHandlers[event] - if (!handler) { - handler = this.eventHandlers[event] = new EventHandler() - } - return handler.register(fn, atTheBeginning) - } - - has(event: N, fn: E[N]): boolean { - const handler = this.eventHandlers && this.eventHandlers[event] - return !!handler && handler!.has(fn) - } - - unregister(event: N, fn: E[N]) { - const handler = this.eventHandlers && this.eventHandlers[event] - if (handler) { - handler!.unregister(fn) - } - } - - clear(event: N) { - if (this.eventHandlers) { - delete this.eventHandlers[event] - } - } - - clearAll() { - this.eventHandlers = undefined - } - - emit(event: N, ...args: ArgumentTypes) { - const handler = this.eventHandlers && this.eventHandlers[event] - if (handler) { - ;(handler!.emit as any)(...args) - } - } -} - -const prototypeHasOwnProperty = Object.prototype.hasOwnProperty - -/** - * @internal - * @hidden - */ -export function hasOwnProperty(object: Object, propName: string) { - return prototypeHasOwnProperty.call(object, propName) -} - -/** - * @internal - * @hidden - */ -export function argsToArray(args: IArguments): any[] { - const res = new Array(args.length) - for (let i = 0; i < args.length; i++) res[i] = args[i] - return res -} - -/** - * @internal - * @hidden - */ -export function stringStartsWith(str: string, beginning: string) { - return str.indexOf(beginning) === 0 -} - -/** - * @internal - * @hidden - */ -export type DeprecatedFunction = Function & { ids?: { [id: string]: true } } - -/** - * @internal - * @hidden - */ -export const deprecated: DeprecatedFunction = function (id: string, message: string): void { - // skip if running production - if (!devMode()) return - // warn if hasn't been warned before - if (deprecated.ids && !deprecated.ids.hasOwnProperty(id)) { - warnError("Deprecation warning: " + message) - } - // mark as warned to avoid duplicate warn message - if (deprecated.ids) deprecated.ids[id] = true -} -deprecated.ids = {} - -/** - * @internal - * @hidden - */ -export function warnError(msg: string) { - console.warn(new Error(`[mobx-state-tree] ${msg}`)) -} -/** - * @internal - * @hidden - */ -export function isTypeCheckingEnabled() { - return ( - devMode() || - (typeof process !== "undefined" && process.env && process.env.ENABLE_TYPE_CHECK === "true") - ) -} - -/** - * @internal - * @hidden - */ -export function devMode() { - return process.env.NODE_ENV !== "production" -} - -/** - * @internal - * @hidden - */ -export function assertArg( - value: T, - fn: (value: T) => boolean, - typeName: string, - argNumber: number | number[] -) { - if (devMode()) { - if (!fn(value)) { - // istanbul ignore next - throw fail( - `expected ${typeName} as argument ${asArray(argNumber).join( - " or " - )}, got ${value} instead` - ) - } - } -} - -/** - * @internal - * @hidden - */ -export function assertIsFunction(value: Function, argNumber: number | number[]) { - assertArg(value, (fn) => typeof fn === "function", "function", argNumber) -} - -/** - * @internal - * @hidden - */ -export function assertIsNumber( - value: number, - argNumber: number | number[], - min?: number, - max?: number -) { - assertArg(value, (n) => typeof n === "number", "number", argNumber) - if (min !== undefined) { - assertArg(value, (n) => n >= min, `number greater than ${min}`, argNumber) - } - if (max !== undefined) { - assertArg(value, (n) => n <= max, `number lesser than ${max}`, argNumber) - } -} - -/** - * @internal - * @hidden - */ -export function assertIsString(value: string, argNumber: number | number[], canBeEmpty = true) { - assertArg(value, (s) => typeof s === "string", "string", argNumber) - if (!canBeEmpty) { - assertArg(value, (s) => s !== "", "not empty string", argNumber) - } -} - -/** - * @internal - * @hidden - */ -export function setImmediateWithFallback(fn: (...args: any[]) => void) { - if (typeof queueMicrotask === "function") { - queueMicrotask(fn) - } else if (typeof setImmediate === "function") { - setImmediate(fn) - } else { - setTimeout(fn, 1) - } -} diff --git a/packages/mobx-state-tree/tsconfig.json b/packages/mobx-state-tree/tsconfig.json deleted file mode 100644 index 24978c52b..000000000 --- a/packages/mobx-state-tree/tsconfig.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "extends": "../../tsconfig.base.json", - "compilerOptions": { - "outDir": "lib/" - }, - "files": ["src/index.ts"] -} diff --git a/packages/mobx-state-tree/tslint.json b/packages/mobx-state-tree/tslint.json deleted file mode 100644 index 40a18cdec..000000000 --- a/packages/mobx-state-tree/tslint.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": "../../tslint.json" -} diff --git a/packages/mobx-state-tree/typedocconfig.js b/packages/mobx-state-tree/typedocconfig.js deleted file mode 100644 index d40b4e146..000000000 --- a/packages/mobx-state-tree/typedocconfig.js +++ /dev/null @@ -1,14 +0,0 @@ -module.exports = { - src: ["src/index.ts"], - module: "commonjs", - excludeNotExported: true, - excludePrivate: true, - excludeProtected: true, - mode: "file", - readme: "none", - out: "../../docs/API", - theme: "docusaurus", - tsconfig: "tsconfig.json", - listInvalidSymbolLinks: true, - mdHideSources: true -} diff --git a/packages/mobx-state-tree/wallaby.js b/packages/mobx-state-tree/wallaby.js deleted file mode 100644 index 38ff4cfd9..000000000 --- a/packages/mobx-state-tree/wallaby.js +++ /dev/null @@ -1,22 +0,0 @@ -module.exports = function (wallaby) { - return { - files: ["src/**/*.ts"], - - tests: ["__tests__/**/*.ts"], - - compilers: { - "**/*.ts": wallaby.compilers.typeScript({ - module: "commonjs", - files: ["src/index.ts"] - }) - }, - - env: { - type: "node" - }, - - testFramework: "ava", - - debug: true - } -} diff --git a/rollup.base-config.js b/rollup.base-config.js deleted file mode 100644 index e61dc4920..000000000 --- a/rollup.base-config.js +++ /dev/null @@ -1,34 +0,0 @@ -import * as path from "path" -import filesize from "rollup-plugin-filesize" -import resolve from "rollup-plugin-node-resolve" -import { terser } from "rollup-plugin-terser" -import replace from "rollup-plugin-replace" - -const devPlugins = () => [resolve(), filesize()] - -// For umd builds, set process.env.NODE_ENV to "development" since 'process' is not available in the browser -const devPluginsUmd = () => [ - resolve(), - replace({ "process.env.NODE_ENV": JSON.stringify("development") }), - filesize() -] - -const prodPlugins = () => [ - resolve(), - replace({ "process.env.NODE_ENV": JSON.stringify("production") }), - terser(), - filesize() -] - -export const baseConfig = ({ input, globals, umdName, external, outFile, format, mode }) => ({ - input, - output: { - file: path.join("./dist", outFile), - format: format, - globals, - name: format === "umd" ? umdName : undefined - }, - external, - plugins: - mode === "production" ? prodPlugins() : format === "umd" ? devPluginsUmd() : devPlugins() -}) diff --git a/rollup.config.js b/rollup.config.js new file mode 100644 index 000000000..d21023afb --- /dev/null +++ b/rollup.config.js @@ -0,0 +1,43 @@ +import * as path from "path" +import filesize from "rollup-plugin-filesize" +import resolve from "rollup-plugin-node-resolve" +import { terser } from "rollup-plugin-terser" +import replace from "rollup-plugin-replace" + +const devPlugins = () => [resolve(), filesize()] + +// For umd builds, set process.env.NODE_ENV to "development" since 'process' is not available in the browser +const devPluginsUmd = () => [ + resolve(), + replace({ "process.env.NODE_ENV": JSON.stringify("development") }), + filesize() +] + +const prodPlugins = () => [ + resolve(), + replace({ "process.env.NODE_ENV": JSON.stringify("production") }), + terser(), + filesize() +] + +const config = (outFile, format, mode) => ({ + input: "./lib/index.js", + output: { + file: path.join("./dist", outFile), + format: format, + globals: { + mobx: "mobx" + }, + name: format === "umd" ? "mobxStateTree" : undefined + }, + external: ["mobx"], + plugins: mode === "production" ? prodPlugins() : format === "umd" ? devPluginsUmd() : devPlugins() +}) + +export default [ + config("mobx-state-tree.js", "cjs", "development"), + config("mobx-state-tree.min.js", "cjs", "production"), + config("mobx-state-tree.umd.js", "umd", "development"), + config("mobx-state-tree.umd.min.js", "umd", "production"), + config("mobx-state-tree.module.js", "es", "development") +] diff --git a/scripts/generate-compose-type.js b/scripts/generate-compose-type.js new file mode 100644 index 000000000..d30928684 --- /dev/null +++ b/scripts/generate-compose-type.js @@ -0,0 +1,53 @@ +const { getDeclaration } = require("./generate-shared") + +let str = `// generated with ${__filename}\n` + +const minArgs = 2 +const maxArgs = 10 +const preParam = "name: string, " + +const returnTypeTransform = (rt) => { + // [['PA', 'PB', 'PC'], ['OA', 'OB', 'OC'], ['FCA', 'FCB', 'FCC'], ['FSA', 'FSB', 'FSC']] + // -> + // [['PA', 'PB', 'PC'], no change + // ['OA', 'OB', 'OC'], no change + // ['_CustomJoin>'] + // ['_CustomJoin>']] + + const [props, others, fixedC, fixedS] = rt + + function customJoin(left) { + if (left.length === 1) { + return left[0] + } + const [a, ...rest] = left + return `_CustomJoin<${a}, ${customJoin(rest)}>` + } + + return [props, others, [customJoin(fixedC)], [customJoin(fixedS)]] +} + +for (let i = minArgs; i < maxArgs; i++) { + str += getDeclaration( + "compose", + "IModelType", + ["P", "O", "FC", "FS"], + i, + preParam, + "&", + "IModelType", + returnTypeTransform + ) + str += getDeclaration( + "compose", + "IModelType", + ["P", "O", "FC", "FS"], + i, + null, + "&", + "IModelType", + returnTypeTransform + ) +} + +console.log(str) diff --git a/scripts/generate-shared.js b/scripts/generate-shared.js new file mode 100644 index 000000000..68fb6ace9 --- /dev/null +++ b/scripts/generate-shared.js @@ -0,0 +1,55 @@ +const alfa = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + +function getTemplateVar(templateVar, argNumber) { + return `${templateVar}${alfa[argNumber]}` +} + +function getTemplateVars(templateVars, argNumber) { + return templateVars.map((tv) => getTemplateVar(tv, argNumber)) +} + +exports.getDeclaration = function getDeclaration( + funcName, + type, + templateVars, + args, + preParam, + operationChar, + outType = type, + allReturnTypesTransform = (x) => x +) { + let str = "// prettier-ignore\n" + + let allTemplateVars = [] + for (let i = 0; i < args; i++) { + allTemplateVars = allTemplateVars.concat(getTemplateVars(templateVars, i)) + } + allTemplateVars = allTemplateVars.map((tv) => + tv.startsWith("P") ? `${tv} extends ModelProperties` : tv + ) + str += `export function ${funcName}<${allTemplateVars.join(", ")}>(` + + if (preParam) { + str += preParam + } + + const allParams = [] + for (let i = 0; i < args; i++) { + allParams.push(`${alfa[i]}: ${type}<${getTemplateVars(templateVars, i).join(", ")}>`) + } + str += `${allParams.join(", ")}` + str += ")" + + let allReturnTypes = [] + for (const templateVar of templateVars) { + let union = [] + for (let i = 0; i < args; i++) { + union.push(getTemplateVar(templateVar, i)) + } + allReturnTypes.push(union) + } + allReturnTypes = allReturnTypesTransform(allReturnTypes) + str += `: ${outType}<${allReturnTypes.map((u) => u.join(` ${operationChar} `)).join(", ")}>` + + return str + "\n" +} diff --git a/scripts/generate-union-types.js b/scripts/generate-union-types.js new file mode 100644 index 000000000..39313ce92 --- /dev/null +++ b/scripts/generate-union-types.js @@ -0,0 +1,69 @@ +const { getDeclaration } = require("./generate-shared") + +let str = `// generated with ${__filename}\n` + +const minArgs = 2 +const maxArgs = 10 +const preParam = "options: UnionOptions, " +const modelReturnTypeTransform = (rt) => { + // [['PA', 'PB'], ['OA', 'OB'], ['FCA', 'FCB'], ['FSA', 'FSB']] + // -> + // [['ModelCreationType2', 'ModelCreationType2'], + // ['ModelSnapshotType2', 'ModelSnapshotType2'], + // ['ModelInstanceType', 'ModelInstanceType']] + const [props, others, fixedC, fixedS] = rt + + const c = [], + s = [], + t = [] + for (let i = 0; i < props.length; i++) { + const p = props[i] + const o = others[i] + const fc = fixedC[i] + const fs = fixedS[i] + + c.push(`ModelCreationType2<${p}, ${fc}>`) + s.push(`ModelSnapshotType2<${p}, ${fs}>`) + t.push(`ModelInstanceType<${p}, ${o}>`) + } + return [c, s, t] +} + +for (let i = minArgs; i < maxArgs; i++) { + str += getDeclaration( + "union", + "IModelType", + ["P", "O", "FC", "FS"], + i, + null, + "|", + "ITypeUnion", + modelReturnTypeTransform + ) + str += getDeclaration( + "union", + "IModelType", + ["P", "O", "FC", "FS"], + i, + preParam, + "|", + "ITypeUnion", + modelReturnTypeTransform + ) +} + +for (let i = minArgs; i < maxArgs; i++) { + str += getDeclaration("union", "IType", ["C", "S", "T"], i, null, "|", "ITypeUnion", undefined) + str += getDeclaration( + "union", + "IType", + ["C", "S", "T"], + i, + preParam, + "|", + "ITypeUnion", + undefined + ) +} + +console.log(str) diff --git a/src/core/action.ts b/src/core/action.ts new file mode 100644 index 000000000..944b39f0d --- /dev/null +++ b/src/core/action.ts @@ -0,0 +1,308 @@ +import { action as mobxAction } from "mobx" +import { + getStateTreeNode, + fail, + argsToArray, + IDisposer, + getRoot, + Hook, + IAnyStateTreeNode, + warnError, + AnyObjectNode, + devMode, + IActionContext +} from "../internal" + +export type IMiddlewareEventType = + | "action" + | "flow_spawn" + | "flow_resume" + | "flow_resume_error" + | "flow_return" + | "flow_throw" +// | "task_spawn TODO, see #273" + +export interface IMiddlewareEvent extends IActionContext { + /** Event type */ + readonly type: IMiddlewareEventType + + /** Parent event unique id */ + readonly parentId: number + /** Parent event object */ + readonly parentEvent: IMiddlewareEvent | undefined + + /** Root event unique id */ + readonly rootId: number + /** Id of all events, from root until current (excluding current) */ + readonly allParentIds: number[] +} + +export interface FunctionWithFlag extends Function { + _isMSTAction?: boolean + _isFlowAction?: boolean +} + +/** + * @internal + * @hidden + */ +export type IMiddleware = { + handler: IMiddlewareHandler + includeHooks: boolean +} + +export type IMiddlewareHandler = ( + actionCall: IMiddlewareEvent, + next: (actionCall: IMiddlewareEvent, callback?: (value: any) => any) => void, + abort: (value: any) => void +) => any + +let nextActionId = 1 +let currentActionContext: IMiddlewareEvent | undefined + +/** + * @internal + * @hidden + */ +export function getCurrentActionContext() { + return currentActionContext +} + +/** + * @internal + * @hidden + */ +export function getNextActionId() { + return nextActionId++ +} + +// TODO: optimize away entire action context if there is no middleware in tree? +/** + * @internal + * @hidden + */ +export function runWithActionContext(context: IMiddlewareEvent, fn: Function) { + const node = getStateTreeNode(context.context) + + if (context.type === "action") { + node.assertAlive({ + actionContext: context + }) + } + + const baseIsRunningAction = node._isRunningAction + node._isRunningAction = true + const previousContext = currentActionContext + currentActionContext = context + try { + return runMiddleWares(node, context, fn) + } finally { + currentActionContext = previousContext + node._isRunningAction = baseIsRunningAction + } +} + +/** + * @internal + * @hidden + */ +export function getParentActionContext(parentContext: IMiddlewareEvent | undefined) { + if (!parentContext) return undefined + if (parentContext.type === "action") return parentContext + return parentContext.parentActionEvent +} + +/** + * @internal + * @hidden + */ +export function createActionInvoker( + target: IAnyStateTreeNode, + name: string, + fn: T +) { + const res = function () { + const id = getNextActionId() + const parentContext = currentActionContext + const parentActionContext = getParentActionContext(parentContext) + + return runWithActionContext( + { + type: "action", + name, + id, + args: argsToArray(arguments), + context: target, + tree: getRoot(target), + rootId: parentContext ? parentContext.rootId : id, + parentId: parentContext ? parentContext.id : 0, + allParentIds: parentContext ? [...parentContext.allParentIds, parentContext.id] : [], + parentEvent: parentContext, + parentActionEvent: parentActionContext + }, + fn + ) + } + ;(res as FunctionWithFlag)._isMSTAction = true + ;(res as FunctionWithFlag)._isFlowAction = fn._isFlowAction + return res +} + +/** + * Middleware can be used to intercept any action is invoked on the subtree where it is attached. + * If a tree is protected (by default), this means that any mutation of the tree will pass through your middleware. + * + * For more details, see the [middleware docs](concepts/middleware.md) + * + * @param target Node to apply the middleware to. + * @param middleware Middleware to apply. + * @returns A callable function to dispose the middleware. + */ +export function addMiddleware( + target: IAnyStateTreeNode, + handler: IMiddlewareHandler, + includeHooks: boolean = true +): IDisposer { + const node = getStateTreeNode(target) + if (devMode()) { + if (!node.isProtectionEnabled) { + warnError( + "It is recommended to protect the state tree before attaching action middleware, as otherwise it cannot be guaranteed that all changes are passed through middleware. See `protect`" + ) + } + } + return node.addMiddleWare(handler, includeHooks) +} + +/** + * Binds middleware to a specific action. + * + * Example: + * ```ts + * type.actions(self => { + * function takeA____() { + * self.toilet.donate() + * self.wipe() + * self.wipe() + * self.toilet.flush() + * } + * return { + * takeA____: decorate(atomic, takeA____) + * } + * }) + * ``` + * + * @param handler + * @param fn + * @param includeHooks + * @returns The original function + */ +export function decorate( + handler: IMiddlewareHandler, + fn: T, + includeHooks = true +): T { + const middleware: IMiddleware = { handler, includeHooks } + ;(fn as any).$mst_middleware = (fn as any).$mst_middleware || [] + ;(fn as any).$mst_middleware.push(middleware) + return fn +} + +class CollectedMiddlewares { + private arrayIndex = 0 + private inArrayIndex = 0 + private middlewares: IMiddleware[][] = [] + + constructor(node: AnyObjectNode, fn: Function) { + // we just push middleware arrays into an array of arrays to avoid making copies + if ((fn as any).$mst_middleware) { + this.middlewares.push((fn as any).$mst_middleware) + } + let n: AnyObjectNode | null = node + // Find all middlewares. Optimization: cache this? + while (n) { + if (n.middlewares) this.middlewares.push(n.middlewares) + n = n.parent + } + } + + get isEmpty() { + return this.middlewares.length <= 0 + } + + getNextMiddleware(): IMiddleware | undefined { + const array = this.middlewares[this.arrayIndex] + if (!array) return undefined + const item = array[this.inArrayIndex++] + if (!item) { + this.arrayIndex++ + this.inArrayIndex = 0 + return this.getNextMiddleware() + } + return item + } +} + +function runMiddleWares( + node: AnyObjectNode, + baseCall: IMiddlewareEvent, + originalFn: Function +): any { + const middlewares = new CollectedMiddlewares(node, originalFn) + // Short circuit + if (middlewares.isEmpty) return mobxAction(originalFn).apply(null, baseCall.args) + + let result: any = null + + function runNextMiddleware(call: IMiddlewareEvent): any { + const middleware = middlewares.getNextMiddleware() + const handler = middleware && middleware.handler + + if (!handler) { + return mobxAction(originalFn).apply(null, call.args) + } + + // skip hooks if asked to + if (!middleware!.includeHooks && (Hook as any)[call.name]) { + return runNextMiddleware(call) + } + + let nextInvoked = false + function next(call2: IMiddlewareEvent, callback?: (value: any) => any): void { + nextInvoked = true + // the result can contain + // - the non manipulated return value from an action + // - the non manipulated abort value + // - one of the above but manipulated through the callback function + result = runNextMiddleware(call2) + if (callback) { + result = callback(result) + } + } + + let abortInvoked = false + function abort(value: any) { + abortInvoked = true + // overwrite the result + // can be manipulated through middlewares earlier in the queue using the callback fn + result = value + } + + handler(call, next, abort) + if (devMode()) { + if (!nextInvoked && !abortInvoked) { + const node2 = getStateTreeNode(call.tree) + throw fail( + `Neither the next() nor the abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} was invoked.` + ) + } else if (nextInvoked && abortInvoked) { + const node2 = getStateTreeNode(call.tree) + throw fail( + `The next() and abort() callback within the middleware ${handler.name} for the action: "${call.name}" on the node: ${node2.type.name} were invoked.` + ) + } + } + return result + } + return runNextMiddleware(baseCall) +} diff --git a/src/core/actionContext.ts b/src/core/actionContext.ts new file mode 100644 index 000000000..58b8e2519 --- /dev/null +++ b/src/core/actionContext.ts @@ -0,0 +1,71 @@ +import { IAnyStateTreeNode, IMiddlewareEvent } from "../internal" +import { getCurrentActionContext } from "./action" + +export interface IActionContext { + /** Event name (action name for actions) */ + readonly name: string + + /** Event unique id */ + readonly id: number + + /** Parent action event object */ + readonly parentActionEvent: IMiddlewareEvent | undefined + + /** Event context (node where the action was invoked) */ + readonly context: IAnyStateTreeNode + /** Event tree (root node of the node where the action was invoked) */ + readonly tree: IAnyStateTreeNode + + /** Event arguments in an array (action arguments for actions) */ + readonly args: any[] +} + +/** + * Returns the currently executing MST action context, or undefined if none. + */ +export function getRunningActionContext(): IActionContext | undefined { + let current = getCurrentActionContext() + while (current && current.type !== "action") { + current = current.parentActionEvent + } + return current +} + +function _isActionContextThisOrChildOf( + actionContext: IActionContext, + sameOrParent: number | IActionContext | IMiddlewareEvent, + includeSame: boolean +) { + const parentId = typeof sameOrParent === "number" ? sameOrParent : sameOrParent.id + + let current: IActionContext | IMiddlewareEvent | undefined = includeSame + ? actionContext + : actionContext.parentActionEvent + while (current) { + if (current.id === parentId) { + return true + } + current = current.parentActionEvent + } + return false +} + +/** + * Returns if the given action context is a parent of this action context. + */ +export function isActionContextChildOf( + actionContext: IActionContext, + parent: number | IActionContext | IMiddlewareEvent +) { + return _isActionContextThisOrChildOf(actionContext, parent, false) +} + +/** + * Returns if the given action context is this or a parent of this action context. + */ +export function isActionContextThisOrChildOf( + actionContext: IActionContext, + parentOrThis: number | IActionContext | IMiddlewareEvent +) { + return _isActionContextThisOrChildOf(actionContext, parentOrThis, true) +} diff --git a/src/core/flow.ts b/src/core/flow.ts new file mode 100644 index 000000000..5b0765264 --- /dev/null +++ b/src/core/flow.ts @@ -0,0 +1,204 @@ +import { argsToArray, fail, setImmediateWithFallback } from "../utils" +import { + FunctionWithFlag, + getCurrentActionContext, + getNextActionId, + getParentActionContext, + IMiddlewareEventType, + runWithActionContext +} from "./action" + +/** + * @hidden + */ +export type FlowReturn = R extends Promise ? T : R + +/** + * See [asynchronous actions](concepts/async-actions.md). + * + * @returns The flow as a promise. + */ +export function flow( + generator: (...args: Args) => Generator, R, any> +): (...args: Args) => Promise> { + return createFlowSpawner(generator.name, generator) as any +} + +/** + * @deprecated Not needed since TS3.6. + * Used for TypeScript to make flows that return a promise return the actual promise result. + * + * @param val + * @returns + */ +export function castFlowReturn(val: T): T { + return val as any +} + +/** + * @experimental + * experimental api - might change on minor/patch releases + * + * Convert a promise-returning function to a generator-returning one. + * This is intended to allow for usage of `yield*` in async actions to + * retain the promise return type. + * + * Example: + * ```ts + * function getDataAsync(input: string): Promise { ... } + * const getDataGen = toGeneratorFunction(getDataAsync); + * + * const someModel.actions(self => ({ + * someAction: flow(function*() { + * // value is typed as number + * const value = yield* getDataGen("input value"); + * ... + * }) + * })) + * ``` + */ +export function toGeneratorFunction(p: (...args: Args) => Promise) { + return function* (...args: Args) { + return (yield p(...args)) as R + } +} + +/** + * @experimental + * experimental api - might change on minor/patch releases + * + * Convert a promise to a generator yielding that promise + * This is intended to allow for usage of `yield*` in async actions to + * retain the promise return type. + * + * Example: + * ```ts + * function getDataAsync(input: string): Promise { ... } + * + * const someModel.actions(self => ({ + * someAction: flow(function*() { + * // value is typed as number + * const value = yield* toGenerator(getDataAsync("input value")); + * ... + * }) + * })) + * ``` + */ +export function* toGenerator(p: Promise) { + return (yield p) as R +} + +/** + * @internal + * @hidden + */ +export function createFlowSpawner(name: string, generator: FunctionWithFlag) { + const spawner = function flowSpawner(this: any) { + // Implementation based on https://github.com/tj/co/blob/master/index.js + const runId = getNextActionId() + const parentContext = getCurrentActionContext()! + if (!parentContext) { + throw fail("a mst flow must always have a parent context") + } + const parentActionContext = getParentActionContext(parentContext) + if (!parentActionContext) { + throw fail("a mst flow must always have a parent action context") + } + + const contextBase = { + name, + id: runId, + tree: parentContext.tree, + context: parentContext.context, + parentId: parentContext.id, + allParentIds: [...parentContext.allParentIds, parentContext.id], + rootId: parentContext.rootId, + parentEvent: parentContext, + parentActionEvent: parentActionContext + } + + const args = arguments + + function wrap(fn: any, type: IMiddlewareEventType, arg: any) { + fn.$mst_middleware = (spawner as any).$mst_middleware // pick up any middleware attached to the flow + return runWithActionContext( + { + ...contextBase, + type, + args: [arg] + }, + fn + ) + } + + return new Promise(function (resolve, reject) { + let gen: any + const init = function asyncActionInit() { + gen = generator.apply(null, arguments) + onFulfilled(undefined) // kick off the flow + } + ;(init as any).$mst_middleware = (spawner as any).$mst_middleware + + runWithActionContext( + { + ...contextBase, + type: "flow_spawn", + args: argsToArray(args) + }, + init + ) + + function onFulfilled(res: any) { + let ret + try { + // prettier-ignore + const cancelError: any = wrap((r: any) => { ret = gen.next(r) }, "flow_resume", res) + if (cancelError instanceof Error) { + ret = gen.throw(cancelError) + } + } catch (e) { + // prettier-ignore + setImmediateWithFallback(() => { + wrap((r: any) => { reject(e) }, "flow_throw", e) + }) + return + } + next(ret) + return + } + + function onRejected(err: any) { + let ret + try { + // prettier-ignore + wrap((r: any) => { ret = gen.throw(r) }, "flow_resume_error", err) // or yieldError? + } catch (e) { + // prettier-ignore + setImmediateWithFallback(() => { + wrap((r: any) => { reject(e) }, "flow_throw", e) + }) + return + } + next(ret) + } + + function next(ret: any) { + if (ret.done) { + // prettier-ignore + setImmediateWithFallback(() => { + wrap((r: any) => { resolve(r) }, "flow_return", ret.value) + }) + return + } + // TODO: support more type of values? See https://github.com/tj/co/blob/249bbdc72da24ae44076afd716349d2089b31c4c/index.js#L100 + if (!ret.value || typeof ret.value.then !== "function") { + // istanbul ignore next + throw fail("Only promises can be yielded to `async`, got: " + ret) + } + return ret.value.then(onFulfilled, onRejected) + } + }) + } + ;(spawner as FunctionWithFlag)._isFlowAction = true + return spawner +} diff --git a/src/core/json-patch.ts b/src/core/json-patch.ts new file mode 100644 index 000000000..9353736d0 --- /dev/null +++ b/src/core/json-patch.ts @@ -0,0 +1,144 @@ +import { fail, stringStartsWith } from "../internal" + +/** + * https://tools.ietf.org/html/rfc6902 + * http://jsonpatch.com/ + */ +export interface IJsonPatch { + readonly op: "replace" | "add" | "remove" + readonly path: string + readonly value?: any +} + +export interface IReversibleJsonPatch extends IJsonPatch { + readonly oldValue: any // This goes beyond JSON-patch, but makes sure each patch can be inverse applied +} + +/** + * @internal + * @hidden + */ +export function splitPatch(patch: IReversibleJsonPatch): [IJsonPatch, IJsonPatch] { + if (!("oldValue" in patch)) throw fail(`Patches without \`oldValue\` field cannot be inversed`) + return [stripPatch(patch), invertPatch(patch)] +} + +/** + * @internal + * @hidden + */ +export function stripPatch(patch: IReversibleJsonPatch): IJsonPatch { + // strips `oldvalue` information from the patch, so that it becomes a patch conform the json-patch spec + // this removes the ability to undo the patch + switch (patch.op) { + case "add": + return { op: "add", path: patch.path, value: patch.value } + case "remove": + return { op: "remove", path: patch.path } + case "replace": + return { op: "replace", path: patch.path, value: patch.value } + } +} + +function invertPatch(patch: IReversibleJsonPatch): IJsonPatch { + switch (patch.op) { + case "add": + return { + op: "remove", + path: patch.path + } + case "remove": + return { + op: "add", + path: patch.path, + value: patch.oldValue + } + case "replace": + return { + op: "replace", + path: patch.path, + value: patch.oldValue + } + } +} + +/** + * Simple simple check to check it is a number. + */ +function isNumber(x: string): boolean { + return typeof x === "number" +} + +/** + * Escape slashes and backslashes. + * + * http://tools.ietf.org/html/rfc6901 + */ +export function escapeJsonPath(path: string): string { + if (isNumber(path) === true) { + return "" + path + } + if (path.indexOf("/") === -1 && path.indexOf("~") === -1) return path + return path.replace(/~/g, "~0").replace(/\//g, "~1") +} + +/** + * Unescape slashes and backslashes. + */ +export function unescapeJsonPath(path: string): string { + return path.replace(/~1/g, "/").replace(/~0/g, "~") +} + +/** + * Generates a json-path compliant json path from path parts. + * + * @param path + * @returns + */ +export function joinJsonPath(path: string[]): string { + // `/` refers to property with an empty name, while `` refers to root itself! + if (path.length === 0) return "" + + const getPathStr = (p: string[]) => p.map(escapeJsonPath).join("/") + if (path[0] === "." || path[0] === "..") { + // relative + return getPathStr(path) + } else { + // absolute + return "/" + getPathStr(path) + } +} + +/** + * Splits and decodes a json path into several parts. + * + * @param path + * @returns + */ +export function splitJsonPath(path: string): string[] { + // `/` refers to property with an empty name, while `` refers to root itself! + const parts = path.split("/").map(unescapeJsonPath) + + const valid = + path === "" || + path === "." || + path === ".." || + stringStartsWith(path, "/") || + stringStartsWith(path, "./") || + stringStartsWith(path, "../") + if (!valid) { + throw fail(`a json path must be either rooted, empty or relative, but got '${path}'`) + } + + // '/a/b/c' -> ["a", "b", "c"] + // '../../b/c' -> ["..", "..", "b", "c"] + // '' -> [] + // '/' -> [''] + // './a' -> [".", "a"] + // /./a' -> [".", "a"] equivalent to './a' + + if (parts[0] === "") { + parts.shift() + } + return parts +} diff --git a/packages/mobx-state-tree/src/core/mst-operations.ts b/src/core/mst-operations.ts similarity index 56% rename from packages/mobx-state-tree/src/core/mst-operations.ts rename to src/core/mst-operations.ts index b42d40d76..3b99c0eb1 100644 --- a/packages/mobx-state-tree/src/core/mst-operations.ts +++ b/src/core/mst-operations.ts @@ -1,42 +1,42 @@ import { isComputedProp, isObservableProp } from "mobx" import { - IAnyStateTreeNode, - IType, - IAnyModelType, - getStateTreeNode, - IStateTreeNode, - isStateTreeNode, - IJsonPatch, - splitJsonPath, - asArray, - EMPTY_OBJECT, - fail, - IDisposer, - resolveNodeByPath, - getRelativePathBetweenNodes, - freeze, - IAnyType, - isModelType, - InvalidReferenceError, - normalizeIdentifier, - ReferenceIdentifier, - AnyObjectNode, - assertIsType, - assertIsStateTreeNode, - TypeOfValue, - assertIsFunction, - assertIsNumber, - assertIsString, - assertArg, - assertIsValidIdentifier, - IActionContext, - getRunningActionContext, - IAnyComplexType + IAnyStateTreeNode, + IType, + IAnyModelType, + getStateTreeNode, + IStateTreeNode, + isStateTreeNode, + IJsonPatch, + splitJsonPath, + asArray, + EMPTY_OBJECT, + fail, + IDisposer, + resolveNodeByPath, + getRelativePathBetweenNodes, + freeze, + IAnyType, + isModelType, + InvalidReferenceError, + normalizeIdentifier, + ReferenceIdentifier, + AnyObjectNode, + assertIsType, + assertIsStateTreeNode, + TypeOfValue, + assertIsFunction, + assertIsNumber, + assertIsString, + assertArg, + assertIsValidIdentifier, + IActionContext, + getRunningActionContext, + IAnyComplexType } from "../internal" /** @hidden */ export type TypeOrStateTreeNodeToStateTreeNode = - T extends IType ? TT & IStateTreeNode : T + T extends IType ? TT & IStateTreeNode : T /** * Returns the _actual_ type of the given tree node. (Or throws) @@ -45,9 +45,9 @@ export type TypeOrStateTreeNodeToStateTreeNode void + target: IAnyStateTreeNode, + callback: (patch: IJsonPatch, reversePatch: IJsonPatch) => void ): IDisposer { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsFunction(callback, 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsFunction(callback, 2) - return getStateTreeNode(target).onPatch(callback) + return getStateTreeNode(target).onPatch(callback) } /** @@ -102,14 +102,14 @@ export function onPatch( * @returns */ export function onSnapshot( - target: IStateTreeNode>, - callback: (snapshot: S) => void + target: IStateTreeNode>, + callback: (snapshot: S) => void ): IDisposer { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsFunction(callback, 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsFunction(callback, 2) - return getStateTreeNode(target).onSnapshot(callback) + return getStateTreeNode(target).onSnapshot(callback) } /** @@ -123,25 +123,25 @@ export function onSnapshot( * @returns */ export function applyPatch( - target: IAnyStateTreeNode, - patch: IJsonPatch | ReadonlyArray + target: IAnyStateTreeNode, + patch: IJsonPatch | ReadonlyArray ): void { - // check all arguments - assertIsStateTreeNode(target, 1) - assertArg(patch, (p) => typeof p === "object", "object or array", 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertArg(patch, (p) => typeof p === "object", "object or array", 2) - getStateTreeNode(target).applyPatches(asArray(patch)) + getStateTreeNode(target).applyPatches(asArray(patch)) } export interface IPatchRecorder { - patches: ReadonlyArray - inversePatches: ReadonlyArray - reversedInversePatches: ReadonlyArray - readonly recording: boolean - stop(): void - resume(): void - replay(target?: IAnyStateTreeNode): void - undo(target?: IAnyStateTreeNode): void + patches: ReadonlyArray + inversePatches: ReadonlyArray + reversedInversePatches: ReadonlyArray + readonly recording: boolean + stop(): void + resume(): void + replay(target?: IAnyStateTreeNode): void + undo(target?: IAnyStateTreeNode): void } /** @@ -176,86 +176,86 @@ export interface IPatchRecorder { * @returns */ export function recordPatches( - subject: IAnyStateTreeNode, - filter?: ( - patch: IJsonPatch, - inversePatch: IJsonPatch, - actionContext: IActionContext | undefined - ) => boolean + subject: IAnyStateTreeNode, + filter?: ( + patch: IJsonPatch, + inversePatch: IJsonPatch, + actionContext: IActionContext | undefined + ) => boolean ): IPatchRecorder { - // check all arguments - assertIsStateTreeNode(subject, 1) - - interface IPatches { - patches: IJsonPatch[] - reversedInversePatches: IJsonPatch[] - inversePatches: IJsonPatch[] - } - - const data: Pick = { - patches: [], - inversePatches: [] - } - - // we will generate the immutable copy of patches on demand for public consumption - const publicData: Partial = {} - - let disposer: IDisposer | undefined - - const recorder: IPatchRecorder = { - get recording() { - return !!disposer - }, - get patches() { - if (!publicData.patches) { - publicData.patches = data.patches.slice() - } - return publicData.patches - }, - get reversedInversePatches() { - if (!publicData.reversedInversePatches) { - publicData.reversedInversePatches = data.inversePatches.slice().reverse() - } - return publicData.reversedInversePatches - }, - get inversePatches() { - if (!publicData.inversePatches) { - publicData.inversePatches = data.inversePatches.slice() - } - return publicData.inversePatches - }, - stop() { - if (disposer) { - disposer() - disposer = undefined - } - }, - resume() { - if (disposer) return - disposer = onPatch(subject, (patch, inversePatch) => { - // skip patches that are asked to be filtered if there's a filter in place - if (filter && !filter(patch, inversePatch, getRunningActionContext())) { - return - } - data.patches.push(patch) - data.inversePatches.push(inversePatch) - - // mark immutable public patches as dirty - publicData.patches = undefined - publicData.inversePatches = undefined - publicData.reversedInversePatches = undefined - }) - }, - replay(target?: IAnyStateTreeNode) { - applyPatch(target || subject, data.patches) - }, - undo(target?: IAnyStateTreeNode) { - applyPatch(target || subject, data.inversePatches.slice().reverse()) + // check all arguments + assertIsStateTreeNode(subject, 1) + + interface IPatches { + patches: IJsonPatch[] + reversedInversePatches: IJsonPatch[] + inversePatches: IJsonPatch[] + } + + const data: Pick = { + patches: [], + inversePatches: [] + } + + // we will generate the immutable copy of patches on demand for public consumption + const publicData: Partial = {} + + let disposer: IDisposer | undefined + + const recorder: IPatchRecorder = { + get recording() { + return !!disposer + }, + get patches() { + if (!publicData.patches) { + publicData.patches = data.patches.slice() + } + return publicData.patches + }, + get reversedInversePatches() { + if (!publicData.reversedInversePatches) { + publicData.reversedInversePatches = data.inversePatches.slice().reverse() + } + return publicData.reversedInversePatches + }, + get inversePatches() { + if (!publicData.inversePatches) { + publicData.inversePatches = data.inversePatches.slice() + } + return publicData.inversePatches + }, + stop() { + if (disposer) { + disposer() + disposer = undefined + } + }, + resume() { + if (disposer) return + disposer = onPatch(subject, (patch, inversePatch) => { + // skip patches that are asked to be filtered if there's a filter in place + if (filter && !filter(patch, inversePatch, getRunningActionContext())) { + return } + data.patches.push(patch) + data.inversePatches.push(inversePatch) + + // mark immutable public patches as dirty + publicData.patches = undefined + publicData.inversePatches = undefined + publicData.reversedInversePatches = undefined + }) + }, + replay(target?: IAnyStateTreeNode) { + applyPatch(target || subject, data.patches) + }, + undo(target?: IAnyStateTreeNode) { + applyPatch(target || subject, data.inversePatches.slice().reverse()) } + } - recorder.resume() - return recorder + recorder.resume() + return recorder } /** @@ -264,12 +264,12 @@ export function recordPatches( * @param target */ export function protect(target: IAnyStateTreeNode): void { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - const node = getStateTreeNode(target) - if (!node.isRoot) throw fail("`protect` can only be invoked on root nodes") - node.isProtectionEnabled = true + const node = getStateTreeNode(target) + if (!node.isRoot) throw fail("`protect` can only be invoked on root nodes") + node.isProtectionEnabled = true } /** @@ -297,19 +297,19 @@ export function protect(target: IAnyStateTreeNode): void { * ``` */ export function unprotect(target: IAnyStateTreeNode): void { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - const node = getStateTreeNode(target) - if (!node.isRoot) throw fail("`unprotect` can only be invoked on root nodes") - node.isProtectionEnabled = false + const node = getStateTreeNode(target) + if (!node.isRoot) throw fail("`unprotect` can only be invoked on root nodes") + node.isProtectionEnabled = false } /** * Returns true if the object is in protected mode, @see protect */ export function isProtected(target: IAnyStateTreeNode): boolean { - return getStateTreeNode(target).isProtected + return getStateTreeNode(target).isProtected } /** @@ -320,10 +320,10 @@ export function isProtected(target: IAnyStateTreeNode): boolean { * @returns */ export function applySnapshot(target: IStateTreeNode>, snapshot: C) { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).applySnapshot(snapshot) + return getStateTreeNode(target).applySnapshot(snapshot) } /** @@ -335,16 +335,16 @@ export function applySnapshot(target: IStateTreeNode>, sna * @returns */ export function getSnapshot( - target: IStateTreeNode>, - applyPostProcess = true + target: IStateTreeNode>, + applyPostProcess = true ): S { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - const node = getStateTreeNode(target) - if (applyPostProcess) return node.snapshot + const node = getStateTreeNode(target) + if (applyPostProcess) return node.snapshot - return freeze(node.type.getSnapshot(node, false)) + return freeze(node.type.getSnapshot(node, false)) } /** @@ -355,16 +355,16 @@ export function getSnapshot( * @returns */ export function hasParent(target: IAnyStateTreeNode, depth: number = 1): boolean { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsNumber(depth, 2, 0) - - let parent: AnyObjectNode | null = getStateTreeNode(target).parent - while (parent) { - if (--depth === 0) return true - parent = parent.parent - } - return false + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsNumber(depth, 2, 0) + + let parent: AnyObjectNode | null = getStateTreeNode(target).parent + while (parent) { + if (--depth === 0) return true + parent = parent.parent + } + return false } /** @@ -381,20 +381,20 @@ export function hasParent(target: IAnyStateTreeNode, depth: number = 1): boolean * @returns */ export function getParent( - target: IAnyStateTreeNode, - depth = 1 + target: IAnyStateTreeNode, + depth = 1 ): TypeOrStateTreeNodeToStateTreeNode { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsNumber(depth, 2, 0) - - let d = depth - let parent: AnyObjectNode | null = getStateTreeNode(target).parent - while (parent) { - if (--d === 0) return parent.storedValue as any - parent = parent.parent - } - throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsNumber(depth, 2, 0) + + let d = depth + let parent: AnyObjectNode | null = getStateTreeNode(target).parent + while (parent) { + if (--d === 0) return parent.storedValue as any + parent = parent.parent + } + throw fail(`Failed to find the parent of ${getStateTreeNode(target)} at depth ${depth}`) } /** @@ -405,16 +405,16 @@ export function getParent( * @returns */ export function hasParentOfType(target: IAnyStateTreeNode, type: IAnyComplexType): boolean { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsType(type, 2) - - let parent: AnyObjectNode | null = getStateTreeNode(target).parent - while (parent) { - if (type.is(parent.storedValue)) return true - parent = parent.parent - } - return false + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsType(type, 2) + + let parent: AnyObjectNode | null = getStateTreeNode(target).parent + while (parent) { + if (type.is(parent.storedValue)) return true + parent = parent.parent + } + return false } /** @@ -425,19 +425,19 @@ export function hasParentOfType(target: IAnyStateTreeNode, type: IAnyComplexType * @returns */ export function getParentOfType( - target: IAnyStateTreeNode, - type: IT + target: IAnyStateTreeNode, + type: IT ): IT["Type"] { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsType(type, 2) - - let parent: AnyObjectNode | null = getStateTreeNode(target).parent - while (parent) { - if (type.is(parent.storedValue)) return parent.storedValue - parent = parent.parent - } - throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsType(type, 2) + + let parent: AnyObjectNode | null = getStateTreeNode(target).parent + while (parent) { + if (type.is(parent.storedValue)) return parent.storedValue + parent = parent.parent + } + throw fail(`Failed to find the parent of ${getStateTreeNode(target)} of a given type`) } /** @@ -450,12 +450,12 @@ export function getParentOfType( * @returns */ export function getRoot( - target: IAnyStateTreeNode + target: IAnyStateTreeNode ): TypeOrStateTreeNodeToStateTreeNode { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).root.storedValue + return getStateTreeNode(target).root.storedValue } /** @@ -465,10 +465,10 @@ export function getRoot( * @returns */ export function getPath(target: IAnyStateTreeNode): string { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).path + return getStateTreeNode(target).path } /** @@ -478,10 +478,10 @@ export function getPath(target: IAnyStateTreeNode): string { * @returns */ export function getPathParts(target: IAnyStateTreeNode): string[] { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return splitJsonPath(getStateTreeNode(target).path) + return splitJsonPath(getStateTreeNode(target).path) } /** @@ -491,10 +491,10 @@ export function getPathParts(target: IAnyStateTreeNode): string[] { * @returns */ export function isRoot(target: IAnyStateTreeNode): boolean { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).isRoot + return getStateTreeNode(target).isRoot } /** @@ -506,12 +506,12 @@ export function isRoot(target: IAnyStateTreeNode): boolean { * @returns */ export function resolvePath(target: IAnyStateTreeNode, path: string): any { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsString(path, 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsString(path, 2) - const node = resolveNodeByPath(getStateTreeNode(target), path) - return node ? node.value : undefined + const node = resolveNodeByPath(getStateTreeNode(target), path) + return node ? node.value : undefined } /** @@ -524,20 +524,20 @@ export function resolvePath(target: IAnyStateTreeNode, path: string): any { * @returns */ export function resolveIdentifier( - type: IT, - target: IAnyStateTreeNode, - identifier: ReferenceIdentifier + type: IT, + target: IAnyStateTreeNode, + identifier: ReferenceIdentifier ): IT["Type"] | undefined { - // check all arguments - assertIsType(type, 1) - assertIsStateTreeNode(target, 2) - assertIsValidIdentifier(identifier, 3) + // check all arguments + assertIsType(type, 1) + assertIsStateTreeNode(target, 2) + assertIsValidIdentifier(identifier, 3) - const node = getStateTreeNode(target).root.identifierCache!.resolve( - type, - normalizeIdentifier(identifier) - ) - return node?.value + const node = getStateTreeNode(target).root.identifierCache!.resolve( + type, + normalizeIdentifier(identifier) + ) + return node?.value } /** @@ -548,10 +548,10 @@ export function resolveIdentifier( * @returns */ export function getIdentifier(target: IAnyStateTreeNode): string | null { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).identifier + return getStateTreeNode(target).identifier } /** @@ -563,28 +563,28 @@ export function getIdentifier(target: IAnyStateTreeNode): string | null { * @returns */ export function tryReference( - getter: () => N | null | undefined, - checkIfAlive = true + getter: () => N | null | undefined, + checkIfAlive = true ): N | undefined { - try { - const node = getter() - if (node === undefined || node === null) { - return undefined - } else if (isStateTreeNode(node)) { - if (!checkIfAlive) { - return node - } else { - return isAlive(node) ? node : undefined - } - } else { - throw fail("The reference to be checked is not one of node, null or undefined") - } - } catch (e) { - if (e instanceof InvalidReferenceError) { - return undefined - } - throw e + try { + const node = getter() + if (node === undefined || node === null) { + return undefined + } else if (isStateTreeNode(node)) { + if (!checkIfAlive) { + return node + } else { + return isAlive(node) ? node : undefined + } + } else { + throw fail("The reference to be checked is not one of node, null or undefined") } + } catch (e) { + if (e instanceof InvalidReferenceError) { + return undefined + } + throw e + } } /** @@ -595,24 +595,24 @@ export function tryReference( * @returns */ export function isValidReference( - getter: () => N | null | undefined, - checkIfAlive = true + getter: () => N | null | undefined, + checkIfAlive = true ): boolean { - try { - const node = getter() - if (node === undefined || node === null) { - return false - } else if (isStateTreeNode(node)) { - return checkIfAlive ? isAlive(node) : true - } else { - throw fail("The reference to be checked is not one of node, null or undefined") - } - } catch (e) { - if (e instanceof InvalidReferenceError) { - return false - } - throw e + try { + const node = getter() + if (node === undefined || node === null) { + return false + } else if (isStateTreeNode(node)) { + return checkIfAlive ? isAlive(node) : true + } else { + throw fail("The reference to be checked is not one of node, null or undefined") + } + } catch (e) { + if (e instanceof InvalidReferenceError) { + return false } + throw e + } } /** @@ -623,19 +623,19 @@ export function isValidReference( * @returns */ export function tryResolve(target: IAnyStateTreeNode, path: string): any { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsString(path, 2) - - const node = resolveNodeByPath(getStateTreeNode(target), path, false) - if (node === undefined) return undefined - try { - return node.value - } catch (e) { - // For what ever reason not resolvable (e.g. totally not existing path, or value that cannot be fetched) - // see test / issue: 'try resolve doesn't work #686' - return undefined - } + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsString(path, 2) + + const node = resolveNodeByPath(getStateTreeNode(target), path, false) + if (node === undefined) return undefined + try { + return node.value + } catch (e) { + // For what ever reason not resolvable (e.g. totally not existing path, or value that cannot be fetched) + // see test / issue: 'try resolve doesn't work #686' + return undefined + } } /** @@ -647,11 +647,11 @@ export function tryResolve(target: IAnyStateTreeNode, path: string): any { * @returns */ export function getRelativePath(base: IAnyStateTreeNode, target: IAnyStateTreeNode): string { - // check all arguments - assertIsStateTreeNode(base, 1) - assertIsStateTreeNode(target, 2) + // check all arguments + assertIsStateTreeNode(base, 1) + assertIsStateTreeNode(target, 2) - return getRelativePathBetweenNodes(getStateTreeNode(base), getStateTreeNode(target)) + return getRelativePathBetweenNodes(getStateTreeNode(base), getStateTreeNode(target)) } /** @@ -665,44 +665,44 @@ export function getRelativePath(base: IAnyStateTreeNode, target: IAnyStateTreeNo * @returns */ export function clone( - source: T, - keepEnvironment: boolean | any = true + source: T, + keepEnvironment: boolean | any = true ): T { - // check all arguments - assertIsStateTreeNode(source, 1) + // check all arguments + assertIsStateTreeNode(source, 1) - const node = getStateTreeNode(source) - return node.type.create( - node.snapshot, - keepEnvironment === true - ? node.root.environment - : keepEnvironment === false - ? undefined - : keepEnvironment - ) // it's an object or something else + const node = getStateTreeNode(source) + return node.type.create( + node.snapshot, + keepEnvironment === true + ? node.root.environment + : keepEnvironment === false + ? undefined + : keepEnvironment + ) // it's an object or something else } /** * Removes a model element from the state tree, and let it live on as a new state tree */ export function detach(target: T): T { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - getStateTreeNode(target).detach() - return target + getStateTreeNode(target).detach() + return target } /** * Removes a model element from the state tree, and mark it as end-of-life; the element should not be used anymore */ export function destroy(target: IAnyStateTreeNode): void { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - const node = getStateTreeNode(target) - if (node.isRoot) node.die() - else node.parent!.removeChild(node.subpath) + const node = getStateTreeNode(target) + if (node.isRoot) node.die() + else node.parent!.removeChild(node.subpath) } /** @@ -715,10 +715,10 @@ export function destroy(target: IAnyStateTreeNode): void { * @returns */ export function isAlive(target: IAnyStateTreeNode): boolean { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).observableIsAlive + return getStateTreeNode(target).observableIsAlive } /** @@ -750,13 +750,13 @@ export function isAlive(target: IAnyStateTreeNode): boolean { * @returns The same disposer that was passed as argument */ export function addDisposer(target: IAnyStateTreeNode, disposer: IDisposer): IDisposer { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsFunction(disposer, 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsFunction(disposer, 2) - const node = getStateTreeNode(target) - node.addDisposer(disposer) - return disposer + const node = getStateTreeNode(target) + node.addDisposer(disposer) + return disposer } /** @@ -772,37 +772,37 @@ export function addDisposer(target: IAnyStateTreeNode, disposer: IDisposer): IDi * @returns */ export function getEnv(target: IAnyStateTreeNode): T { - // check all arguments - assertIsStateTreeNode(target, 1) + // check all arguments + assertIsStateTreeNode(target, 1) - const node = getStateTreeNode(target) - const env = node.root.environment - if (!env) return EMPTY_OBJECT as T - return env + const node = getStateTreeNode(target) + const env = node.root.environment + if (!env) return EMPTY_OBJECT as T + return env } /** * Performs a depth first walk through a tree. */ export function walk( - target: IAnyStateTreeNode, - processor: (item: IAnyStateTreeNode) => void + target: IAnyStateTreeNode, + processor: (item: IAnyStateTreeNode) => void ): void { - // check all arguments - assertIsStateTreeNode(target, 1) - assertIsFunction(processor, 2) + // check all arguments + assertIsStateTreeNode(target, 1) + assertIsFunction(processor, 2) - const node = getStateTreeNode(target) - // tslint:disable-next-line:no_unused-variable - node.getChildren().forEach((child) => { - if (isStateTreeNode(child.storedValue)) walk(child.storedValue, processor) - }) - processor(node.storedValue) + const node = getStateTreeNode(target) + // tslint:disable-next-line:no_unused-variable + node.getChildren().forEach((child) => { + if (isStateTreeNode(child.storedValue)) walk(child.storedValue, processor) + }) + processor(node.storedValue) } export interface IModelReflectionPropertiesData { - name: string - properties: { [K: string]: IAnyType } + name: string + properties: { [K: string]: IAnyType } } /** @@ -812,29 +812,29 @@ export interface IModelReflectionPropertiesData { * @returns */ export function getPropertyMembers( - typeOrNode: IAnyModelType | IAnyStateTreeNode + typeOrNode: IAnyModelType | IAnyStateTreeNode ): IModelReflectionPropertiesData { - let type: IAnyModelType + let type: IAnyModelType - if (isStateTreeNode(typeOrNode)) { - type = getType(typeOrNode) as IAnyModelType - } else { - type = typeOrNode as IAnyModelType - } + if (isStateTreeNode(typeOrNode)) { + type = getType(typeOrNode) as IAnyModelType + } else { + type = typeOrNode as IAnyModelType + } - assertArg(type, (t) => isModelType(t), "model type or model instance", 1) + assertArg(type, (t) => isModelType(t), "model type or model instance", 1) - return { - name: type.name, - properties: { ...type.properties } - } + return { + name: type.name, + properties: { ...type.properties } + } } export interface IModelReflectionData extends IModelReflectionPropertiesData { - actions: string[] - views: string[] - volatile: string[] - flowActions: string[] + actions: string[] + views: string[] + volatile: string[] + flowActions: string[] } /** @@ -851,41 +851,41 @@ export interface IModelReflectionData extends IModelReflectionPropertiesData { * @returns */ export function getMembers(target: IAnyStateTreeNode): IModelReflectionData { - const type = getStateTreeNode(target).type as unknown as IAnyModelType - - const reflected: IModelReflectionData = { - ...getPropertyMembers(type), - actions: [], - volatile: [], - views: [], - flowActions: [] + const type = getStateTreeNode(target).type as unknown as IAnyModelType + + const reflected: IModelReflectionData = { + ...getPropertyMembers(type), + actions: [], + volatile: [], + views: [], + flowActions: [] + } + + const props = Object.getOwnPropertyNames(target) + props.forEach((key) => { + if (key in reflected.properties) return + const descriptor = Object.getOwnPropertyDescriptor(target, key)! + if (descriptor.get) { + if (isComputedProp(target, key)) reflected.views.push(key) + else reflected.volatile.push(key) + return } - - const props = Object.getOwnPropertyNames(target) - props.forEach((key) => { - if (key in reflected.properties) return - const descriptor = Object.getOwnPropertyDescriptor(target, key)! - if (descriptor.get) { - if (isComputedProp(target, key)) reflected.views.push(key) - else reflected.volatile.push(key) - return - } - if (descriptor.value._isMSTAction === true) reflected.actions.push(key) - if (descriptor.value._isFlowAction === true) reflected.flowActions.push(key) - else if (isObservableProp(target, key)) reflected.volatile.push(key) - else reflected.views.push(key) - }) - return reflected + if (descriptor.value._isMSTAction === true) reflected.actions.push(key) + if (descriptor.value._isFlowAction === true) reflected.flowActions.push(key) + else if (isObservableProp(target, key)) reflected.volatile.push(key) + else reflected.views.push(key) + }) + return reflected } export function cast( - snapshotOrInstance: O + snapshotOrInstance: O ): O export function cast( - snapshotOrInstance: - | TypeOfValue["CreationType"] - | TypeOfValue["SnapshotType"] - | TypeOfValue["Type"] + snapshotOrInstance: + | TypeOfValue["CreationType"] + | TypeOfValue["SnapshotType"] + | TypeOfValue["Type"] ): O /** * Casts a node snapshot or instance type to an instance type so it can be assigned to a type instance. @@ -917,7 +917,7 @@ export function cast( * @returns The same object cast as an instance */ export function cast(snapshotOrInstance: any): any { - return snapshotOrInstance as any + return snapshotOrInstance as any } /** @@ -948,9 +948,9 @@ export function cast(snapshotOrInstance: any): any { * @returns The same object cast as an input (creation) snapshot */ export function castToSnapshot( - snapshotOrInstance: I + snapshotOrInstance: I ): Extract extends never ? I : TypeOfValue["CreationType"] { - return snapshotOrInstance as any + return snapshotOrInstance as any } /** @@ -982,9 +982,9 @@ export function castToSnapshot( * @returns The same object cast as a reference snapshot (string or number) */ export function castToReferenceSnapshot( - instance: I + instance: I ): Extract extends never ? I : ReferenceIdentifier { - return instance as any + return instance as any } /** @@ -997,7 +997,7 @@ export function castToReferenceSnapshot( * @returns */ export function getNodeId(target: IAnyStateTreeNode): number { - assertIsStateTreeNode(target, 1) + assertIsStateTreeNode(target, 1) - return getStateTreeNode(target).nodeId + return getStateTreeNode(target).nodeId } diff --git a/src/core/node/BaseNode.ts b/src/core/node/BaseNode.ts new file mode 100644 index 000000000..ec75bdcf8 --- /dev/null +++ b/src/core/node/BaseNode.ts @@ -0,0 +1,212 @@ +import { + AnyObjectNode, + NodeLifeCycle, + Hook, + escapeJsonPath, + EventHandlers, + IAnyType, + IDisposer, + devMode +} from "../../internal" +import { createAtom, IAtom } from "mobx" + +type HookSubscribers = { + [Hook.afterAttach]: (node: AnyNode, hook: Hook) => void + [Hook.afterCreate]: (node: AnyNode, hook: Hook) => void + [Hook.afterCreationFinalization]: (node: AnyNode, hook: Hook) => void + [Hook.beforeDestroy]: (node: AnyNode, hook: Hook) => void + [Hook.beforeDetach]: (node: AnyNode, hook: Hook) => void +} + +/** + * @internal + * @hidden + */ +export abstract class BaseNode { + private _escapedSubpath?: string + + private _subpath!: string + get subpath() { + return this._subpath + } + + private _subpathUponDeath?: string + get subpathUponDeath() { + return this._subpathUponDeath + } + + private _pathUponDeath?: string + protected get pathUponDeath() { + return this._pathUponDeath + } + + storedValue!: any // usually the same type as the value, but not always (such as with references) + get value(): T { + return (this.type as any).getValue(this) + } + + private aliveAtom?: IAtom + private _state = NodeLifeCycle.INITIALIZING + get state() { + return this._state + } + set state(val: NodeLifeCycle) { + const wasAlive = this.isAlive + this._state = val + const isAlive = this.isAlive + + if (this.aliveAtom && wasAlive !== isAlive) { + this.aliveAtom.reportChanged() + } + } + + private _hookSubscribers?: EventHandlers + + protected abstract fireHook(name: Hook): void + + protected fireInternalHook(name: Hook) { + if (this._hookSubscribers) { + this._hookSubscribers.emit(name, this, name) + } + } + + registerHook(hook: H, hookHandler: HookSubscribers[H]): IDisposer { + if (!this._hookSubscribers) { + this._hookSubscribers = new EventHandlers() + } + return this._hookSubscribers.register(hook, hookHandler) + } + + private _parent!: AnyObjectNode | null + get parent() { + return this._parent + } + + constructor( + readonly type: IAnyType, + parent: AnyObjectNode | null, + subpath: string, + public environment: any + ) { + this.environment = environment + this.baseSetParent(parent, subpath) + } + + getReconciliationType() { + return this.type + } + + private pathAtom?: IAtom + protected baseSetParent(parent: AnyObjectNode | null, subpath: string) { + this._parent = parent + this._subpath = subpath + this._escapedSubpath = undefined // regenerate when needed + if (this.pathAtom) { + this.pathAtom.reportChanged() + } + } + + /* + * Returns (escaped) path representation as string + */ + get path(): string { + return this.getEscapedPath(true) + } + + protected getEscapedPath(reportObserved: boolean): string { + if (reportObserved) { + if (!this.pathAtom) { + this.pathAtom = createAtom(`path`) + } + this.pathAtom.reportObserved() + } + if (!this.parent) return "" + // regenerate escaped subpath if needed + if (this._escapedSubpath === undefined) { + this._escapedSubpath = !this._subpath ? "" : escapeJsonPath(this._subpath) + } + return this.parent.getEscapedPath(reportObserved) + "/" + this._escapedSubpath + } + + get isRoot(): boolean { + return this.parent === null + } + + abstract get root(): AnyObjectNode + + abstract setParent(newParent: AnyObjectNode | null, subpath: string | null): void + + abstract get snapshot(): S + abstract getSnapshot(): S + + get isAlive() { + return this.state !== NodeLifeCycle.DEAD + } + + get isDetaching() { + return this.state === NodeLifeCycle.DETACHING + } + + get observableIsAlive() { + if (!this.aliveAtom) { + this.aliveAtom = createAtom(`alive`) + } + this.aliveAtom.reportObserved() + return this.isAlive + } + + abstract die(): void + + abstract finalizeCreation(): void + + protected baseFinalizeCreation(whenFinalized?: () => void) { + if (devMode()) { + if (!this.isAlive) { + // istanbul ignore next + throw fail("assertion failed: cannot finalize the creation of a node that is already dead") + } + } + + // goal: afterCreate hooks runs depth-first. After attach runs parent first, so on afterAttach the parent has completed already + if (this.state === NodeLifeCycle.CREATED) { + if (this.parent) { + if (this.parent.state !== NodeLifeCycle.FINALIZED) { + // parent not ready yet, postpone + return + } + this.fireHook(Hook.afterAttach) + } + + this.state = NodeLifeCycle.FINALIZED + + if (whenFinalized) { + whenFinalized() + } + } + } + + abstract finalizeDeath(): void + + protected baseFinalizeDeath() { + if (this._hookSubscribers) { + this._hookSubscribers.clearAll() + } + + this._subpathUponDeath = this._subpath + this._pathUponDeath = this.getEscapedPath(false) + this.baseSetParent(null, "") + this.state = NodeLifeCycle.DEAD + } + + abstract aboutToDie(): void + + protected baseAboutToDie() { + this.fireHook(Hook.beforeDestroy) + } +} + +/** + * @internal + * @hidden + */ +export type AnyNode = BaseNode diff --git a/src/core/node/Hook.ts b/src/core/node/Hook.ts new file mode 100644 index 000000000..8d560d3c4 --- /dev/null +++ b/src/core/node/Hook.ts @@ -0,0 +1,19 @@ +/** + * @hidden + */ +export enum Hook { + afterCreate = "afterCreate", + afterAttach = "afterAttach", + afterCreationFinalization = "afterCreationFinalization", + beforeDetach = "beforeDetach", + beforeDestroy = "beforeDestroy" +} + +export interface IHooks { + [Hook.afterCreate]?: () => void + [Hook.afterAttach]?: () => void + [Hook.beforeDetach]?: () => void + [Hook.beforeDestroy]?: () => void +} + +export type IHooksGetter = (self: T) => IHooks diff --git a/src/core/node/create-node.ts b/src/core/node/create-node.ts new file mode 100644 index 000000000..1be8122a2 --- /dev/null +++ b/src/core/node/create-node.ts @@ -0,0 +1,66 @@ +import { + fail, + ObjectNode, + ScalarNode, + AnyNode, + getStateTreeNodeSafe, + AnyObjectNode, + ComplexType, + SimpleType +} from "../../internal" + +/** + * @internal + * @hidden + */ +export function createObjectNode( + type: ComplexType, + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C | T +): ObjectNode { + const existingNode = getStateTreeNodeSafe(initialValue) + if (existingNode) { + if (existingNode.parent) { + // istanbul ignore next + throw fail( + `Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${ + parent ? parent.path : "" + }/${subpath}', but it lives already at '${existingNode.path}'` + ) + } + + if (parent) { + existingNode.setParent(parent, subpath) + } + // else it already has no parent since it is a pre-requisite + + return existingNode + } + + // not a node, a snapshot + return new ObjectNode(type, parent, subpath, environment, initialValue as C) +} + +/** + * @internal + * @hidden + */ +export function createScalarNode( + type: SimpleType, + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C +): ScalarNode { + return new ScalarNode(type, parent, subpath, environment, initialValue) +} + +/** + * @internal + * @hidden + */ +export function isNode(value: any): value is AnyNode { + return value instanceof ScalarNode || value instanceof ObjectNode +} diff --git a/src/core/node/identifier-cache.ts b/src/core/node/identifier-cache.ts new file mode 100644 index 000000000..f56424a09 --- /dev/null +++ b/src/core/node/identifier-cache.ts @@ -0,0 +1,126 @@ +import { IObservableArray, values, observable, entries } from "mobx" +import { fail, ObjectNode, mobxShallow, AnyObjectNode, IAnyComplexType } from "../../internal" + +let identifierCacheId = 0 + +/** + * @internal + * @hidden + */ +export class IdentifierCache { + private cacheId = identifierCacheId++ + + // n.b. in cache all identifiers are normalized to strings + private cache = observable.map>() + + // last time the cache (array) for a given time changed + // n.b. it is not really the time, but just an integer that gets increased after each modification to the array + private lastCacheModificationPerId = observable.map() + + constructor() {} + + private updateLastCacheModificationPerId(identifier: string) { + const lcm = this.lastCacheModificationPerId.get(identifier) + // we start at 1 since 0 means no update since cache creation + this.lastCacheModificationPerId.set(identifier, lcm === undefined ? 1 : lcm + 1) + } + + getLastCacheModificationPerId(identifier: string): string { + const modificationId = this.lastCacheModificationPerId.get(identifier) || 0 + return `${this.cacheId}-${modificationId}` + } + + addNodeToCache(node: AnyObjectNode, lastCacheUpdate = true): void { + if (node.identifierAttribute) { + const identifier = node.identifier! + if (!this.cache.has(identifier)) { + this.cache.set(identifier, observable.array([], mobxShallow)) + } + const set = this.cache.get(identifier)! + if (set.indexOf(node) !== -1) throw fail(`Already registered`) + set.push(node) + if (lastCacheUpdate) { + this.updateLastCacheModificationPerId(identifier) + } + } + } + + mergeCache(node: AnyObjectNode) { + values(node.identifierCache!.cache).forEach((nodes) => + nodes.forEach((child) => { + this.addNodeToCache(child) + }) + ) + } + + notifyDied(node: AnyObjectNode) { + if (node.identifierAttribute) { + const id = node.identifier! + const set = this.cache.get(id) + if (set) { + set.remove(node) + // remove empty sets from cache + if (!set.length) { + this.cache.delete(id) + } + this.updateLastCacheModificationPerId(node.identifier!) + } + } + } + + splitCache(splitNode: AnyObjectNode): IdentifierCache { + const newCache = new IdentifierCache() + // The slash is added here so we only match children of the splitNode. In version 5.1.8 and + // earlier there was no trailing slash, so non children that started with the same path string + // were being matched incorrectly. + const basePath = splitNode.path + "/" + entries(this.cache).forEach(([id, nodes]) => { + let modified = false + for (let i = nodes.length - 1; i >= 0; i--) { + const node = nodes[i] + if (node === splitNode || node.path.indexOf(basePath) === 0) { + newCache.addNodeToCache(node, false) // no need to update lastUpdated since it is a whole new cache + nodes.splice(i, 1) + // remove empty sets from cache + if (!nodes.length) { + this.cache.delete(id) + } + modified = true + } + } + if (modified) { + this.updateLastCacheModificationPerId(id) + } + }) + return newCache + } + + has(type: IAnyComplexType, identifier: string): boolean { + const set = this.cache.get(identifier) + if (!set) return false + return set.some((candidate) => type.isAssignableFrom(candidate.type)) + } + + resolve( + type: IT, + identifier: string + ): ObjectNode | null { + const set = this.cache.get(identifier) + if (!set) return null + const matches = set.filter((candidate) => type.isAssignableFrom(candidate.type)) + switch (matches.length) { + case 0: + return null + case 1: + return matches[0] + default: + throw fail( + `Cannot resolve a reference to type '${ + type.name + }' with id: '${identifier}' unambigously, there are multiple candidates: ${matches + .map((n) => n.path) + .join(", ")}` + ) + } + } +} diff --git a/packages/mobx-state-tree/src/core/node/livelinessChecking.ts b/src/core/node/livelinessChecking.ts similarity index 93% rename from packages/mobx-state-tree/src/core/node/livelinessChecking.ts rename to src/core/node/livelinessChecking.ts index 291e1fd67..e6561f63f 100644 --- a/packages/mobx-state-tree/src/core/node/livelinessChecking.ts +++ b/src/core/node/livelinessChecking.ts @@ -16,7 +16,7 @@ let livelinessChecking: LivelinessMode = "warn" * @param mode `"warn"`, `"error"` or `"ignore"` */ export function setLivelinessChecking(mode: LivelinessMode) { - livelinessChecking = mode + livelinessChecking = mode } /** @@ -25,7 +25,7 @@ export function setLivelinessChecking(mode: LivelinessMode) { * @returns `"warn"`, `"error"` or `"ignore"` */ export function getLivelinessChecking(): LivelinessMode { - return livelinessChecking + return livelinessChecking } /** @@ -45,5 +45,5 @@ export type LivelynessMode = LivelinessMode * @param mode `"warn"`, `"error"` or `"ignore"` */ export function setLivelynessChecking(mode: LivelinessMode) { - setLivelinessChecking(mode) + setLivelinessChecking(mode) } diff --git a/src/core/node/node-utils.ts b/src/core/node/node-utils.ts new file mode 100644 index 000000000..918701da0 --- /dev/null +++ b/src/core/node/node-utils.ts @@ -0,0 +1,215 @@ +import { + fail, + ObjectNode, + splitJsonPath, + joinJsonPath, + ScalarNode, + IChildNodesMap, + EMPTY_ARRAY, + AnyObjectNode, + AnyNode, + IAnyType, + IType, + assertArg, + STNValue, + Instance, + IAnyComplexType +} from "../../internal" + +/** + * @internal + * @hidden + */ +export enum NodeLifeCycle { + INITIALIZING, // setting up + CREATED, // afterCreate has run + FINALIZED, // afterAttach has run + DETACHING, // being detached from the tree + DEAD // no coming back from this one +} + +/** @hidden */ +declare const $stateTreeNodeType: unique symbol + +/** + * Common interface that represents a node instance. + * @hidden + */ +export interface IStateTreeNode { + /** + * @internal + */ + readonly $treenode?: any + + // fake, will never be present, just for typing + // we use this weird trick to solve an issue with reference types + readonly [$stateTreeNodeType]?: [IT] | [any] +} + +/** @hidden */ +export type TypeOfValue = T extends IStateTreeNode + ? IT + : never + +/** + * Represents any state tree node instance. + * @hidden + */ +export interface IAnyStateTreeNode extends STNValue {} + +/** + * Returns true if the given value is a node in a state tree. + * More precisely, that is, if the value is an instance of a + * `types.model`, `types.array` or `types.map`. + * + * @param value + * @returns true if the value is a state tree node. + */ +export function isStateTreeNode( + value: any +): value is STNValue, IT> { + return !!(value && value.$treenode) +} + +/** + * @internal + * @hidden + */ +export function assertIsStateTreeNode( + value: IAnyStateTreeNode, + argNumber: number | number[] +): void { + assertArg(value, isStateTreeNode, "mobx-state-tree node", argNumber) +} + +/** + * @internal + * @hidden + */ +export function getStateTreeNode(value: IAnyStateTreeNode): AnyObjectNode { + if (!isStateTreeNode(value)) { + // istanbul ignore next + throw fail(`Value ${value} is no MST Node`) + } + return value.$treenode! +} + +/** + * @internal + * @hidden + */ +export function getStateTreeNodeSafe(value: IAnyStateTreeNode): AnyObjectNode | null { + return (value && value.$treenode) || null +} + +/** + * @internal + * @hidden + */ +export function toJSON(this: IStateTreeNode>): S { + return getStateTreeNode(this).snapshot +} + +const doubleDot = (_: any) => ".." + +/** + * @internal + * @hidden + */ +export function getRelativePathBetweenNodes(base: AnyObjectNode, target: AnyObjectNode): string { + // PRE condition target is (a child of) base! + if (base.root !== target.root) { + throw fail( + `Cannot calculate relative path: objects '${base}' and '${target}' are not part of the same object tree` + ) + } + + const baseParts = splitJsonPath(base.path) + const targetParts = splitJsonPath(target.path) + let common = 0 + for (; common < baseParts.length; common++) { + if (baseParts[common] !== targetParts[common]) break + } + // TODO: assert that no targetParts paths are "..", "." or ""! + return baseParts.slice(common).map(doubleDot).join("/") + joinJsonPath(targetParts.slice(common)) +} + +/** + * @internal + * @hidden + */ +export function resolveNodeByPath( + base: AnyObjectNode, + path: string, + failIfResolveFails: boolean = true +): AnyNode | undefined { + return resolveNodeByPathParts(base, splitJsonPath(path), failIfResolveFails) +} + +/** + * @internal + * @hidden + */ +export function resolveNodeByPathParts( + base: AnyObjectNode, + pathParts: string[], + failIfResolveFails: boolean = true +): AnyNode | undefined { + let current: AnyNode | null = base + try { + for (let i = 0; i < pathParts.length; i++) { + const part = pathParts[i] + if (part === "..") { + current = current!.parent + if (current) continue // not everything has a parent + } else if (part === ".") { + continue + } else if (current) { + if (current instanceof ScalarNode) { + // check if the value of a scalar resolves to a state tree node (e.g. references) + // then we can continue resolving... + const value: any = current.value + if (isStateTreeNode(value)) { + current = getStateTreeNode(value) + // fall through + } + } + if (current instanceof ObjectNode) { + const subType = current.getChildType(part) + if (subType) { + current = current.getChildNode(part) + if (current) continue + } + } + } + throw fail( + `Could not resolve '${part}' in path '${ + joinJsonPath(pathParts.slice(0, i)) || "/" + }' while resolving '${joinJsonPath(pathParts)}'` + ) + } + } catch (e) { + if (!failIfResolveFails) { + return undefined + } + throw e + } + return current! +} + +/** + * @internal + * @hidden + */ +export function convertChildNodesToArray(childNodes: IChildNodesMap | null): AnyNode[] { + if (!childNodes) return EMPTY_ARRAY as AnyNode[] + + const keys = Object.keys(childNodes) + if (!keys.length) return EMPTY_ARRAY as AnyNode[] + + const result = new Array(keys.length) as AnyNode[] + keys.forEach((key, index) => { + result[index] = childNodes![key] + }) + return result +} diff --git a/src/core/node/object-node.ts b/src/core/node/object-node.ts new file mode 100644 index 000000000..7b4939968 --- /dev/null +++ b/src/core/node/object-node.ts @@ -0,0 +1,733 @@ +// noinspection ES6UnusedImports +import { action, computed, IComputedValue, reaction, _allowStateChangesInsideComputed } from "mobx" +import { + addHiddenFinalProp, + ComplexType, + convertChildNodesToArray, + createActionInvoker, + EMPTY_OBJECT, + extend, + fail, + freeze, + IAnyType, + IdentifierCache, + IDisposer, + IJsonPatch, + IMiddleware, + IMiddlewareHandler, + IReversibleJsonPatch, + NodeLifeCycle, + resolveNodeByPathParts, + splitJsonPath, + splitPatch, + toJSON, + EventHandlers, + Hook, + BaseNode, + getLivelinessChecking, + normalizeIdentifier, + ReferenceIdentifier, + IMiddlewareEvent, + escapeJsonPath, + getPath, + warnError, + AnyNode, + IStateTreeNode, + ArgumentTypes, + IType, + devMode, + getCurrentActionContext +} from "../../internal" + +let nextNodeId = 1 + +const enum ObservableInstanceLifecycle { + // the actual observable instance has not been created yet + UNINITIALIZED, + // the actual observable instance is being created + CREATING, + // the actual observable instance has been created + CREATED +} + +const enum InternalEvents { + Dispose = "dispose", + Patch = "patch", + Snapshot = "snapshot" +} + +/** + * @internal + * @hidden + */ +export interface IChildNodesMap { + [key: string]: AnyNode +} + +const snapshotReactionOptions = { + onError(e: any) { + throw e + } +} + +type InternalEventHandlers = { + [InternalEvents.Dispose]: IDisposer + [InternalEvents.Patch]: (patch: IJsonPatch, reversePatch: IJsonPatch) => void + [InternalEvents.Snapshot]: (snapshot: S) => void +} + +/** + * @internal + * @hidden + */ +export class ObjectNode extends BaseNode { + declare readonly type: ComplexType + declare storedValue: T & IStateTreeNode> + + readonly nodeId = ++nextNodeId + readonly identifierAttribute?: string + readonly identifier: string | null // Identifier is always normalized to string, even if the identifier property isn't + readonly unnormalizedIdentifier: ReferenceIdentifier | null + + identifierCache?: IdentifierCache + isProtectionEnabled = true + middlewares?: IMiddleware[] + + private _applyPatches?: (patches: IJsonPatch[]) => void + + applyPatches(patches: IJsonPatch[]): void { + this.createObservableInstanceIfNeeded() + this._applyPatches!(patches) + } + + private _applySnapshot?: (snapshot: C) => void + + applySnapshot(snapshot: C): void { + this.createObservableInstanceIfNeeded() + this._applySnapshot!(snapshot) + } + + private _autoUnbox = true // unboxing is disabled when reading child nodes + _isRunningAction = false // only relevant for root + private _hasSnapshotReaction = false + + private _observableInstanceState = ObservableInstanceLifecycle.UNINITIALIZED + private _childNodes: IChildNodesMap + private _initialSnapshot: C + private _cachedInitialSnapshot?: S + private _cachedInitialSnapshotCreated = false + private _snapshotComputed: IComputedValue + + constructor( + complexType: ComplexType, + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C + ) { + super(complexType, parent, subpath, environment) + this._snapshotComputed = computed(() => freeze(this.getSnapshot())) + + this.unbox = this.unbox.bind(this) + + this._initialSnapshot = freeze(initialValue) + this.identifierAttribute = complexType.identifierAttribute + + if (!parent) { + this.identifierCache = new IdentifierCache() + } + + this._childNodes = complexType.initializeChildNodes(this, this._initialSnapshot) + + // identifier can not be changed during lifecycle of a node + // so we safely can read it from initial snapshot + this.identifier = null + this.unnormalizedIdentifier = null + if (this.identifierAttribute && this._initialSnapshot) { + let id = (this._initialSnapshot as any)[this.identifierAttribute] + if (id === undefined) { + // try with the actual node if not (for optional identifiers) + const childNode = this._childNodes[this.identifierAttribute] + if (childNode) { + id = childNode.value + } + } + + if (typeof id !== "string" && typeof id !== "number") { + throw fail( + `Instance identifier '${this.identifierAttribute}' for type '${this.type.name}' must be a string or a number` + ) + } + + // normalize internal identifier to string + this.identifier = normalizeIdentifier(id) + this.unnormalizedIdentifier = id + } + + if (!parent) { + this.identifierCache!.addNodeToCache(this) + } else { + parent.root.identifierCache!.addNodeToCache(this) + } + } + + createObservableInstanceIfNeeded(fireHooks = true): void { + if (this._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED) { + this.createObservableInstance(fireHooks) + } + } + + createObservableInstance(fireHooks = true): void { + if (devMode()) { + if (this.state !== NodeLifeCycle.INITIALIZING) { + // istanbul ignore next + throw fail( + "assertion failed: the creation of the observable instance must be done on the initializing phase" + ) + } + } + this._observableInstanceState = ObservableInstanceLifecycle.CREATING + + // make sure the parent chain is created as well + + // array with parent chain from parent to child + const parentChain = [] + + let parent = this.parent + // for performance reasons we never go back further than the most direct + // uninitialized parent + // this is done to avoid traversing the whole tree to the root when using + // the same reference again + while ( + parent && + parent._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED + ) { + parentChain.unshift(parent) + parent = parent.parent + } + + // initialize the uninitialized parent chain from parent to child + for (const p of parentChain) { + // delay firing hooks until after all parents have been created + p.createObservableInstanceIfNeeded(false) + } + + const type = this.type + + try { + this.storedValue = type.createNewInstance(this._childNodes) + this.preboot() + + this._isRunningAction = true + type.finalizeNewInstance(this, this.storedValue) + } catch (e) { + // short-cut to die the instance, to avoid the snapshot computed starting to throw... + this.state = NodeLifeCycle.DEAD + throw e + } finally { + this._isRunningAction = false + } + + this._observableInstanceState = ObservableInstanceLifecycle.CREATED + + // NOTE: we need to touch snapshot, because non-observable + // "_observableInstanceState" field was touched + ;(this._snapshotComputed as any).trackAndCompute() + + if (this.isRoot) this._addSnapshotReaction() + + this._childNodes = EMPTY_OBJECT + + this.state = NodeLifeCycle.CREATED + + if (fireHooks) { + this.fireHook(Hook.afterCreate) + // Note that the parent might not be finalized at this point + // so afterAttach won't be called until later in that case + this.finalizeCreation() + + // fire the hooks of the parents that we created + for (const p of parentChain.reverse()) { + p.fireHook(Hook.afterCreate) + // This will call afterAttach on the child if necessary + p.finalizeCreation() + } + } + } + + get root(): AnyObjectNode { + const parent = this.parent + return parent ? parent.root : this + } + + clearParent(): void { + if (!this.parent) return + + // detach if attached + this.fireHook(Hook.beforeDetach) + const previousState = this.state + this.state = NodeLifeCycle.DETACHING + + const root = this.root + const newEnv = root.environment + const newIdCache = root.identifierCache!.splitCache(this) + + try { + this.parent.removeChild(this.subpath) + this.baseSetParent(null, "") + this.environment = newEnv + this.identifierCache = newIdCache + } finally { + this.state = previousState + } + } + + setParent(newParent: AnyObjectNode, subpath: string): void { + const parentChanged = newParent !== this.parent + const subpathChanged = subpath !== this.subpath + + if (!parentChanged && !subpathChanged) { + return + } + + if (devMode()) { + if (!subpath) { + // istanbul ignore next + throw fail("assertion failed: subpath expected") + } + if (!newParent) { + // istanbul ignore next + throw fail("assertion failed: new parent expected") + } + + if (this.parent && parentChanged) { + throw fail( + `A node cannot exists twice in the state tree. Failed to add ${this} to path '${newParent.path}/${subpath}'.` + ) + } + if (!this.parent && newParent.root === this) { + throw fail( + `A state tree is not allowed to contain itself. Cannot assign ${this} to path '${newParent.path}/${subpath}'` + ) + } + if (!this.parent && !!this.environment && this.environment !== newParent.root.environment) { + throw fail( + `A state tree cannot be made part of another state tree as long as their environments are different.` + ) + } + } + + if (parentChanged) { + // attach to new parent + this.environment = undefined // will use root's + newParent.root.identifierCache!.mergeCache(this) + this.baseSetParent(newParent, subpath) + this.fireHook(Hook.afterAttach) + } else if (subpathChanged) { + // moving to a new subpath on the same parent + this.baseSetParent(this.parent, subpath) + } + } + + protected fireHook(name: Hook): void { + this.fireInternalHook(name) + + const fn = + this.storedValue && typeof this.storedValue === "object" && (this.storedValue as any)[name] + if (typeof fn === "function") { + // we check for it to allow old mobx peer dependencies that don't have the method to work (even when still bugged) + if (_allowStateChangesInsideComputed) { + _allowStateChangesInsideComputed(() => { + fn.apply(this.storedValue) + }) + } else { + fn.apply(this.storedValue) + } + } + } + + private _snapshotUponDeath?: S + + // advantage of using computed for a snapshot is that nicely respects transactions etc. + get snapshot(): S { + return this._snapshotComputed.get() + } + + // NOTE: we use this method to get snapshot without creating @computed overhead + getSnapshot(): S { + if (!this.isAlive) return this._snapshotUponDeath! + return this._observableInstanceState === ObservableInstanceLifecycle.CREATED + ? this._getActualSnapshot() + : this._getCachedInitialSnapshot() + } + + private _getActualSnapshot(): S { + return this.type.getSnapshot(this) + } + + private _getCachedInitialSnapshot(): S { + if (!this._cachedInitialSnapshotCreated) { + const type = this.type + const childNodes = this._childNodes + const snapshot = this._initialSnapshot + + this._cachedInitialSnapshot = type.processInitialSnapshot(childNodes, snapshot) + this._cachedInitialSnapshotCreated = true + } + + return this._cachedInitialSnapshot! + } + + private isRunningAction(): boolean { + if (this._isRunningAction) return true + if (this.isRoot) return false + return this.parent!.isRunningAction() + } + + assertAlive(context: AssertAliveContext): void { + const livelinessChecking = getLivelinessChecking() + if (!this.isAlive && livelinessChecking !== "ignore") { + const error = this._getAssertAliveError(context) + switch (livelinessChecking) { + case "error": + throw fail(error) + case "warn": + warnError(error) + } + } + } + + private _getAssertAliveError(context: AssertAliveContext): string { + const escapedPath = this.getEscapedPath(false) || this.pathUponDeath || "" + const subpath = (context.subpath && escapeJsonPath(context.subpath)) || "" + + let actionContext = context.actionContext || getCurrentActionContext() + + // try to use a real action context if possible since it includes the action name + if (actionContext && actionContext.type !== "action" && actionContext.parentActionEvent) { + actionContext = actionContext.parentActionEvent + } + + let actionFullPath = "" + if (actionContext && actionContext.name != null) { + // try to use the context, and if it not available use the node one + const actionPath = + (actionContext && actionContext.context && getPath(actionContext.context)) || escapedPath + actionFullPath = `${actionPath}.${actionContext.name}()` + } + + return `You are trying to read or write to an object that is no longer part of a state tree. (Object type: '${this.type.name}', Path upon death: '${escapedPath}', Subpath: '${subpath}', Action: '${actionFullPath}'). Either detach nodes first, or don't use objects after removing / replacing them in the tree.` + } + + getChildNode(subpath: string): AnyNode { + this.assertAlive({ + subpath + }) + this._autoUnbox = false + try { + return this._observableInstanceState === ObservableInstanceLifecycle.CREATED + ? this.type.getChildNode(this, subpath) + : this._childNodes![subpath] + } finally { + this._autoUnbox = true + } + } + + getChildren(): ReadonlyArray { + this.assertAlive(EMPTY_OBJECT) + this._autoUnbox = false + try { + return this._observableInstanceState === ObservableInstanceLifecycle.CREATED + ? this.type.getChildren(this) + : convertChildNodesToArray(this._childNodes) + } finally { + this._autoUnbox = true + } + } + + getChildType(propertyName?: string): IAnyType { + return this.type.getChildType(propertyName) + } + + get isProtected(): boolean { + return this.root.isProtectionEnabled + } + + assertWritable(context: AssertAliveContext): void { + this.assertAlive(context) + if (!this.isRunningAction() && this.isProtected) { + throw fail( + `Cannot modify '${this}', the object is protected and can only be modified by using an action.` + ) + } + } + + removeChild(subpath: string): void { + this.type.removeChild(this, subpath) + } + + // bound on the constructor + unbox(childNode: AnyNode | undefined): AnyNode | undefined { + if (!childNode) return childNode + + this.assertAlive({ + subpath: childNode.subpath || childNode.subpathUponDeath + }) + return this._autoUnbox ? childNode.value : childNode + } + + toString(): string { + const path = (this.isAlive ? this.path : this.pathUponDeath) || "" + const identifier = this.identifier ? `(id: ${this.identifier})` : "" + return `${this.type.name}@${path}${identifier}${this.isAlive ? "" : " [dead]"}` + } + + finalizeCreation(): void { + this.baseFinalizeCreation(() => { + for (let child of this.getChildren()) { + child.finalizeCreation() + } + + this.fireInternalHook(Hook.afterCreationFinalization) + }) + } + + detach(): void { + if (!this.isAlive) throw fail(`Error while detaching, node is not alive.`) + + this.clearParent() + } + + private preboot(): void { + const self = this + this._applyPatches = createActionInvoker( + this.storedValue, + "@APPLY_PATCHES", + (patches: IJsonPatch[]) => { + patches.forEach((patch) => { + if (!patch.path) { + self.type.applySnapshot(self, patch.value) + return + } + const parts = splitJsonPath(patch.path) + const node = resolveNodeByPathParts(self, parts.slice(0, -1)) as AnyObjectNode + node.applyPatchLocally(parts[parts.length - 1], patch) + }) + } + ) + this._applySnapshot = createActionInvoker( + this.storedValue, + "@APPLY_SNAPSHOT", + (snapshot: C) => { + // if the snapshot is the same as the current one, avoid performing a reconcile + if (snapshot === (self.snapshot as any)) return + // else, apply it by calling the type logic + return self.type.applySnapshot(self, snapshot as any) + } + ) + + addHiddenFinalProp(this.storedValue, "$treenode", this) + addHiddenFinalProp(this.storedValue, "toJSON", toJSON) + } + + die(): void { + if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) return + this.aboutToDie() + this.finalizeDeath() + } + + aboutToDie(): void { + if (this._observableInstanceState === ObservableInstanceLifecycle.UNINITIALIZED) { + return + } + + this.getChildren().forEach((node) => { + node.aboutToDie() + }) + + // beforeDestroy should run before the disposers since else we could end up in a situation where + // a disposer added with addDisposer at this stage (beforeDestroy) is actually never released + this.baseAboutToDie() + + this._internalEventsEmit(InternalEvents.Dispose) + this._internalEventsClear(InternalEvents.Dispose) + } + + finalizeDeath(): void { + // invariant: not called directly but from "die" + this.getChildren().forEach((node) => { + node.finalizeDeath() + }) + this.root.identifierCache!.notifyDied(this) + + // "kill" the computed prop and just store the last snapshot + const snapshot = this.snapshot + this._snapshotUponDeath = snapshot + + this._internalEventsClearAll() + + this.baseFinalizeDeath() + } + + onSnapshot(onChange: (snapshot: S) => void): IDisposer { + this._addSnapshotReaction() + return this._internalEventsRegister(InternalEvents.Snapshot, onChange) + } + + protected emitSnapshot(snapshot: S): void { + this._internalEventsEmit(InternalEvents.Snapshot, snapshot) + } + + onPatch(handler: (patch: IJsonPatch, reversePatch: IJsonPatch) => void): IDisposer { + return this._internalEventsRegister(InternalEvents.Patch, handler) + } + + emitPatch(basePatch: IReversibleJsonPatch, source: AnyNode): void { + if (this._internalEventsHasSubscribers(InternalEvents.Patch)) { + const localizedPatch: IReversibleJsonPatch = extend({}, basePatch, { + path: source.path.substr(this.path.length) + "/" + basePatch.path // calculate the relative path of the patch + }) + const [patch, reversePatch] = splitPatch(localizedPatch) + this._internalEventsEmit(InternalEvents.Patch, patch, reversePatch) + } + if (this.parent) this.parent.emitPatch(basePatch, source) + } + + hasDisposer(disposer: () => void): boolean { + return this._internalEventsHas(InternalEvents.Dispose, disposer) + } + + addDisposer(disposer: () => void): void { + if (!this.hasDisposer(disposer)) { + this._internalEventsRegister(InternalEvents.Dispose, disposer, true) + return + } + throw fail("cannot add a disposer when it is already registered for execution") + } + + removeDisposer(disposer: () => void): void { + if (!this._internalEventsHas(InternalEvents.Dispose, disposer)) { + throw fail("cannot remove a disposer which was never registered for execution") + } + this._internalEventsUnregister(InternalEvents.Dispose, disposer) + } + + private removeMiddleware(middleware: IMiddleware): void { + if (this.middlewares) { + const index = this.middlewares.indexOf(middleware) + if (index >= 0) { + this.middlewares.splice(index, 1) + } + } + } + + addMiddleWare(handler: IMiddlewareHandler, includeHooks: boolean = true): IDisposer { + const middleware = { handler, includeHooks } + if (!this.middlewares) this.middlewares = [middleware] + else this.middlewares.push(middleware) + + return () => { + this.removeMiddleware(middleware) + } + } + + applyPatchLocally(subpath: string, patch: IJsonPatch): void { + this.assertWritable({ + subpath + }) + this.createObservableInstanceIfNeeded() + this.type.applyPatchLocally(this, subpath, patch) + } + + private _addSnapshotReaction(): void { + if (!this._hasSnapshotReaction) { + const snapshotDisposer = reaction( + () => this.snapshot, + (snapshot) => this.emitSnapshot(snapshot), + snapshotReactionOptions + ) + this.addDisposer(snapshotDisposer) + this._hasSnapshotReaction = true + } + } + + // #region internal event handling + + private _internalEvents?: EventHandlers> + + // we proxy the methods to avoid creating an EventHandlers instance when it is not needed + + private _internalEventsHasSubscribers(event: InternalEvents): boolean { + return !!this._internalEvents && this._internalEvents.hasSubscribers(event) + } + + private _internalEventsRegister( + event: IE, + eventHandler: InternalEventHandlers[IE], + atTheBeginning = false + ): IDisposer { + if (!this._internalEvents) { + this._internalEvents = new EventHandlers() + } + return this._internalEvents.register(event, eventHandler, atTheBeginning) + } + + private _internalEventsHas( + event: IE, + eventHandler: InternalEventHandlers[IE] + ): boolean { + return !!this._internalEvents && this._internalEvents.has(event, eventHandler) + } + + private _internalEventsUnregister( + event: IE, + eventHandler: InternalEventHandlers[IE] + ): void { + if (this._internalEvents) { + this._internalEvents.unregister(event, eventHandler) + } + } + + private _internalEventsEmit( + event: IE, + ...args: ArgumentTypes[IE]> + ): void { + if (this._internalEvents) { + this._internalEvents.emit(event, ...args) + } + } + + private _internalEventsClear(event: InternalEvents): void { + if (this._internalEvents) { + this._internalEvents.clear(event) + } + } + + private _internalEventsClearAll(): void { + if (this._internalEvents) { + this._internalEvents.clearAll() + } + } + + // #endregion +} +ObjectNode.prototype.createObservableInstance = action( + ObjectNode.prototype.createObservableInstance +) +ObjectNode.prototype.detach = action(ObjectNode.prototype.detach) +ObjectNode.prototype.die = action(ObjectNode.prototype.die) + +/** + * @internal + * @hidden + */ +export type AnyObjectNode = ObjectNode + +/** + * @internal + * @hidden + */ +export interface AssertAliveContext { + subpath?: string + actionContext?: IMiddlewareEvent +} diff --git a/src/core/node/scalar-node.ts b/src/core/node/scalar-node.ts new file mode 100644 index 000000000..de36ac4c0 --- /dev/null +++ b/src/core/node/scalar-node.ts @@ -0,0 +1,118 @@ +import { + fail, + freeze, + NodeLifeCycle, + Hook, + BaseNode, + AnyObjectNode, + SimpleType, + devMode +} from "../../internal" +import { action } from "mobx" + +/** + * @internal + * @hidden + */ +export class ScalarNode extends BaseNode { + // note about hooks: + // - afterCreate is not emmited in scalar nodes, since it would be emitted in the + // constructor, before it can be subscribed by anybody + // - afterCreationFinalization could be emitted, but there's no need for it right now + // - beforeDetach is never emitted for scalar nodes, since they cannot be detached + + declare readonly type: SimpleType + + constructor( + simpleType: SimpleType, + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialSnapshot: C + ) { + super(simpleType, parent, subpath, environment) + try { + this.storedValue = simpleType.createNewInstance(initialSnapshot) + } catch (e) { + // short-cut to die the instance, to avoid the snapshot computed starting to throw... + this.state = NodeLifeCycle.DEAD + throw e + } + + this.state = NodeLifeCycle.CREATED + // for scalar nodes there's no point in firing this event since it would fire on the constructor, before + // anybody can actually register for/listen to it + // this.fireHook(Hook.AfterCreate) + + this.finalizeCreation() + } + + get root(): AnyObjectNode { + // future optimization: store root ref in the node and maintain it + if (!this.parent) throw fail(`This scalar node is not part of a tree`) + return this.parent.root + } + + setParent(newParent: AnyObjectNode, subpath: string): void { + const parentChanged = this.parent !== newParent + const subpathChanged = this.subpath !== subpath + + if (!parentChanged && !subpathChanged) { + return + } + + if (devMode()) { + if (!subpath) { + // istanbul ignore next + throw fail("assertion failed: subpath expected") + } + if (!newParent) { + // istanbul ignore next + throw fail("assertion failed: parent expected") + } + if (parentChanged) { + // istanbul ignore next + throw fail("assertion failed: scalar nodes cannot change their parent") + } + } + + this.environment = undefined // use parent's + this.baseSetParent(this.parent, subpath) + } + + get snapshot(): S { + return freeze(this.getSnapshot()) + } + + getSnapshot(): S { + return this.type.getSnapshot(this) + } + + toString(): string { + const path = (this.isAlive ? this.path : this.pathUponDeath) || "" + return `${this.type.name}@${path}${this.isAlive ? "" : " [dead]"}` + } + + die(): void { + if (!this.isAlive || this.state === NodeLifeCycle.DETACHING) return + this.aboutToDie() + this.finalizeDeath() + } + + finalizeCreation(): void { + this.baseFinalizeCreation() + } + + aboutToDie(): void { + this.baseAboutToDie() + } + + finalizeDeath(): void { + this.baseFinalizeDeath() + } + + protected fireHook(name: Hook): void { + this.fireInternalHook(name) + } +} +ScalarNode.prototype.die = action(ScalarNode.prototype.die) diff --git a/packages/mobx-state-tree/src/core/process.ts b/src/core/process.ts similarity index 67% rename from packages/mobx-state-tree/src/core/process.ts rename to src/core/process.ts index c84c95695..13e7804d6 100644 --- a/packages/mobx-state-tree/src/core/process.ts +++ b/src/core/process.ts @@ -11,8 +11,8 @@ import { deprecated, flow, createFlowSpawner } from "../internal" */ const DEPRECATION_MESSAGE = - "See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information. " + - "Note that the middleware event types starting with `process` now start with `flow`." + "See https://github.com/mobxjs/mobx-state-tree/issues/399 for more information. " + + "Note that the middleware event types starting with `process` now start with `flow`." /** * @deprecated has been renamed to `flow()`. @@ -29,58 +29,58 @@ export function process(generator: (a1: A1) => IterableIterator): (a1: * @hidden */ export function process( - generator: (a1: A1, a2: A2) => IterableIterator + generator: (a1: A1, a2: A2) => IterableIterator ): (a1: A1, a2: A2) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: (a1: A1, a2: A2, a3: A3) => IterableIterator + generator: (a1: A1, a2: A2, a3: A3) => IterableIterator ): (a1: A1, a2: A2, a3: A3) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: (a1: A1, a2: A2, a3: A3, a4: A4) => IterableIterator + generator: (a1: A1, a2: A2, a3: A3, a4: A4) => IterableIterator ): (a1: A1, a2: A2, a3: A3, a4: A4) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => IterableIterator + generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => IterableIterator ): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => IterableIterator + generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => IterableIterator ): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => IterableIterator + generator: (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => IterableIterator ): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7) => Promise /** * @deprecated has been renamed to `flow()`. * @hidden */ export function process( - generator: ( - a1: A1, - a2: A2, - a3: A3, - a4: A4, - a5: A5, - a6: A6, - a7: A7, - a8: A8 - ) => IterableIterator + generator: ( + a1: A1, + a2: A2, + a3: A3, + a4: A4, + a5: A5, + a6: A6, + a7: A7, + a8: A8 + ) => IterableIterator ): (a1: A1, a2: A2, a3: A3, a4: A4, a5: A5, a6: A6, a7: A7, a8: A8) => Promise /** * @hidden @@ -92,8 +92,8 @@ export function process( * @returns {Promise} */ export function process(asyncAction: any): any { - deprecated("process", "`process()` has been renamed to `flow()`. " + DEPRECATION_MESSAGE) - return flow(asyncAction) + deprecated("process", "`process()` has been renamed to `flow()`. " + DEPRECATION_MESSAGE) + return flow(asyncAction) } /** @@ -101,9 +101,9 @@ export function process(asyncAction: any): any { * @hidden */ export function createProcessSpawner(name: string, generator: Function) { - deprecated( - "process", - "`createProcessSpawner()` has been renamed to `createFlowSpawner()`. " + DEPRECATION_MESSAGE - ) - return createFlowSpawner(name, generator) + deprecated( + "process", + "`createProcessSpawner()` has been renamed to `createFlowSpawner()`. " + DEPRECATION_MESSAGE + ) + return createFlowSpawner(name, generator) } diff --git a/src/core/type/type-checker.ts b/src/core/type/type-checker.ts new file mode 100644 index 000000000..67d81ece8 --- /dev/null +++ b/src/core/type/type-checker.ts @@ -0,0 +1,186 @@ +import { + fail, + EMPTY_ARRAY, + isPrimitive, + getStateTreeNode, + isStateTreeNode, + isPrimitiveType, + IAnyType, + ExtractCSTWithSTN, + isTypeCheckingEnabled, + devMode +} from "../../internal" + +/** Validation context entry, this is, where the validation should run against which type */ +export interface IValidationContextEntry { + /** Subpath where the validation should be run, or an empty string to validate it all */ + path: string + /** Type to validate the subpath against */ + type: IAnyType +} + +/** Array of validation context entries */ +export type IValidationContext = IValidationContextEntry[] + +/** Type validation error */ +export interface IValidationError { + /** Validation context */ + context: IValidationContext + /** Value that was being validated, either a snapshot or an instance */ + value: any + /** Error message */ + message?: string +} + +/** Type validation result, which is an array of type validation errors */ +export type IValidationResult = IValidationError[] + +function safeStringify(value: any) { + try { + return JSON.stringify(value) + } catch (e) { + // istanbul ignore next + return `` + } +} + +/** + * @internal + * @hidden + */ +export function prettyPrintValue(value: any) { + return typeof value === "function" + ? `` + : isStateTreeNode(value) + ? `<${value}>` + : `\`${safeStringify(value)}\`` +} + +function shortenPrintValue(valueInString: string) { + return valueInString.length < 280 + ? valueInString + : `${valueInString.substring(0, 272)}......${valueInString.substring(valueInString.length - 8)}` +} + +function toErrorString(error: IValidationError): string { + const { value } = error + const type = error.context[error.context.length - 1].type! + const fullPath = error.context + .map(({ path }) => path) + .filter((path) => path.length > 0) + .join("/") + + const pathPrefix = fullPath.length > 0 ? `at path "/${fullPath}" ` : `` + + const currentTypename = isStateTreeNode(value) + ? `value of type ${getStateTreeNode(value).type.name}:` + : isPrimitive(value) + ? "value" + : "snapshot" + const isSnapshotCompatible = + type && isStateTreeNode(value) && type.is(getStateTreeNode(value).snapshot) + + return ( + `${pathPrefix}${currentTypename} ${prettyPrintValue(value)} is not assignable ${ + type ? `to type: \`${type.name}\`` : `` + }` + + (error.message ? ` (${error.message})` : "") + + (type + ? isPrimitiveType(type) || isPrimitive(value) + ? `.` + : `, expected an instance of \`${(type as IAnyType).name}\` or a snapshot like \`${( + type as IAnyType + ).describe()}\` instead.` + + (isSnapshotCompatible + ? " (Note that a snapshot of the provided value is compatible with the targeted type)" + : "") + : `.`) + ) +} + +/** + * @internal + * @hidden + */ +export function getContextForPath( + context: IValidationContext, + path: string, + type: IAnyType +): IValidationContext { + return context.concat([{ path, type }]) +} + +/** + * @internal + * @hidden + */ +export function typeCheckSuccess(): IValidationResult { + return EMPTY_ARRAY as any +} + +/** + * @internal + * @hidden + */ +export function typeCheckFailure( + context: IValidationContext, + value: any, + message?: string +): IValidationResult { + return [{ context, value, message }] +} + +/** + * @internal + * @hidden + */ +export function flattenTypeErrors(errors: IValidationResult[]): IValidationResult { + return errors.reduce((a, i) => a.concat(i), []) +} + +// TODO; doublecheck: typecheck should only needed to be invoked from: type.create and array / map / value.property will change +/** + * @internal + * @hidden + */ +export function typecheckInternal( + type: IAnyType, + value: ExtractCSTWithSTN +): void { + // runs typeChecking if it is in dev-mode or through a process.env.ENABLE_TYPE_CHECK flag + if (isTypeCheckingEnabled()) { + typecheck(type, value) + } +} + +/** + * Run's the typechecker for the given type on the given value, which can be a snapshot or an instance. + * Throws if the given value is not according the provided type specification. + * Use this if you need typechecks even in a production build (by default all automatic runtime type checks will be skipped in production builds) + * + * @param type Type to check against. + * @param value Value to be checked, either a snapshot or an instance. + */ +export function typecheck(type: IT, value: ExtractCSTWithSTN): void { + const errors = type.validate(value, [{ path: "", type }]) + + if (errors.length > 0) { + throw fail(validationErrorsToString(type, value, errors)) + } +} + +function validationErrorsToString( + type: IT, + value: ExtractCSTWithSTN, + errors: IValidationError[] +): string | undefined { + if (errors.length === 0) { + return undefined + } + + return ( + `Error while converting ${shortenPrintValue(prettyPrintValue(value))} to \`${ + type.name + }\`:\n\n ` + errors.map(toErrorString).join("\n ") + ) +} diff --git a/src/core/type/type.ts b/src/core/type/type.ts new file mode 100644 index 000000000..9a2bb9595 --- /dev/null +++ b/src/core/type/type.ts @@ -0,0 +1,548 @@ +import { action } from "mobx" + +import { + fail, + isMutable, + isStateTreeNode, + getStateTreeNode, + IValidationContext, + IValidationResult, + typecheckInternal, + typeCheckFailure, + typeCheckSuccess, + IStateTreeNode, + IJsonPatch, + getType, + ObjectNode, + IChildNodesMap, + ModelPrimitive, + normalizeIdentifier, + AnyObjectNode, + AnyNode, + BaseNode, + ScalarNode, + getStateTreeNodeSafe, + assertArg +} from "../../internal" + +/** + * @internal + * @hidden + */ +export enum TypeFlags { + String = 1, + Number = 1 << 1, + Boolean = 1 << 2, + Date = 1 << 3, + Literal = 1 << 4, + Array = 1 << 5, + Map = 1 << 6, + Object = 1 << 7, + Frozen = 1 << 8, + Optional = 1 << 9, + Reference = 1 << 10, + Identifier = 1 << 11, + Late = 1 << 12, + Refinement = 1 << 13, + Union = 1 << 14, + Null = 1 << 15, + Undefined = 1 << 16, + Integer = 1 << 17, + Custom = 1 << 18, + SnapshotProcessor = 1 << 19, + Lazy = 1 << 20, + Finite = 1 << 21, + Float = 1 << 22 +} + +/** + * @internal + * @hidden + */ +export const cannotDetermineSubtype = "cannotDetermine" + +/** + * A state tree node value. + * @hidden + */ +export type STNValue = T extends object ? T & IStateTreeNode : T + +/** @hidden */ +const $type: unique symbol = Symbol("$type") + +/** + * A type, either complex or simple. + */ +export interface IType { + // fake, will never be present, just for typing + /** @hidden */ + readonly [$type]: undefined + + /** + * Friendly type name. + */ + name: string + + /** + * Name of the identifier attribute or null if none. + */ + readonly identifierAttribute?: string + + /** + * Creates an instance for the type given an snapshot input. + * + * @returns An instance of that type. + */ + create(snapshot?: C, env?: any): this["Type"] + + /** + * Checks if a given snapshot / instance is of the given type. + * + * @param thing Snapshot or instance to be checked. + * @returns true if the value is of the current type, false otherwise. + */ + is(thing: any): thing is C | this["Type"] + + /** + * Run's the type's typechecker on the given value with the given validation context. + * + * @param thing Value to be checked, either a snapshot or an instance. + * @param context Validation context, an array of { subpaths, subtypes } that should be validated + * @returns The validation result, an array with the list of validation errors. + */ + validate(thing: C, context: IValidationContext): IValidationResult + + /** + * Gets the textual representation of the type as a string. + */ + describe(): string + + /** + * @deprecated use `Instance` instead. + * @hidden + */ + readonly Type: STNValue + + /** + * @deprecated do not use. + * @hidden + */ + readonly TypeWithoutSTN: T + + /** + * @deprecated use `SnapshotOut` instead. + * @hidden + */ + readonly SnapshotType: S + + /** + * @deprecated use `SnapshotIn` instead. + * @hidden + */ + readonly CreationType: C + + // Internal api's + + /** + * @internal + * @hidden + */ + flags: TypeFlags + /** + * @internal + * @hidden + */ + isType: true + /** + * @internal + * @hidden + */ + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C | T + ): BaseNode + /** + * @internal + * @hidden + */ + reconcile( + current: BaseNode, + newValue: C | T, + parent: AnyObjectNode, + subpath: string + ): BaseNode + /** + * @internal + * @hidden + */ + getSnapshot(node: BaseNode, applyPostProcess?: boolean): S + /** + * @internal + * @hidden + */ + isAssignableFrom(type: IAnyType): boolean + /** + * @internal + * @hidden + */ + getSubTypes(): IAnyType[] | IAnyType | null | typeof cannotDetermineSubtype +} + +/** + * Any kind of type. + */ +export interface IAnyType extends IType {} + +/** + * A simple type, this is, a type where the instance and the snapshot representation are the same. + */ +export interface ISimpleType extends IType {} + +/** @hidden */ +export type Primitives = ModelPrimitive | null | undefined + +/** + * A complex type. + * @deprecated just for compatibility with old versions, could be deprecated on the next major version + * @hidden + */ +export interface IComplexType extends IType {} + +/** + * Any kind of complex type. + */ +export interface IAnyComplexType extends IType {} + +/** @hidden */ +export type ExtractCSTWithoutSTN< + IT extends { [$type]: undefined; CreationType: any; SnapshotType: any; TypeWithoutSTN: any } +> = IT["CreationType"] | IT["SnapshotType"] | IT["TypeWithoutSTN"] +/** @hidden */ +export type ExtractCSTWithSTN< + IT extends { [$type]: undefined; CreationType: any; SnapshotType: any; Type: any } +> = IT["CreationType"] | IT["SnapshotType"] | IT["Type"] + +/** + * The instance representation of a given type. + */ +export type Instance = T extends { [$type]: undefined; Type: any } ? T["Type"] : T + +/** + * The input (creation) snapshot representation of a given type. + */ +export type SnapshotIn = T extends { [$type]: undefined; CreationType: any } + ? T["CreationType"] + : T extends IStateTreeNode + ? IT["CreationType"] + : T + +/** + * The output snapshot representation of a given type. + */ +export type SnapshotOut = T extends { [$type]: undefined; SnapshotType: any } + ? T["SnapshotType"] + : T extends IStateTreeNode + ? IT["SnapshotType"] + : T + +/** + * A type which is equivalent to the union of SnapshotIn and Instance types of a given typeof TYPE or typeof VARIABLE. + * For primitives it defaults to the primitive itself. + * + * For example: + * - `SnapshotOrInstance = SnapshotIn | Instance` + * - `SnapshotOrInstance = SnapshotIn | Instance` + * + * Usually you might want to use this when your model has a setter action that sets a property. + * + * Example: + * ```ts + * const ModelA = types.model({ + * n: types.number + * }) + * + * const ModelB = types.model({ + * innerModel: ModelA + * }).actions(self => ({ + * // this will accept as property both the snapshot and the instance, whichever is preferred + * setInnerModel(m: SnapshotOrInstance) { + * self.innerModel = cast(m) + * } + * })) + * ``` + */ +export type SnapshotOrInstance = SnapshotIn | Instance + +/** + * A base type produces a MST node (Node in the state tree) + * + * @internal + * @hidden + */ +export abstract class BaseType = BaseNode> + implements IType +{ + [$type]!: undefined + + // these are just to make inner types avaialable to inherited classes + readonly C!: C + readonly S!: S + readonly T!: T + readonly N!: N + + readonly isType = true + readonly name: string + + constructor(name: string) { + this.name = name + } + + create(snapshot?: C, environment?: any) { + typecheckInternal(this, snapshot) + return this.instantiate(null, "", environment, snapshot!).value + } + + getSnapshot(node: N, applyPostProcess?: boolean): S { + // istanbul ignore next + throw fail("unimplemented method") + } + + abstract reconcile(current: N, newValue: C | T, parent: AnyObjectNode, subpath: string): N + + abstract instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C | T + ): N + + declare abstract flags: TypeFlags + abstract describe(): string + + abstract isValidSnapshot(value: C, context: IValidationContext): IValidationResult + + isAssignableFrom(type: IAnyType): boolean { + return type === this + } + + validate(value: C | T, context: IValidationContext): IValidationResult { + const node = getStateTreeNodeSafe(value) + if (node) { + const valueType = getType(value) + return this.isAssignableFrom(valueType) + ? typeCheckSuccess() + : typeCheckFailure(context, value) + // it is tempting to compare snapshots, but in that case we should always clone on assignments... + } + return this.isValidSnapshot(value as C, context) + } + + is(thing: any): thing is any { + return this.validate(thing, [{ path: "", type: this }]).length === 0 + } + + get Type(): any { + // istanbul ignore next + throw fail( + "Factory.Type should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.Type`" + ) + } + get TypeWithoutSTN(): any { + // istanbul ignore next + throw fail( + "Factory.TypeWithoutSTN should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.TypeWithoutSTN`" + ) + } + get SnapshotType(): any { + // istanbul ignore next + throw fail( + "Factory.SnapshotType should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.SnapshotType`" + ) + } + get CreationType(): any { + // istanbul ignore next + throw fail( + "Factory.CreationType should not be actually called. It is just a Type signature that can be used at compile time with Typescript, by using `typeof type.CreationType`" + ) + } + + abstract getSubTypes(): IAnyType[] | IAnyType | null | typeof cannotDetermineSubtype +} +BaseType.prototype.create = action(BaseType.prototype.create) + +/** + * @internal + * @hidden + */ +export type AnyBaseType = BaseType + +/** + * @internal + * @hidden + */ +export type ExtractNodeType = IT extends BaseType + ? N + : never + +/** + * A complex type produces a MST node (Node in the state tree) + * + * @internal + * @hidden + */ +export abstract class ComplexType extends BaseType> { + identifierAttribute?: string + + constructor(name: string) { + super(name) + } + + create(snapshot: C = this.getDefaultSnapshot(), environment?: any) { + return super.create(snapshot, environment) + } + + getValue(node: this["N"]): T { + node.createObservableInstanceIfNeeded() + return node.storedValue + } + + abstract getDefaultSnapshot(): C + + abstract createNewInstance(childNodes: IChildNodesMap): T + abstract finalizeNewInstance(node: this["N"], instance: any): void + + abstract applySnapshot(node: this["N"], snapshot: C): void + abstract applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void + abstract processInitialSnapshot(childNodes: IChildNodesMap, snapshot: C): S + + abstract getChildren(node: this["N"]): ReadonlyArray + abstract getChildNode(node: this["N"], key: string): AnyNode + abstract getChildType(propertyName?: string): IAnyType + abstract initializeChildNodes(node: this["N"], snapshot: any): IChildNodesMap + abstract removeChild(node: this["N"], subpath: string): void + + isMatchingSnapshotId(current: this["N"], snapshot: C): boolean { + return ( + !current.identifierAttribute || + current.identifier === normalizeIdentifier((snapshot as any)[current.identifierAttribute]) + ) + } + + private tryToReconcileNode(current: this["N"], newValue: C | T) { + if (current.isDetaching) return false + if ((current.snapshot as any) === newValue) { + // newValue is the current snapshot of the node, noop + return true + } + if (isStateTreeNode(newValue) && getStateTreeNode(newValue) === current) { + // the current node is the same as the new one + return true + } + if ( + current.type === this && + isMutable(newValue) && + !isStateTreeNode(newValue) && + this.isMatchingSnapshotId(current, newValue as any) + ) { + // the newValue has no node, so can be treated like a snapshot + // we can reconcile + current.applySnapshot(newValue as C) + return true + } + return false + } + + reconcile( + current: this["N"], + newValue: C | T, + parent: AnyObjectNode, + subpath: string + ): this["N"] { + const nodeReconciled = this.tryToReconcileNode(current, newValue) + if (nodeReconciled) { + current.setParent(parent, subpath) + return current + } + + // current node cannot be recycled in any way + current.die() // noop if detaching + // attempt to reuse the new one + if (isStateTreeNode(newValue) && this.isAssignableFrom(getType(newValue))) { + // newValue is a Node as well, move it here.. + const newNode = getStateTreeNode(newValue) + newNode.setParent(parent, subpath) + return newNode + } + // nothing to do, we have to create a new node + return this.instantiate(parent, subpath, undefined, newValue) + } + + getSubTypes() { + return null + } +} +ComplexType.prototype.create = action(ComplexType.prototype.create) + +/** + * @internal + * @hidden + */ +export abstract class SimpleType extends BaseType> { + abstract instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C + ): this["N"] + + createNewInstance(snapshot: C): T { + return snapshot as any + } + + getValue(node: this["N"]): T { + // if we ever find a case where scalar nodes can be accessed without iterating through its parent + // uncomment this to make sure the parent chain is created when this is accessed + // if (node.parent) { + // node.parent.createObservableInstanceIfNeeded() + // } + return node.storedValue + } + + getSnapshot(node: this["N"]): S { + return node.storedValue + } + + reconcile(current: this["N"], newValue: C, parent: AnyObjectNode, subpath: string): this["N"] { + // reconcile only if type and value are still the same, and only if the node is not detaching + if (!current.isDetaching && current.type === this && current.storedValue === newValue) { + return current + } + const res = this.instantiate(parent, subpath, undefined, newValue) + current.die() // noop if detaching + return res + } + + getSubTypes() { + return null + } +} + +/** + * Returns if a given value represents a type. + * + * @param value Value to check. + * @returns `true` if the value is a type. + */ +export function isType(value: any): value is IAnyType { + return typeof value === "object" && value && value.isType === true +} + +/** + * @internal + * @hidden + */ +export function assertIsType(type: IAnyType, argNumber: number | number[]) { + assertArg(type, isType, "mobx-state-tree type", argNumber) +} diff --git a/src/index.ts b/src/index.ts new file mode 100644 index 000000000..3f6ebad55 --- /dev/null +++ b/src/index.ts @@ -0,0 +1,154 @@ +// tslint:disable-next-line:no_unused-variable +import { IObservableArray, ObservableMap } from "mobx" + +/* all code is initially loaded through internal, to avoid circular dep issues */ +export { + IModelType, + IAnyModelType, + IDisposer, + IMSTMap, + IMapType, + IMSTArray, + IArrayType, + IType, + IAnyType, + ModelPrimitive, + ISimpleType, + IComplexType, + IAnyComplexType, + IReferenceType, + _CustomCSProcessor, + _CustomOrOther, + _CustomJoin, + _NotCustomized, + typecheck, + escapeJsonPath, + unescapeJsonPath, + joinJsonPath, + splitJsonPath, + IJsonPatch, + IReversibleJsonPatch, + decorate, + addMiddleware, + IMiddlewareEvent, + IActionTrackingMiddleware2Call, + IMiddlewareHandler, + IMiddlewareEventType, + IActionTrackingMiddlewareHooks, + IActionTrackingMiddleware2Hooks, + process, + isStateTreeNode, + IStateTreeNode, + IAnyStateTreeNode, + flow, + castFlowReturn, + applyAction, + onAction, + IActionRecorder, + ISerializedActionCall, + recordActions, + createActionTrackingMiddleware, + createActionTrackingMiddleware2, + setLivelinessChecking, + getLivelinessChecking, + LivelinessMode, + setLivelynessChecking, // to be deprecated + LivelynessMode, // to be deprecated + ModelSnapshotType, + ModelCreationType, + ModelSnapshotType2, + ModelCreationType2, + ModelInstanceType, + ModelInstanceTypeProps, + ModelPropertiesDeclarationToProperties, + ModelProperties, + ModelPropertiesDeclaration, + ModelActions, + ITypeUnion, + CustomTypeOptions, + UnionOptions, + Instance, + SnapshotIn, + SnapshotOut, + SnapshotOrInstance, + TypeOrStateTreeNodeToStateTreeNode, + UnionStringArray, + getType, + getChildType, + onPatch, + onSnapshot, + applyPatch, + IPatchRecorder, + recordPatches, + protect, + unprotect, + isProtected, + applySnapshot, + getSnapshot, + hasParent, + getParent, + hasParentOfType, + getParentOfType, + getRoot, + getPath, + getPathParts, + isRoot, + resolvePath, + resolveIdentifier, + getIdentifier, + tryResolve, + getRelativePath, + clone, + detach, + destroy, + isAlive, + addDisposer, + getEnv, + walk, + IModelReflectionData, + IModelReflectionPropertiesData, + IMaybeIType, + IMaybe, + IMaybeNull, + IOptionalIType, + OptionalDefaultValueOrFunction, + ValidOptionalValue, + ValidOptionalValues, + getMembers, + getPropertyMembers, + TypeOfValue, + cast, + castToSnapshot, + castToReferenceSnapshot, + isType, + isArrayType, + isFrozenType, + isIdentifierType, + isLateType, + isLiteralType, + isMapType, + isModelType, + isOptionalType, + isPrimitiveType, + isReferenceType, + isRefinementType, + isUnionType, + tryReference, + isValidReference, + OnReferenceInvalidated, + OnReferenceInvalidatedEvent, + ReferenceOptions, + ReferenceOptionsGetSet, + ReferenceOptionsOnInvalidated, + ReferenceIdentifier, + ISnapshotProcessor, + ISnapshotProcessors, + getNodeId, + IActionContext, + getRunningActionContext, + isActionContextChildOf, + isActionContextThisOrChildOf, + types, + toGeneratorFunction, + toGenerator +} from "./internal" diff --git a/packages/mobx-state-tree/src/internal.ts b/src/internal.ts similarity index 100% rename from packages/mobx-state-tree/src/internal.ts rename to src/internal.ts diff --git a/src/middlewares/create-action-tracking-middleware.ts b/src/middlewares/create-action-tracking-middleware.ts new file mode 100644 index 000000000..3214dacb7 --- /dev/null +++ b/src/middlewares/create-action-tracking-middleware.ts @@ -0,0 +1,92 @@ +import { IMiddlewareEvent, IMiddlewareHandler } from "../internal" + +const runningActions = new Map() + +export interface IActionTrackingMiddlewareHooks { + filter?: (call: IMiddlewareEvent) => boolean + onStart: (call: IMiddlewareEvent) => T + onResume: (call: IMiddlewareEvent, context: T) => void + onSuspend: (call: IMiddlewareEvent, context: T) => void + onSuccess: (call: IMiddlewareEvent, context: T, result: any) => void + onFail: (call: IMiddlewareEvent, context: T, error: any) => void +} + +/** + * Note: Consider migrating to `createActionTrackingMiddleware2`, it is easier to use. + * + * Convenience utility to create action based middleware that supports async processes more easily. + * All hooks are called for both synchronous and asynchronous actions. Except that either `onSuccess` or `onFail` is called + * + * The create middleware tracks the process of an action (assuming it passes the `filter`). + * `onResume` can return any value, which will be passed as second argument to any other hook. This makes it possible to keep state during a process. + * + * See the `atomic` middleware for an example + * + * @param hooks + * @returns + */ +export function createActionTrackingMiddleware( + hooks: IActionTrackingMiddlewareHooks +): IMiddlewareHandler { + return function actionTrackingMiddleware( + call: IMiddlewareEvent, + next: (actionCall: IMiddlewareEvent) => any, + abort: (value: any) => any + ) { + switch (call.type) { + case "action": { + if (!hooks.filter || hooks.filter(call) === true) { + const context = hooks.onStart(call) + hooks.onResume(call, context) + runningActions.set(call.id, { + call, + context, + async: false + }) + try { + const res = next(call) + hooks.onSuspend(call, context) + if (runningActions.get(call.id)!.async === false) { + runningActions.delete(call.id) + hooks.onSuccess(call, context, res) + } + return res + } catch (e) { + runningActions.delete(call.id) + hooks.onFail(call, context, e) + throw e + } + } else { + return next(call) + } + } + case "flow_spawn": { + const root = runningActions.get(call.rootId)! + root.async = true + return next(call) + } + case "flow_resume": + case "flow_resume_error": { + const root = runningActions.get(call.rootId)! + hooks.onResume(call, root.context) + try { + return next(call) + } finally { + hooks.onSuspend(call, root.context) + } + } + case "flow_throw": { + const root = runningActions.get(call.rootId)! + runningActions.delete(call.rootId) + hooks.onFail(call, root.context, call.args[0]) + return next(call) + } + case "flow_return": { + const root = runningActions.get(call.rootId)! + runningActions.delete(call.rootId) + hooks.onSuccess(call, root.context, call.args[0]) + return next(call) + } + } + } +} diff --git a/src/middlewares/createActionTrackingMiddleware2.ts b/src/middlewares/createActionTrackingMiddleware2.ts new file mode 100644 index 000000000..2c85634b1 --- /dev/null +++ b/src/middlewares/createActionTrackingMiddleware2.ts @@ -0,0 +1,156 @@ +import { IMiddlewareEvent, IMiddlewareHandler, IActionContext } from "../internal" + +type Omit = Pick> + +export interface IActionTrackingMiddleware2Call extends Readonly { + env: TEnv | undefined + readonly parentCall?: IActionTrackingMiddleware2Call +} + +export interface IActionTrackingMiddleware2Hooks { + filter?: (call: IActionTrackingMiddleware2Call) => boolean + onStart: (call: IActionTrackingMiddleware2Call) => void + onFinish: (call: IActionTrackingMiddleware2Call, error?: any) => void +} + +class RunningAction { + private flowsPending = 0 + private running = true + + constructor( + public readonly hooks: IActionTrackingMiddleware2Hooks | undefined, + readonly call: IActionTrackingMiddleware2Call + ) { + if (hooks) { + hooks.onStart(call) + } + } + + finish(error?: any) { + if (this.running) { + this.running = false + if (this.hooks) { + this.hooks.onFinish(this.call, error) + } + } + } + + incFlowsPending() { + this.flowsPending++ + } + + decFlowsPending() { + this.flowsPending-- + } + + get hasFlowsPending() { + return this.flowsPending > 0 + } +} + +/** + * Convenience utility to create action based middleware that supports async processes more easily. + * The flow is like this: + * - for each action: if filter passes -> `onStart` -> (inner actions recursively) -> `onFinish` + * + * Example: if we had an action `a` that called inside an action `b1`, then `b2` the flow would be: + * - `filter(a)` + * - `onStart(a)` + * - `filter(b1)` + * - `onStart(b1)` + * - `onFinish(b1)` + * - `filter(b2)` + * - `onStart(b2)` + * - `onFinish(b2)` + * - `onFinish(a)` + * + * The flow is the same no matter if the actions are sync or async. + * + * See the `atomic` middleware for an example + * + * @param hooks + * @returns + */ +export function createActionTrackingMiddleware2( + middlewareHooks: IActionTrackingMiddleware2Hooks +): IMiddlewareHandler { + const runningActions = new Map() + + return function actionTrackingMiddleware( + call: IMiddlewareEvent, + next: (actionCall: IMiddlewareEvent) => any + ) { + // find parentRunningAction + const parentRunningAction = call.parentActionEvent + ? runningActions.get(call.parentActionEvent.id) + : undefined + + if (call.type === "action") { + const newCall: IActionTrackingMiddleware2Call = { + ...call, + // make a shallow copy of the parent action env + env: parentRunningAction && parentRunningAction.call.env, + parentCall: parentRunningAction && parentRunningAction.call + } + + const passesFilter = !middlewareHooks.filter || middlewareHooks.filter(newCall) + const hooks = passesFilter ? middlewareHooks : undefined + + const runningAction = new RunningAction(hooks, newCall) + runningActions.set(call.id, runningAction) + + let res + try { + res = next(call) + } catch (e) { + runningActions.delete(call.id) + runningAction.finish(e) + throw e + } + // sync action finished + if (!runningAction.hasFlowsPending) { + runningActions.delete(call.id) + runningAction.finish() + } + return res + } else { + if (!parentRunningAction) { + return next(call) + } + + switch (call.type) { + case "flow_spawn": { + parentRunningAction.incFlowsPending() + return next(call) + } + case "flow_resume": + case "flow_resume_error": { + return next(call) + } + case "flow_throw": { + const error = call.args[0] + try { + return next(call) + } finally { + parentRunningAction.decFlowsPending() + if (!parentRunningAction.hasFlowsPending) { + runningActions.delete(call.parentActionEvent!.id) + parentRunningAction.finish(error) + } + } + } + case "flow_return": { + try { + return next(call) + } finally { + parentRunningAction.decFlowsPending() + if (!parentRunningAction.hasFlowsPending) { + runningActions.delete(call.parentActionEvent!.id) + parentRunningAction.finish() + } + } + } + } + } + } +} diff --git a/src/middlewares/on-action.ts b/src/middlewares/on-action.ts new file mode 100644 index 000000000..470240e06 --- /dev/null +++ b/src/middlewares/on-action.ts @@ -0,0 +1,265 @@ +import { runInAction } from "mobx" + +import { + getStateTreeNode, + isStateTreeNode, + addMiddleware, + tryResolve, + applyPatch, + getType, + applySnapshot, + isRoot, + isProtected, + fail, + isPlainObject, + isPrimitive, + IDisposer, + isArray, + asArray, + getRelativePathBetweenNodes, + IAnyStateTreeNode, + warnError, + AnyNode, + assertIsStateTreeNode, + devMode, + assertArg, + IActionContext, + getRunningActionContext +} from "../internal" + +export interface ISerializedActionCall { + name: string + path?: string + args?: any[] +} + +export interface IActionRecorder { + actions: ReadonlyArray + readonly recording: boolean + stop(): void + resume(): void + replay(target: IAnyStateTreeNode): void +} + +function serializeArgument(node: AnyNode, actionName: string, index: number, arg: any): any { + if (arg instanceof Date) return { $MST_DATE: arg.getTime() } + if (isPrimitive(arg)) return arg + // We should not serialize MST nodes, even if we can, because we don't know if the receiving party can handle a raw snapshot instead of an + // MST type instance. So if one wants to serialize a MST node that was pass in, either explitly pass: 1: an id, 2: a (relative) path, 3: a snapshot + if (isStateTreeNode(arg)) return serializeTheUnserializable(`[MSTNode: ${getType(arg).name}]`) + if (typeof arg === "function") return serializeTheUnserializable(`[function]`) + if (typeof arg === "object" && !isPlainObject(arg) && !isArray(arg)) + return serializeTheUnserializable( + `[object ${ + (arg && (arg as any).constructor && (arg as any).constructor.name) || "Complex Object" + }]` + ) + try { + // Check if serializable, cycle free etc... + // MWE: there must be a better way.... + JSON.stringify(arg) // or throws + return arg + } catch (e) { + return serializeTheUnserializable("" + e) + } +} + +function deserializeArgument(adm: AnyNode, value: any): any { + if (value && typeof value === "object" && "$MST_DATE" in value) + return new Date(value["$MST_DATE"]) + return value +} + +function serializeTheUnserializable(baseType: string) { + return { + $MST_UNSERIALIZABLE: true, + type: baseType + } +} + +/** + * Applies an action or a series of actions in a single MobX transaction. + * Does not return any value + * Takes an action description as produced by the `onAction` middleware. + * + * @param target + * @param actions + */ +export function applyAction( + target: IAnyStateTreeNode, + actions: ISerializedActionCall | ISerializedActionCall[] +): void { + // check all arguments + assertIsStateTreeNode(target, 1) + assertArg(actions, (a) => typeof a === "object", "object or array", 2) + + runInAction(() => { + asArray(actions).forEach((action) => baseApplyAction(target, action)) + }) +} + +function baseApplyAction(target: IAnyStateTreeNode, action: ISerializedActionCall): any { + const resolvedTarget = tryResolve(target, action.path || "") + if (!resolvedTarget) throw fail(`Invalid action path: ${action.path || ""}`) + const node = getStateTreeNode(resolvedTarget) + + // Reserved functions + if (action.name === "@APPLY_PATCHES") { + return applyPatch.call(null, resolvedTarget, action.args![0]) + } + if (action.name === "@APPLY_SNAPSHOT") { + return applySnapshot.call(null, resolvedTarget, action.args![0]) + } + + if (!(typeof resolvedTarget[action.name] === "function")) + throw fail(`Action '${action.name}' does not exist in '${node.path}'`) + return resolvedTarget[action.name].apply( + resolvedTarget, + action.args ? action.args.map((v) => deserializeArgument(node, v)) : [] + ) +} + +/** + * Small abstraction around `onAction` and `applyAction`, attaches an action listener to a tree and records all the actions emitted. + * Returns an recorder object with the following signature: + * + * Example: + * ```ts + * export interface IActionRecorder { + * // the recorded actions + * actions: ISerializedActionCall[] + * // true if currently recording + * recording: boolean + * // stop recording actions + * stop(): void + * // resume recording actions + * resume(): void + * // apply all the recorded actions on the given object + * replay(target: IAnyStateTreeNode): void + * } + * ``` + * + * The optional filter function allows to skip recording certain actions. + * + * @param subject + * @returns + */ +export function recordActions( + subject: IAnyStateTreeNode, + filter?: (action: ISerializedActionCall, actionContext: IActionContext | undefined) => boolean +): IActionRecorder { + // check all arguments + assertIsStateTreeNode(subject, 1) + + const actions: ISerializedActionCall[] = [] + const listener = (call: ISerializedActionCall) => { + const recordThis = filter ? filter(call, getRunningActionContext()) : true + if (recordThis) { + actions.push(call) + } + } + + let disposer: IDisposer | undefined + const recorder: IActionRecorder = { + actions, + get recording() { + return !!disposer + }, + stop() { + if (disposer) { + disposer() + disposer = undefined + } + }, + resume() { + if (disposer) return + disposer = onAction(subject, listener) + }, + replay(target) { + applyAction(target, actions) + } + } + + recorder.resume() + return recorder +} + +/** + * Registers a function that will be invoked for each action that is called on the provided model instance, or to any of its children. + * See [actions](https://github.com/mobxjs/mobx-state-tree#actions) for more details. onAction events are emitted only for the outermost called action in the stack. + * Action can also be intercepted by middleware using addMiddleware to change the function call before it will be run. + * + * Not all action arguments might be serializable. For unserializable arguments, a struct like `{ $MST_UNSERIALIZABLE: true, type: "someType" }` will be generated. + * MST Nodes are considered non-serializable as well (they could be serialized as there snapshot, but it is uncertain whether an replaying party will be able to handle such a non-instantiated snapshot). + * Rather, when using `onAction` middleware, one should consider in passing arguments which are 1: an id, 2: a (relative) path, or 3: a snapshot. Instead of a real MST node. + * + * Example: + * ```ts + * const Todo = types.model({ + * task: types.string + * }) + * + * const TodoStore = types.model({ + * todos: types.array(Todo) + * }).actions(self => ({ + * add(todo) { + * self.todos.push(todo); + * } + * })) + * + * const s = TodoStore.create({ todos: [] }) + * + * let disposer = onAction(s, (call) => { + * console.log(call); + * }) + * + * s.add({ task: "Grab a coffee" }) + * // Logs: { name: "add", path: "", args: [{ task: "Grab a coffee" }] } + * ``` + * + * @param target + * @param listener + * @param attachAfter (default false) fires the listener *after* the action has executed instead of before. + * @returns + */ +export function onAction( + target: IAnyStateTreeNode, + listener: (call: ISerializedActionCall) => void, + attachAfter = false +): IDisposer { + // check all arguments + assertIsStateTreeNode(target, 1) + if (devMode()) { + if (!isRoot(target)) + warnError( + "Warning: Attaching onAction listeners to non root nodes is dangerous: No events will be emitted for actions initiated higher up in the tree." + ) + if (!isProtected(target)) + warnError( + "Warning: Attaching onAction listeners to non protected nodes is dangerous: No events will be emitted for direct modifications without action." + ) + } + + return addMiddleware(target, function handler(rawCall, next) { + if (rawCall.type === "action" && rawCall.id === rawCall.rootId) { + const sourceNode = getStateTreeNode(rawCall.context) + const info = { + name: rawCall.name, + path: getRelativePathBetweenNodes(getStateTreeNode(target), sourceNode), + args: rawCall.args.map((arg: any, index: number) => + serializeArgument(sourceNode, rawCall.name, index, arg) + ) + } + if (attachAfter) { + const res = next(rawCall) + listener(info) + return res + } else { + listener(info) + return next(rawCall) + } + } else { + return next(rawCall) + } + }) +} diff --git a/src/types/complex-types/array.ts b/src/types/complex-types/array.ts new file mode 100644 index 000000000..8ef9ff5f2 --- /dev/null +++ b/src/types/complex-types/array.ts @@ -0,0 +1,501 @@ +import { + _getAdministration, + action, + IArrayDidChange, + IArraySplice, + IArrayWillChange, + IArrayWillSplice, + intercept, + IObservableArray, + observable, + observe +} from "mobx" +import { + addHiddenFinalProp, + addHiddenWritableProp, + AnyNode, + AnyObjectNode, + assertIsType, + ComplexType, + convertChildNodesToArray, + createActionInvoker, + createObjectNode, + devMode, + EMPTY_ARRAY, + EMPTY_OBJECT, + ExtractCSTWithSTN, + fail, + flattenTypeErrors, + getContextForPath, + getStateTreeNode, + IAnyStateTreeNode, + IAnyType, + IChildNodesMap, + IHooksGetter, + IJsonPatch, + isArray, + isNode, + isPlainObject, + isStateTreeNode, + IStateTreeNode, + isType, + IType, + IValidationContext, + IValidationResult, + mobxShallow, + normalizeIdentifier, + ObjectNode, + typeCheckFailure, + typecheckInternal, + TypeFlags +} from "../../internal" + +/** @hidden */ +export interface IMSTArray extends IObservableArray { + // needs to be split or else it will complain about not being compatible with the array interface + push(...items: IT["Type"][]): number + push(...items: ExtractCSTWithSTN[]): number + + concat(...items: ConcatArray[]): IT["Type"][] + concat(...items: ConcatArray>[]): IT["Type"][] + + concat(...items: (IT["Type"] | ConcatArray)[]): IT["Type"][] + concat(...items: (ExtractCSTWithSTN | ConcatArray>)[]): IT["Type"][] + + splice(start: number, deleteCount?: number): IT["Type"][] + splice(start: number, deleteCount: number, ...items: IT["Type"][]): IT["Type"][] + splice(start: number, deleteCount: number, ...items: ExtractCSTWithSTN[]): IT["Type"][] + + unshift(...items: IT["Type"][]): number + unshift(...items: ExtractCSTWithSTN[]): number +} + +/** @hidden */ +export interface IArrayType + extends IType> { + hooks(hooks: IHooksGetter>): IArrayType +} + +/** + * @internal + * @hidden + */ +export class ArrayType extends ComplexType< + readonly IT["CreationType"][] | undefined, + IT["SnapshotType"][], + IMSTArray +> { + readonly flags = TypeFlags.Array + private readonly hookInitializers: Array>> = [] + constructor( + name: string, + private readonly _subType: IT, + hookInitializers: Array>> = [] + ) { + super(name) + this.hookInitializers = hookInitializers + } + + hooks(hooks: IHooksGetter>) { + const hookInitializers = + this.hookInitializers.length > 0 ? this.hookInitializers.concat(hooks) : [hooks] + return new ArrayType(this.name, this._subType, hookInitializers) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + return createObjectNode(this, parent, subpath, environment, initialValue) + } + + initializeChildNodes(objNode: this["N"], snapshot: this["C"] = []): IChildNodesMap { + const subType = (objNode.type as this)._subType + const result: IChildNodesMap = {} + snapshot.forEach((item, index) => { + const subpath = "" + index + result[subpath] = subType.instantiate(objNode, subpath, undefined, item) + }) + return result + } + + createNewInstance(childNodes: IChildNodesMap): this["T"] { + const options = { ...mobxShallow, name: this.name } + return observable.array(convertChildNodesToArray(childNodes), options) as this["T"] + } + + finalizeNewInstance(node: this["N"], instance: this["T"]): void { + _getAdministration(instance).dehancer = node.unbox + + const type = node.type as this + type.hookInitializers.forEach((initializer) => { + const hooks = initializer(instance) + Object.keys(hooks).forEach((name) => { + const hook = hooks[name as keyof typeof hooks]! + const actionInvoker = createActionInvoker(instance as IAnyStateTreeNode, name, hook) + ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(instance, name, actionInvoker) + }) + }) + + intercept(instance as IObservableArray, this.willChange) + observe(instance as IObservableArray, this.didChange) + } + + describe() { + return this.name + } + + getChildren(node: this["N"]): AnyNode[] { + return node.storedValue.slice() + } + + getChildNode(node: this["N"], key: string): AnyNode { + const index = Number(key) + if (index < node.storedValue.length) return node.storedValue[index] + throw fail("Not a child: " + key) + } + + willChange( + change: IArrayWillChange | IArrayWillSplice + ): IArrayWillChange | IArrayWillSplice | null { + const node = getStateTreeNode(change.object as IStateTreeNode) + node.assertWritable({ subpath: "" + change.index }) + const subType = (node.type as this)._subType + const childNodes = node.getChildren() + + switch (change.type) { + case "update": + { + if (change.newValue === change.object[change.index]) return null + + const updatedNodes = reconcileArrayChildren( + node, + subType, + [childNodes[change.index]], + [change.newValue], + [change.index] + ) + if (!updatedNodes) { + return null + } + change.newValue = updatedNodes[0] + } + break + case "splice": + { + const { index, removedCount, added } = change + + const addedNodes = reconcileArrayChildren( + node, + subType, + childNodes.slice(index, index + removedCount), + added, + added.map((_, i) => index + i) + ) + if (!addedNodes) { + return null + } + change.added = addedNodes + + // update paths of remaining items + for (let i = index + removedCount; i < childNodes.length; i++) { + childNodes[i].setParent(node, "" + (i + added.length - removedCount)) + } + } + break + } + return change + } + + getSnapshot(node: this["N"]): this["S"] { + return node.getChildren().map((childNode) => childNode.snapshot) + } + + processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { + const processed: this["S"] = [] + Object.keys(childNodes).forEach((key) => { + processed.push(childNodes[key].getSnapshot()) + }) + return processed + } + + didChange(change: IArrayDidChange | IArraySplice): void { + const node = getStateTreeNode(change.object as IAnyStateTreeNode) + switch (change.type) { + case "update": + return void node.emitPatch( + { + op: "replace", + path: "" + change.index, + value: change.newValue.snapshot, + oldValue: change.oldValue ? change.oldValue.snapshot : undefined + }, + node + ) + case "splice": + for (let i = change.removedCount - 1; i >= 0; i--) + node.emitPatch( + { + op: "remove", + path: "" + (change.index + i), + oldValue: change.removed[i].snapshot + }, + node + ) + for (let i = 0; i < change.addedCount; i++) + node.emitPatch( + { + op: "add", + path: "" + (change.index + i), + value: node.getChildNode("" + (change.index + i)).snapshot, + oldValue: undefined + }, + node + ) + return + } + } + + applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { + const target = node.storedValue + const index = subpath === "-" ? target.length : Number(subpath) + switch (patch.op) { + case "replace": + target[index] = patch.value + break + case "add": + target.splice(index, 0, patch.value) + break + case "remove": + target.splice(index, 1) + break + } + } + + applySnapshot(node: this["N"], snapshot: this["C"]): void { + typecheckInternal(this, snapshot) + const target = node.storedValue + target.replace(snapshot as any) + } + + getChildType(): IAnyType { + return this._subType + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (!isArray(value)) { + return typeCheckFailure(context, value, "Value is not an array") + } + + return flattenTypeErrors( + value.map((item, index) => + this._subType.validate(item, getContextForPath(context, "" + index, this._subType)) + ) + ) + } + + getDefaultSnapshot(): this["C"] { + return EMPTY_ARRAY as this["C"] + } + + removeChild(node: this["N"], subpath: string) { + node.storedValue.splice(Number(subpath), 1) + } +} +ArrayType.prototype.applySnapshot = action(ArrayType.prototype.applySnapshot) + +/** + * `types.array` - Creates an index based collection type who's children are all of a uniform declared type. + * + * This type will always produce [observable arrays](https://mobx.js.org/api.html#observablearray) + * + * Example: + * ```ts + * const Todo = types.model({ + * task: types.string + * }) + * + * const TodoStore = types.model({ + * todos: types.array(Todo) + * }) + * + * const s = TodoStore.create({ todos: [] }) + * unprotect(s) // needed to allow modifying outside of an action + * s.todos.push({ task: "Grab coffee" }) + * console.log(s.todos[0]) // prints: "Grab coffee" + * ``` + * + * @param subtype + * @returns + */ +export function array(subtype: IT): IArrayType { + assertIsType(subtype, 1) + return new ArrayType(`${subtype.name}[]`, subtype) +} + +function reconcileArrayChildren( + parent: AnyObjectNode, + childType: IType, + oldNodes: AnyNode[], + newValues: TT[], + newPaths: (string | number)[] +): AnyNode[] | null { + let nothingChanged = true + + for (let i = 0; ; i++) { + const hasNewNode = i <= newValues.length - 1 + const oldNode = oldNodes[i] + let newValue = hasNewNode ? newValues[i] : undefined + const newPath = "" + newPaths[i] + + // for some reason, instead of newValue we got a node, fallback to the storedValue + // TODO: https://github.com/mobxjs/mobx-state-tree/issues/340#issuecomment-325581681 + if (isNode(newValue)) newValue = newValue.storedValue + + if (!oldNode && !hasNewNode) { + // both are empty, end + break + } else if (!hasNewNode) { + // new one does not exists + nothingChanged = false + oldNodes.splice(i, 1) + if (oldNode instanceof ObjectNode) { + // since it is going to be returned by pop/splice/shift better create it before killing it + // so it doesn't end up in an undead state + oldNode.createObservableInstanceIfNeeded() + } + oldNode.die() + i-- + } else if (!oldNode) { + // there is no old node, create it + // check if already belongs to the same parent. if so, avoid pushing item in. only swapping can occur. + if (isStateTreeNode(newValue) && getStateTreeNode(newValue).parent === parent) { + // this node is owned by this parent, but not in the reconcilable set, so it must be double + throw fail( + `Cannot add an object to a state tree if it is already part of the same or another state tree. Tried to assign an object to '${ + parent.path + }/${newPath}', but it lives already at '${getStateTreeNode(newValue).path}'` + ) + } + nothingChanged = false + const newNode = valueAsNode(childType, parent, newPath, newValue) + oldNodes.splice(i, 0, newNode) + } else if (areSame(oldNode, newValue)) { + // both are the same, reconcile + oldNodes[i] = valueAsNode(childType, parent, newPath, newValue, oldNode) + } else { + // nothing to do, try to reorder + let oldMatch = undefined + + // find a possible candidate to reuse + for (let j = i; j < oldNodes.length; j++) { + if (areSame(oldNodes[j], newValue)) { + oldMatch = oldNodes.splice(j, 1)[0] + break + } + } + + nothingChanged = false + const newNode = valueAsNode(childType, parent, newPath, newValue, oldMatch) + oldNodes.splice(i, 0, newNode) + } + } + + return nothingChanged ? null : oldNodes +} + +/** + * Convert a value to a node at given parent and subpath. Attempts to reuse old node if possible and given. + */ +function valueAsNode( + childType: IAnyType, + parent: AnyObjectNode, + subpath: string, + newValue: any, + oldNode?: AnyNode +) { + // ensure the value is valid-ish + typecheckInternal(childType, newValue) + + function getNewNode() { + // the new value has a MST node + if (isStateTreeNode(newValue)) { + const childNode = getStateTreeNode(newValue) + childNode.assertAlive(EMPTY_OBJECT) + + // the node lives here + if (childNode.parent !== null && childNode.parent === parent) { + childNode.setParent(parent, subpath) + return childNode + } + } + // there is old node and new one is a value/snapshot + if (oldNode) { + return childType.reconcile(oldNode, newValue, parent, subpath) + } + + // nothing to do, create from scratch + return childType.instantiate(parent, subpath, undefined, newValue) + } + + const newNode = getNewNode() + if (oldNode && oldNode !== newNode) { + if (oldNode instanceof ObjectNode) { + // since it is going to be returned by pop/splice/shift better create it before killing it + // so it doesn't end up in an undead state + oldNode.createObservableInstanceIfNeeded() + } + oldNode.die() + } + return newNode +} + +/** + * Check if a node holds a value. + */ +function areSame(oldNode: AnyNode, newValue: any) { + // never consider dead old nodes for reconciliation + if (!oldNode.isAlive) { + return false + } + + // the new value has the same node + if (isStateTreeNode(newValue)) { + const newNode = getStateTreeNode(newValue) + return newNode.isAlive && newNode === oldNode + } + + // the provided value is the snapshot of the old node + if (oldNode.snapshot === newValue) { + return true + } + + // Non object nodes don't get reconciled + if (!(oldNode instanceof ObjectNode)) { + return false + } + + const oldNodeType = oldNode.getReconciliationType() + // new value is a snapshot with the correct identifier + return ( + oldNode.identifier !== null && + oldNode.identifierAttribute && + isPlainObject(newValue) && + oldNodeType.is(newValue) && + (oldNodeType as any).isMatchingSnapshotId(oldNode, newValue) + ) +} + +/** + * Returns if a given value represents an array type. + * + * @param type + * @returns `true` if the type is an array type. + */ +export function isArrayType( + type: IAnyType +): type is IArrayType { + return isType(type) && (type.flags & TypeFlags.Array) > 0 +} diff --git a/src/types/complex-types/map.ts b/src/types/complex-types/map.ts new file mode 100644 index 000000000..18690b7de --- /dev/null +++ b/src/types/complex-types/map.ts @@ -0,0 +1,516 @@ +import { + _interceptReads, + action, + IInterceptor, + IKeyValueMap, + IMapDidChange, + IMapWillChange, + intercept, + Lambda, + observable, + ObservableMap, + observe, + values, + IObservableMapInitialValues +} from "mobx" +import { + ComplexType, + createObjectNode, + escapeJsonPath, + fail, + flattenTypeErrors, + getContextForPath, + getStateTreeNode, + IAnyStateTreeNode, + IAnyType, + IChildNodesMap, + IValidationContext, + IJsonPatch, + isMutable, + isPlainObject, + isStateTreeNode, + isType, + IType, + IValidationResult, + ModelType, + ObjectNode, + typecheckInternal, + typeCheckFailure, + TypeFlags, + EMPTY_OBJECT, + normalizeIdentifier, + AnyObjectNode, + AnyNode, + IAnyModelType, + asArray, + cannotDetermineSubtype, + getSnapshot, + isValidIdentifier, + ExtractCSTWithSTN, + devMode, + createActionInvoker, + addHiddenFinalProp, + addHiddenWritableProp, + IHooksGetter +} from "../../internal" + +/** @hidden */ +export interface IMapType + extends IType< + IKeyValueMap | undefined, + IKeyValueMap, + IMSTMap + > { + hooks(hooks: IHooksGetter>): IMapType +} + +/** @hidden */ +export interface IMSTMap { + // bases on ObservableMap, but fine tuned to the auto snapshot conversion of MST + + clear(): void + delete(key: string): boolean + forEach( + callbackfn: (value: IT["Type"], key: string | number, map: this) => void, + thisArg?: any + ): void + get(key: string | number): IT["Type"] | undefined + has(key: string | number): boolean + set(key: string | number, value: ExtractCSTWithSTN): this + readonly size: number + put(value: ExtractCSTWithSTN): IT["Type"] + keys(): IterableIterator + values(): IterableIterator + entries(): IterableIterator<[string, IT["Type"]]> + [Symbol.iterator](): IterableIterator<[string, IT["Type"]]> + /** Merge another object into this map, returns self. */ + merge( + other: + | IMSTMap> + | IKeyValueMap> + | any + ): this + replace( + values: + | IMSTMap> + | IKeyValueMap> + | any + ): this + + toJSON(): IKeyValueMap + + toString(): string + [Symbol.toStringTag]: "Map" + + /** + * Observes this object. Triggers for the events 'add', 'update' and 'delete'. + * See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/observe + * for callback details + */ + observe( + listener: (changes: IMapDidChange) => void, + fireImmediately?: boolean + ): Lambda + intercept(handler: IInterceptor>): Lambda +} + +const needsIdentifierError = `Map.put can only be used to store complex values that have an identifier type attribute` + +function tryCollectModelTypes(type: IAnyType, modelTypes: Array): boolean { + const subtypes = type.getSubTypes() + if (subtypes === cannotDetermineSubtype) { + return false + } + if (subtypes) { + const subtypesArray = asArray(subtypes) + for (const subtype of subtypesArray) { + if (!tryCollectModelTypes(subtype, modelTypes)) return false + } + } + if (type instanceof ModelType) { + modelTypes.push(type) + } + return true +} + +/** + * @internal + * @hidden + */ +export enum MapIdentifierMode { + UNKNOWN, + YES, + NO +} + +class MSTMap extends ObservableMap { + constructor(initialData?: IObservableMapInitialValues | undefined, name?: string) { + super(initialData, (observable.ref as any).enhancer, name) + } + + get(key: string): IT["Type"] | undefined { + // maybe this is over-enthousiastic? normalize numeric keys to strings + return super.get("" + key) + } + + has(key: string) { + return super.has("" + key) + } + + delete(key: string) { + return super.delete("" + key) + } + + set(key: string, value: ExtractCSTWithSTN): this { + return super.set("" + key, value) + } + + put(value: ExtractCSTWithSTN): IT["Type"] { + if (!value) throw fail(`Map.put cannot be used to set empty values`) + if (isStateTreeNode(value)) { + const node = getStateTreeNode(value) + if (devMode()) { + if (!node.identifierAttribute) { + throw fail(needsIdentifierError) + } + } + if (node.identifier === null) { + throw fail(needsIdentifierError) + } + this.set(node.identifier, value) + return value as any + } else if (!isMutable(value)) { + throw fail(`Map.put can only be used to store complex values`) + } else { + const mapNode = getStateTreeNode(this as IAnyStateTreeNode) + const mapType = mapNode.type as MapType + + if (mapType.identifierMode !== MapIdentifierMode.YES) { + throw fail(needsIdentifierError) + } + + const idAttr = mapType.mapIdentifierAttribute! + const id = (value as any)[idAttr] + if (!isValidIdentifier(id)) { + // try again but this time after creating a node for the value + // since it might be an optional identifier + const newNode = this.put(mapType.getChildType().create(value, mapNode.environment)) + return this.put(getSnapshot(newNode)) + } + const key = normalizeIdentifier(id) + this.set(key, value) + return this.get(key) as any + } + } +} + +/** + * @internal + * @hidden + */ +export class MapType extends ComplexType< + IKeyValueMap | undefined, + IKeyValueMap, + IMSTMap +> { + identifierMode: MapIdentifierMode = MapIdentifierMode.UNKNOWN + mapIdentifierAttribute: string | undefined = undefined + readonly flags = TypeFlags.Map + + private readonly hookInitializers: Array>> = [] + + constructor( + name: string, + private readonly _subType: IAnyType, + hookInitializers: Array>> = [] + ) { + super(name) + this._determineIdentifierMode() + this.hookInitializers = hookInitializers + } + + hooks(hooks: IHooksGetter>) { + const hookInitializers = + this.hookInitializers.length > 0 ? this.hookInitializers.concat(hooks) : [hooks] + return new MapType(this.name, this._subType, hookInitializers) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + this._determineIdentifierMode() + return createObjectNode(this, parent, subpath, environment, initialValue) + } + + private _determineIdentifierMode() { + if (this.identifierMode !== MapIdentifierMode.UNKNOWN) { + return + } + + const modelTypes: IAnyModelType[] = [] + if (tryCollectModelTypes(this._subType, modelTypes)) { + const identifierAttribute: string | undefined = modelTypes.reduce( + (current: IAnyModelType["identifierAttribute"], type) => { + if (!type.identifierAttribute) return current + if (current && current !== type.identifierAttribute) { + throw fail( + `The objects in a map should all have the same identifier attribute, expected '${current}', but child of type '${type.name}' declared attribute '${type.identifierAttribute}' as identifier` + ) + } + return type.identifierAttribute + }, + undefined as IAnyModelType["identifierAttribute"] + ) + + if (identifierAttribute) { + this.identifierMode = MapIdentifierMode.YES + this.mapIdentifierAttribute = identifierAttribute + } else { + this.identifierMode = MapIdentifierMode.NO + } + } + } + + initializeChildNodes(objNode: this["N"], initialSnapshot: this["C"] = {}): IChildNodesMap { + const subType = (objNode.type as this)._subType + const result: IChildNodesMap = {} + Object.keys(initialSnapshot!).forEach((name) => { + result[name] = subType.instantiate(objNode, name, undefined, initialSnapshot[name]) + }) + + return result + } + + createNewInstance(childNodes: IChildNodesMap): this["T"] { + return new MSTMap(childNodes, this.name) as any + } + + finalizeNewInstance(node: this["N"], instance: ObservableMap): void { + _interceptReads(instance, node.unbox) + + const type = node.type as this + type.hookInitializers.forEach((initializer) => { + const hooks = initializer(instance as unknown as IMSTMap) + Object.keys(hooks).forEach((name) => { + const hook = hooks[name as keyof typeof hooks]! + const actionInvoker = createActionInvoker(instance as IAnyStateTreeNode, name, hook) + ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(instance, name, actionInvoker) + }) + }) + + intercept(instance, this.willChange) + observe(instance, this.didChange) + } + + describe() { + return this.name + } + + getChildren(node: this["N"]): ReadonlyArray { + // return (node.storedValue as ObservableMap).values() + return values(node.storedValue) + } + + getChildNode(node: this["N"], key: string): AnyNode { + const childNode = node.storedValue.get("" + key) + if (!childNode) throw fail("Not a child " + key) + return childNode + } + + willChange(change: IMapWillChange): IMapWillChange | null { + const node = getStateTreeNode(change.object as IAnyStateTreeNode) + const key = change.name + node.assertWritable({ subpath: key }) + const mapType = node.type as this + const subType = mapType._subType + + switch (change.type) { + case "update": + { + const { newValue } = change + const oldValue = change.object.get(key) + if (newValue === oldValue) return null + typecheckInternal(subType, newValue) + change.newValue = subType.reconcile(node.getChildNode(key), change.newValue, node, key) + mapType.processIdentifier(key, change.newValue) + } + break + case "add": + { + typecheckInternal(subType, change.newValue) + change.newValue = subType.instantiate(node, key, undefined, change.newValue) + mapType.processIdentifier(key, change.newValue) + } + break + } + return change + } + + private processIdentifier(expected: string, node: AnyNode): void { + if (this.identifierMode === MapIdentifierMode.YES && node instanceof ObjectNode) { + const identifier = node.identifier! + if (identifier !== expected) + throw fail( + `A map of objects containing an identifier should always store the object under their own identifier. Trying to store key '${identifier}', but expected: '${expected}'` + ) + } + } + + getSnapshot(node: this["N"]): this["S"] { + const res: any = {} + node.getChildren().forEach((childNode) => { + res[childNode.subpath] = childNode.snapshot + }) + return res + } + + processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { + const processed: any = {} + Object.keys(childNodes).forEach((key) => { + processed[key] = childNodes[key].getSnapshot() + }) + return processed + } + + didChange(change: IMapDidChange): void { + const node = getStateTreeNode(change.object as IAnyStateTreeNode) + switch (change.type) { + case "update": + return void node.emitPatch( + { + op: "replace", + path: escapeJsonPath(change.name), + value: change.newValue.snapshot, + oldValue: change.oldValue ? change.oldValue.snapshot : undefined + }, + node + ) + case "add": + return void node.emitPatch( + { + op: "add", + path: escapeJsonPath(change.name), + value: change.newValue.snapshot, + oldValue: undefined + }, + node + ) + case "delete": + // a node got deleted, get the old snapshot and make the node die + const oldSnapshot = change.oldValue.snapshot + change.oldValue.die() + // emit the patch + return void node.emitPatch( + { + op: "remove", + path: escapeJsonPath(change.name), + oldValue: oldSnapshot + }, + node + ) + } + } + + applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { + const target = node.storedValue + switch (patch.op) { + case "add": + case "replace": + target.set(subpath, patch.value) + break + case "remove": + target.delete(subpath) + break + } + } + + applySnapshot(node: this["N"], snapshot: this["C"]): void { + typecheckInternal(this, snapshot) + const target = node.storedValue + const currentKeys: { [key: string]: boolean } = {} + Array.from(target.keys()).forEach((key) => { + currentKeys[key] = false + }) + if (snapshot) { + // Don't use target.replace, as it will throw away all existing items first + for (let key in snapshot) { + target.set(key, snapshot[key]) + currentKeys["" + key] = true + } + } + Object.keys(currentKeys).forEach((key) => { + if (currentKeys[key] === false) target.delete(key) + }) + } + + getChildType(): IAnyType { + return this._subType + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (!isPlainObject(value)) { + return typeCheckFailure(context, value, "Value is not a plain object") + } + + return flattenTypeErrors( + Object.keys(value).map((path) => + this._subType.validate(value[path], getContextForPath(context, path, this._subType)) + ) + ) + } + + getDefaultSnapshot(): this["C"] { + return EMPTY_OBJECT as this["C"] + } + + removeChild(node: this["N"], subpath: string) { + node.storedValue.delete(subpath) + } +} +MapType.prototype.applySnapshot = action(MapType.prototype.applySnapshot) + +/** + * `types.map` - Creates a key based collection type who's children are all of a uniform declared type. + * If the type stored in a map has an identifier, it is mandatory to store the child under that identifier in the map. + * + * This type will always produce [observable maps](https://mobx.js.org/api.html#observablemap) + * + * Example: + * ```ts + * const Todo = types.model({ + * id: types.identifier, + * task: types.string + * }) + * + * const TodoStore = types.model({ + * todos: types.map(Todo) + * }) + * + * const s = TodoStore.create({ todos: {} }) + * unprotect(s) + * s.todos.set(17, { task: "Grab coffee", id: 17 }) + * s.todos.put({ task: "Grab cookie", id: 18 }) // put will infer key from the identifier + * console.log(s.todos.get(17).task) // prints: "Grab coffee" + * ``` + * + * @param subtype + * @returns + */ +export function map(subtype: IT): IMapType { + return new MapType(`Map`, subtype) +} + +/** + * Returns if a given value represents a map type. + * + * @param type + * @returns `true` if it is a map type. + */ +export function isMapType( + type: IAnyType +): type is IMapType { + return isType(type) && (type.flags & TypeFlags.Map) > 0 +} diff --git a/src/types/complex-types/model.ts b/src/types/complex-types/model.ts new file mode 100644 index 000000000..3fdf1d95f --- /dev/null +++ b/src/types/complex-types/model.ts @@ -0,0 +1,848 @@ +import { + _getAdministration, + _interceptReads, + action, + computed, + defineProperty, + intercept, + getAtom, + IObjectWillChange, + observable, + observe, + set, + IObjectDidChange, + makeObservable +} from "mobx" +import { + addHiddenFinalProp, + addHiddenWritableProp, + ArrayType, + ComplexType, + createActionInvoker, + createObjectNode, + EMPTY_ARRAY, + EMPTY_OBJECT, + escapeJsonPath, + fail, + flattenTypeErrors, + freeze, + getContextForPath, + getPrimitiveFactoryFromValue, + getStateTreeNode, + IAnyType, + IChildNodesMap, + IValidationContext, + IJsonPatch, + isPlainObject, + isPrimitive, + isStateTreeNode, + isType, + IType, + IValidationResult, + mobxShallow, + optional, + MapType, + typecheckInternal, + typeCheckFailure, + TypeFlags, + Hook, + AnyObjectNode, + AnyNode, + _CustomOrOther, + _NotCustomized, + Instance, + devMode, + assertIsString, + assertArg, + FunctionWithFlag +} from "../../internal" +import { ComputedValue } from "mobx/dist/internal" + +const PRE_PROCESS_SNAPSHOT = "preProcessSnapshot" +const POST_PROCESS_SNAPSHOT = "postProcessSnapshot" + +/** @hidden */ +export interface ModelProperties { + [key: string]: IAnyType +} + +/** @hidden */ +export type ModelPrimitive = string | number | boolean | Date + +/** @hidden */ +export interface ModelPropertiesDeclaration { + [key: string]: ModelPrimitive | IAnyType +} + +/** + * Unmaps syntax property declarations to a map of { propName: IType } + * + * @hidden + */ +export type ModelPropertiesDeclarationToProperties = + T extends { [k: string]: IAnyType } // optimization to reduce nesting + ? T + : { + [K in keyof T]: T[K] extends IAnyType // keep IAnyType check on the top to reduce nesting + ? T[K] + : T[K] extends string + ? IType + : T[K] extends number + ? IType + : T[K] extends boolean + ? IType + : T[K] extends Date + ? IType + : never + } + +/** + * Checks if a value is optional (undefined, any or unknown). + * @hidden + * + * Examples: + * - string = false + * - undefined = true + * - string | undefined = true + * - string & undefined = false, but we don't care + * - any = true + * - unknown = true + */ +type IsOptionalValue = undefined extends C ? TV : FV + +// type _A = IsOptionalValue // false +// type _B = IsOptionalValue // true +// type _C = IsOptionalValue // true +// type _D = IsOptionalValue // false, but we don't care +// type _E = IsOptionalValue // true +// type _F = IsOptionalValue // true + +/** + * Name of the properties of an object that can't be set to undefined, any or unknown + * @hidden + */ +type DefinablePropsNames = { [K in keyof T]: IsOptionalValue }[keyof T] + +/** @hidden */ +export declare const $nonEmptyObject: unique symbol + +/** @hidden */ +export interface NonEmptyObject { + [$nonEmptyObject]?: any +} + +/** @hidden */ +export type ExtractCFromProps

= { [k in keyof P]: P[k]["CreationType"] } + +/** @hidden */ +export type ModelCreationType = { [P in DefinablePropsNames]: PC[P] } & Partial & + NonEmptyObject + +/** @hidden */ +export type ModelCreationType2

= _CustomOrOther< + CustomC, + ModelCreationType> +> + +/** @hidden */ +export type ModelSnapshotType

= { + [K in keyof P]: P[K]["SnapshotType"] +} & NonEmptyObject + +/** @hidden */ +export type ModelSnapshotType2

= _CustomOrOther< + CustomS, + ModelSnapshotType

+> + +/** + * @hidden + * we keep this separate from ModelInstanceType to shorten model instance types generated declarations + */ +export type ModelInstanceTypeProps

= { + [K in keyof P]: P[K]["Type"] +} & NonEmptyObject + +/** + * @hidden + * do not transform this to an interface or model instance type generated declarations will be longer + */ +export type ModelInstanceType

= ModelInstanceTypeProps

& O + +/** @hidden */ +export interface ModelActions { + [key: string]: FunctionWithFlag +} + +export interface IModelType< + PROPS extends ModelProperties, + OTHERS, + CustomC = _NotCustomized, + CustomS = _NotCustomized +> extends IType< + ModelCreationType2, + ModelSnapshotType2, + ModelInstanceType + > { + readonly properties: PROPS + + named(newName: string): IModelType + + // warning: redefining props after a process snapshot is used ends up on the fixed (custom) C, S typings being overridden + // so it is recommended to use pre/post process snapshot after all props have been defined + props( + props: PROPS2 + ): IModelType, OTHERS, CustomC, CustomS> + + views( + fn: (self: Instance) => V + ): IModelType + + actions( + fn: (self: Instance) => A + ): IModelType + + volatile( + fn: (self: Instance) => TP + ): IModelType + + extend( + fn: (self: Instance) => { actions?: A; views?: V; state?: VS } + ): IModelType + + preProcessSnapshot>( + fn: (snapshot: NewC) => ModelCreationType2 + ): IModelType + + postProcessSnapshot>( + fn: (snapshot: ModelSnapshotType2) => NewS + ): IModelType +} + +/** + * Any model type. + */ +export interface IAnyModelType extends IModelType {} + +/** @hidden */ +export type ExtractProps = T extends IModelType + ? P + : never +/** @hidden */ +export type ExtractOthers = T extends IModelType + ? O + : never + +function objectTypeToString(this: any) { + return getStateTreeNode(this).toString() +} + +/** + * @internal + * @hidden + */ +export interface ModelTypeConfig { + name?: string + properties?: ModelPropertiesDeclaration + initializers?: ReadonlyArray<(instance: any) => any> + preProcessor?: (snapshot: any) => any + postProcessor?: (snapshot: any) => any +} + +const defaultObjectOptions = { + name: "AnonymousModel", + properties: {}, + initializers: EMPTY_ARRAY +} + +function toPropertiesObject(declaredProps: ModelPropertiesDeclaration): ModelProperties { + const keysList = Object.keys(declaredProps) + const alreadySeenKeys: { [key: string]: boolean } = {} + keysList.forEach((key) => { + if (alreadySeenKeys[key]) { + throw fail(`${key} is declared twice in the model. Model should not contain same keys`) + } else { + alreadySeenKeys[key] = true + } + }) + // loop through properties and ensures that all items are types + return keysList.reduce((props, key) => { + // warn if user intended a HOOK + if (key in Hook) + throw fail( + `Hook '${key}' was defined as property. Hooks should be defined as part of the actions` + ) + + // the user intended to use a view + const descriptor = Object.getOwnPropertyDescriptor(props, key)! + if ("get" in descriptor) { + throw fail("Getters are not supported as properties. Please use views instead") + } + // undefined and null are not valid + const value = descriptor.value + if (value === null || value === undefined) { + throw fail( + "The default value of an attribute cannot be null or undefined as the type cannot be inferred. Did you mean `types.maybe(someType)`?" + ) + // its a primitive, convert to its type + } else if (isPrimitive(value)) { + return Object.assign({}, props, { + [key]: optional(getPrimitiveFactoryFromValue(value), value) + }) + // map defaults to empty object automatically for models + } else if (value instanceof MapType) { + return Object.assign({}, props, { + [key]: optional(value, {}) + }) + } else if (value instanceof ArrayType) { + return Object.assign({}, props, { [key]: optional(value, []) }) + // its already a type + } else if (isType(value)) { + return props + // its a function, maybe the user wanted a view? + } else if (devMode() && typeof value === "function") { + throw fail( + `Invalid type definition for property '${key}', it looks like you passed a function. Did you forget to invoke it, or did you intend to declare a view / action?` + ) + // no other complex values + } else if (devMode() && typeof value === "object") { + throw fail( + `Invalid type definition for property '${key}', it looks like you passed an object. Try passing another model type or a types.frozen.` + ) + // WTF did you pass in mate? + } else { + throw fail( + `Invalid type definition for property '${key}', cannot infer a type from a value like '${value}' (${typeof value})` + ) + } + }, declaredProps as any) +} + +/** + * @internal + * @hidden + */ +export class ModelType< + PROPS extends ModelProperties, + OTHERS, + CustomC, + CustomS, + MT extends IModelType + > + extends ComplexType< + ModelCreationType2, + ModelSnapshotType2, + ModelInstanceType + > + implements IModelType +{ + readonly flags = TypeFlags.Object + + /* + * The original object definition + */ + public readonly initializers!: ((instance: any) => any)[] + public readonly properties!: PROPS + + private preProcessor!: (snapshot: any) => any | undefined + private postProcessor!: (snapshot: any) => any | undefined + private readonly propertyNames: string[] + + constructor(opts: ModelTypeConfig) { + super(opts.name || defaultObjectOptions.name) + Object.assign(this, defaultObjectOptions, opts) + // ensures that any default value gets converted to its related type + this.properties = toPropertiesObject(this.properties) as PROPS + freeze(this.properties) // make sure nobody messes with it + this.propertyNames = Object.keys(this.properties) + this.identifierAttribute = this._getIdentifierAttribute() + } + + private _getIdentifierAttribute(): string | undefined { + let identifierAttribute: string | undefined = undefined + this.forAllProps((propName, propType) => { + if (propType.flags & TypeFlags.Identifier) { + if (identifierAttribute) + throw fail( + `Cannot define property '${propName}' as object identifier, property '${identifierAttribute}' is already defined as identifier property` + ) + identifierAttribute = propName + } + }) + return identifierAttribute + } + + cloneAndEnhance(opts: ModelTypeConfig): IAnyModelType { + return new ModelType({ + name: opts.name || this.name, + properties: Object.assign({}, this.properties, opts.properties), + initializers: this.initializers.concat(opts.initializers || []), + preProcessor: opts.preProcessor || this.preProcessor, + postProcessor: opts.postProcessor || this.postProcessor + }) + } + + actions(fn: (self: Instance) => A) { + const actionInitializer = (self: Instance) => { + this.instantiateActions(self, fn(self)) + return self + } + return this.cloneAndEnhance({ initializers: [actionInitializer] }) + } + + private instantiateActions(self: this["T"], actions: ModelActions): void { + // check if return is correct + if (!isPlainObject(actions)) + throw fail(`actions initializer should return a plain object containing actions`) + + // bind actions to the object created + Object.keys(actions).forEach((name) => { + // warn if preprocessor was given + if (name === PRE_PROCESS_SNAPSHOT) + throw fail( + `Cannot define action '${PRE_PROCESS_SNAPSHOT}', it should be defined using 'type.preProcessSnapshot(fn)' instead` + ) + // warn if postprocessor was given + if (name === POST_PROCESS_SNAPSHOT) + throw fail( + `Cannot define action '${POST_PROCESS_SNAPSHOT}', it should be defined using 'type.postProcessSnapshot(fn)' instead` + ) + + let action2 = actions[name] + + // apply hook composition + let baseAction = (self as any)[name] + if (name in Hook && baseAction) { + let specializedAction = action2 + action2 = function () { + baseAction.apply(null, arguments) + specializedAction.apply(null, arguments) + } + } + + // the goal of this is to make sure actions using "this" can call themselves, + // while still allowing the middlewares to register them + const middlewares = (action2 as any).$mst_middleware // make sure middlewares are not lost + let boundAction = action2.bind(actions) + boundAction._isFlowAction = (action2 as FunctionWithFlag)._isFlowAction || false + boundAction.$mst_middleware = middlewares + const actionInvoker = createActionInvoker(self as any, name, boundAction) + actions[name] = actionInvoker + + // See #646, allow models to be mocked + ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(self, name, actionInvoker) + }) + } + + named: MT["named"] = (name) => { + return this.cloneAndEnhance({ name }) + } + + props: MT["props"] = (properties) => { + return this.cloneAndEnhance({ properties }) + } + + volatile(fn: (self: Instance) => TP) { + if (typeof fn !== "function") { + throw fail( + `You passed an ${typeof fn} to volatile state as an argument, when function is expected` + ) + } + const stateInitializer = (self: Instance) => { + this.instantiateVolatileState(self, fn(self)) + return self + } + return this.cloneAndEnhance({ initializers: [stateInitializer] }) + } + + private instantiateVolatileState( + self: this["T"], + state: { + [key: string]: any + } + ): void { + // check views return + if (!isPlainObject(state)) + throw fail(`volatile state initializer should return a plain object containing state`) + set(self, state) + } + + extend( + fn: (self: Instance) => { actions?: A; views?: V; state?: VS } + ) { + const initializer = (self: Instance) => { + const { actions, views, state, ...rest } = fn(self) + for (let key in rest) + throw fail( + `The \`extend\` function should return an object with a subset of the fields 'actions', 'views' and 'state'. Found invalid key '${key}'` + ) + if (state) this.instantiateVolatileState(self, state) + if (views) this.instantiateViews(self, views) + if (actions) this.instantiateActions(self, actions) + return self + } + return this.cloneAndEnhance({ initializers: [initializer] }) + } + + views(fn: (self: Instance) => V) { + const viewInitializer = (self: Instance) => { + this.instantiateViews(self, fn(self)) + return self + } + return this.cloneAndEnhance({ initializers: [viewInitializer] }) + } + + private instantiateViews(self: this["T"], views: Object): void { + // check views return + if (!isPlainObject(views)) + throw fail(`views initializer should return a plain object containing views`) + Object.getOwnPropertyNames(views).forEach((key) => { + // is this a computed property? + const descriptor = Object.getOwnPropertyDescriptor(views, key)! + if ("get" in descriptor) { + defineProperty(self, key, descriptor) + makeObservable(self, { [key]: computed } as any) + } else if (typeof descriptor.value === "function") { + // this is a view function, merge as is! + // See #646, allow models to be mocked + ;(!devMode() ? addHiddenFinalProp : addHiddenWritableProp)(self, key, descriptor.value) + } else { + throw fail(`A view member should either be a function or getter based property`) + } + }) + } + + preProcessSnapshot: MT["preProcessSnapshot"] = (preProcessor) => { + const currentPreprocessor = this.preProcessor + if (!currentPreprocessor) return this.cloneAndEnhance({ preProcessor }) + else + return this.cloneAndEnhance({ + preProcessor: (snapshot) => currentPreprocessor(preProcessor(snapshot)) + }) + } + + postProcessSnapshot: MT["postProcessSnapshot"] = (postProcessor) => { + const currentPostprocessor = this.postProcessor + if (!currentPostprocessor) return this.cloneAndEnhance({ postProcessor }) + else + return this.cloneAndEnhance({ + postProcessor: (snapshot) => postProcessor(currentPostprocessor(snapshot)) + }) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + const value = isStateTreeNode(initialValue) + ? initialValue + : this.applySnapshotPreProcessor(initialValue) + return createObjectNode(this, parent, subpath, environment, value) + // Optimization: record all prop- view- and action names after first construction, and generate an optimal base class + // that pre-reserves all these fields for fast object-member lookups + } + + initializeChildNodes(objNode: this["N"], initialSnapshot: any = {}): IChildNodesMap { + const type = objNode.type as this + const result: IChildNodesMap = {} + type.forAllProps((name, childType) => { + result[name] = childType.instantiate(objNode, name, undefined, (initialSnapshot as any)[name]) + }) + return result + } + + createNewInstance(childNodes: IChildNodesMap): this["T"] { + const options = { ...mobxShallow, name: this.name } + return observable.object(childNodes, EMPTY_OBJECT, options) as any + } + + finalizeNewInstance(node: this["N"], instance: this["T"]): void { + addHiddenFinalProp(instance, "toString", objectTypeToString) + + this.forAllProps((name) => { + _interceptReads(instance, name, node.unbox) + }) + + this.initializers.reduce((self, fn) => fn(self), instance) + intercept(instance, this.willChange) + observe(instance, this.didChange) + } + + private willChange(chg: IObjectWillChange): IObjectWillChange | null { + // TODO: mobx typings don't seem to take into account that newValue can be set even when removing a prop + const change = chg as IObjectWillChange & { newValue?: any } + + const node = getStateTreeNode(change.object) + const subpath = change.name as string + node.assertWritable({ subpath }) + const childType = (node.type as this).properties[subpath] + // only properties are typed, state are stored as-is references + if (childType) { + typecheckInternal(childType, change.newValue) + change.newValue = childType.reconcile( + node.getChildNode(subpath), + change.newValue, + node, + subpath + ) + } + return change + } + + private didChange(chg: IObjectDidChange) { + // TODO: mobx typings don't seem to take into account that newValue can be set even when removing a prop + const change = chg as IObjectWillChange & { newValue?: any; oldValue?: any } + + const childNode = getStateTreeNode(change.object) + const childType = (childNode.type as this).properties[change.name as string] + if (!childType) { + // don't emit patches for volatile state + return + } + const oldChildValue = change.oldValue ? change.oldValue.snapshot : undefined + childNode.emitPatch( + { + op: "replace", + path: escapeJsonPath(change.name as string), + value: change.newValue.snapshot, + oldValue: oldChildValue + }, + childNode + ) + } + + getChildren(node: this["N"]): ReadonlyArray { + const res: AnyNode[] = [] + this.forAllProps((name) => { + res.push(this.getChildNode(node, name)) + }) + return res + } + + getChildNode(node: this["N"], key: string): AnyNode { + if (!(key in this.properties)) throw fail("Not a value property: " + key) + const adm = _getAdministration(node.storedValue, key) + const childNode = adm.raw?.() + if (!childNode) throw fail("Node not available for property " + key) + return childNode + } + + getSnapshot(node: this["N"], applyPostProcess = true): this["S"] { + const res = {} as any + this.forAllProps((name, type) => { + try { + // TODO: FIXME, make sure the observable ref is used! + const atom = getAtom(node.storedValue, name) + ;(atom as any).reportObserved() + } catch (e) { + throw fail(`${name} property is declared twice`) + } + res[name] = this.getChildNode(node, name).snapshot + }) + if (applyPostProcess) { + return this.applySnapshotPostProcessor(res) + } + return res + } + + processInitialSnapshot(childNodes: IChildNodesMap): this["S"] { + const processed = {} as any + Object.keys(childNodes).forEach((key) => { + processed[key] = childNodes[key].getSnapshot() + }) + return this.applySnapshotPostProcessor(processed) + } + + applyPatchLocally(node: this["N"], subpath: string, patch: IJsonPatch): void { + if (!(patch.op === "replace" || patch.op === "add")) { + throw fail(`object does not support operation ${patch.op}`) + } + ;(node.storedValue as any)[subpath] = patch.value + } + + applySnapshot(node: this["N"], snapshot: this["C"]): void { + typecheckInternal(this, snapshot) + const preProcessedSnapshot = this.applySnapshotPreProcessor(snapshot) + this.forAllProps((name) => { + ;(node.storedValue as any)[name] = preProcessedSnapshot[name] + }) + } + + applySnapshotPreProcessor(snapshot: any) { + const processor = this.preProcessor + return processor ? processor.call(null, snapshot) : snapshot + } + + applySnapshotPostProcessor(snapshot: any) { + const postProcessor = this.postProcessor + if (postProcessor) return postProcessor.call(null, snapshot) + return snapshot + } + + getChildType(propertyName: string): IAnyType { + assertIsString(propertyName, 1) + + return this.properties[propertyName] + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + let snapshot = this.applySnapshotPreProcessor(value) + + if (!isPlainObject(snapshot)) { + return typeCheckFailure(context, snapshot, "Value is not a plain object") + } + + return flattenTypeErrors( + this.propertyNames.map((key) => + this.properties[key].validate( + snapshot[key], + getContextForPath(context, key, this.properties[key]) + ) + ) + ) + } + + private forAllProps(fn: (name: string, type: IAnyType) => void) { + this.propertyNames.forEach((key) => fn(key, this.properties[key])) + } + + describe() { + // optimization: cache + return ( + "{ " + + this.propertyNames.map((key) => key + ": " + this.properties[key].describe()).join("; ") + + " }" + ) + } + + getDefaultSnapshot(): this["C"] { + return EMPTY_OBJECT as this["C"] + } + + removeChild(node: this["N"], subpath: string) { + ;(node.storedValue as any)[subpath] = undefined + } +} +ModelType.prototype.applySnapshot = action(ModelType.prototype.applySnapshot) + +export function model

( + name: string, + properties?: P +): IModelType, {}> +export function model

( + properties?: P +): IModelType, {}> +/** + * `types.model` - Creates a new model type by providing a name, properties, volatile state and actions. + * + * See the [model type](/concepts/trees#creating-models) description or the [getting started](intro/getting-started.md#getting-started-1) tutorial. + */ +export function model(...args: any[]): any { + if (devMode() && typeof args[0] !== "string" && args[1]) { + throw fail( + "Model creation failed. First argument must be a string when two arguments are provided" + ) + } + + const name = typeof args[0] === "string" ? args.shift() : "AnonymousModel" + const properties = args.shift() || {} + return new ModelType({ name, properties }) +} + +// TODO: this can be simplified in TS3, since we can transform _NotCustomized to unknown, since unkonwn & X = X +// and then back unknown to _NotCustomized if needed +/** @hidden */ +export type _CustomJoin = A extends _NotCustomized ? B : A & B + +// generated with C:\VSProjects\github\mobx-state-tree-upstream\packages\mobx-state-tree\scripts\generate-compose-type.js +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType): IModelType, _CustomJoin> +// prettier-ignore +export function compose(A: IModelType, B: IModelType): IModelType, _CustomJoin> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType): IModelType>, _CustomJoin>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType): IModelType>, _CustomJoin>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType): IModelType>>, _CustomJoin>>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType): IModelType>>, _CustomJoin>>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType): IModelType>>>, _CustomJoin>>>> +// prettier-ignore +export function compose(A: + IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType): IModelType>>>, _CustomJoin>>>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType): IModelType>>>>, _CustomJoin>>>>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType): IModelType>>>>, _CustomJoin>>>>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType): IModelType>>>>>, _CustomJoin>>>>>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType): IModelType>>>>>, _CustomJoin>>>>>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType): IModelType>>>>>>, _CustomJoin>>>>>>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType): IModelType>>>>>>, _CustomJoin>>>>>>> +// prettier-ignore +export function compose(name: string, A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType, I: IModelType): IModelType>>>>>>>, _CustomJoin>>>>>>>> +// prettier-ignore +export function compose(A: IModelType, B: IModelType, C: IModelType, D: IModelType, E: IModelType, F: IModelType, G: IModelType, H: IModelType, I: IModelType): IModelType>>>>>>>, _CustomJoin>>>>>>>> + +/** + * `types.compose` - Composes a new model from one or more existing model types. + * This method can be invoked in two forms: + * Given 2 or more model types, the types are composed into a new Type. + * Given first parameter as a string and 2 or more model types, + * the types are composed into a new Type with the given name + */ +export function compose(...args: any[]): any { + // TODO: just join the base type names if no name is provided + const hasTypename = typeof args[0] === "string" + const typeName: string = hasTypename ? args[0] : "AnonymousModel" + if (hasTypename) { + args.shift() + } + + // check all parameters + if (devMode()) { + args.forEach((type, i) => { + assertArg(type, isModelType, "mobx-state-tree model type", hasTypename ? i + 2 : i + 1) + }) + } + + return args + .reduce((prev, cur) => + prev.cloneAndEnhance({ + name: prev.name + "_" + cur.name, + properties: cur.properties, + initializers: cur.initializers, + preProcessor: (snapshot: any) => + cur.applySnapshotPreProcessor(prev.applySnapshotPreProcessor(snapshot)), + postProcessor: (snapshot: any) => + cur.applySnapshotPostProcessor(prev.applySnapshotPostProcessor(snapshot)) + }) + ) + .named(typeName) +} + +/** + * Returns if a given value represents a model type. + * + * @param type + * @returns + */ +export function isModelType(type: IAnyType): type is IT { + return isType(type) && (type.flags & TypeFlags.Object) > 0 +} diff --git a/src/types/index.ts b/src/types/index.ts new file mode 100644 index 000000000..4c6af035f --- /dev/null +++ b/src/types/index.ts @@ -0,0 +1,64 @@ +// we import the types to re-export them inside types. +import { + enumeration, + model, + compose, + custom, + reference, + safeReference, + union, + optional, + literal, + maybe, + maybeNull, + refinement, + string, + boolean, + number, + integer, + float, + finite, + DatePrimitive, + map, + array, + frozen, + identifier, + identifierNumber, + late, + lazy, + undefinedType, + nullType, + snapshotProcessor +} from "../internal" + +export const types = { + enumeration, + model, + compose, + custom, + reference, + safeReference, + union, + optional, + literal, + maybe, + maybeNull, + refinement, + string, + boolean, + number, + integer, + float, + finite, + Date: DatePrimitive, + map, + array, + frozen, + identifier, + identifierNumber, + late, + lazy, + undefined: undefinedType, + null: nullType, + snapshotProcessor +} diff --git a/packages/mobx-state-tree/src/types/primitives.ts b/src/types/primitives.ts similarity index 53% rename from packages/mobx-state-tree/src/types/primitives.ts rename to src/types/primitives.ts index 6aef1ed8f..d0b30c541 100644 --- a/packages/mobx-state-tree/src/types/primitives.ts +++ b/src/types/primitives.ts @@ -1,22 +1,22 @@ import { - SimpleType, - isPrimitive, - fail, - identity, - createScalarNode, - ISimpleType, - IType, - TypeFlags, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - isType, - isInteger, - AnyObjectNode, - AnyNode, - isFloat, - isFinite + SimpleType, + isPrimitive, + fail, + identity, + createScalarNode, + ISimpleType, + IType, + TypeFlags, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + isType, + isInteger, + AnyObjectNode, + AnyNode, + isFloat, + isFinite } from "../internal" // TODO: implement CoreType using types.custom ? @@ -25,40 +25,40 @@ import { * @hidden */ export class CoreType extends SimpleType { - constructor( - name: string, - readonly flags: TypeFlags, - private readonly checker: (value: C) => boolean, - private readonly initializer: (v: C) => T = identity - ) { - super(name) - this.flags = flags - } - - describe() { - return this.name - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: C - ): this["N"] { - return createScalarNode(this, parent, subpath, environment, initialValue) - } - - createNewInstance(snapshot: C) { - return this.initializer(snapshot) - } - - isValidSnapshot(value: C, context: IValidationContext): IValidationResult { - if (isPrimitive(value) && this.checker(value as any)) { - return typeCheckSuccess() - } - const typeName = this.name === "Date" ? "Date or a unix milliseconds timestamp" : this.name - return typeCheckFailure(context, value, `Value is not a ${typeName}`) + constructor( + name: string, + readonly flags: TypeFlags, + private readonly checker: (value: C) => boolean, + private readonly initializer: (v: C) => T = identity + ) { + super(name) + this.flags = flags + } + + describe() { + return this.name + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: C + ): this["N"] { + return createScalarNode(this, parent, subpath, environment, initialValue) + } + + createNewInstance(snapshot: C) { + return this.initializer(snapshot) + } + + isValidSnapshot(value: C, context: IValidationContext): IValidationResult { + if (isPrimitive(value) && this.checker(value as any)) { + return typeCheckSuccess() } + const typeName = this.name === "Date" ? "Date or a unix milliseconds timestamp" : this.name + return typeCheckFailure(context, value, `Value is not a ${typeName}`) + } } /** @@ -75,9 +75,9 @@ export class CoreType extends SimpleType { */ // tslint:disable-next-line:variable-name export const string: ISimpleType = new CoreType( - "string", - TypeFlags.String, - (v) => typeof v === "string" + "string", + TypeFlags.String, + (v) => typeof v === "string" ) /** @@ -94,9 +94,9 @@ export const string: ISimpleType = new CoreType( */ // tslint:disable-next-line:variable-name export const number: ISimpleType = new CoreType( - "number", - TypeFlags.Number, - (v) => typeof v === "number" + "number", + TypeFlags.Number, + (v) => typeof v === "number" ) /** @@ -112,9 +112,9 @@ export const number: ISimpleType = new CoreType( */ // tslint:disable-next-line:variable-name export const integer: ISimpleType = new CoreType( - "integer", - TypeFlags.Integer, - (v) => isInteger(v) + "integer", + TypeFlags.Integer, + (v) => isInteger(v) ) /** @@ -130,9 +130,9 @@ export const integer: ISimpleType = new CoreType */ // tslint:disable-next-line:variable-name export const float: ISimpleType = new CoreType( - "float", - TypeFlags.Float, - (v) => isFloat(v) + "float", + TypeFlags.Float, + (v) => isFloat(v) ) /** @@ -148,9 +148,9 @@ export const float: ISimpleType = new CoreType( */ // tslint:disable-next-line:variable-name export const finite: ISimpleType = new CoreType( - "finite", - TypeFlags.Finite, - (v) => isFinite(v) + "finite", + TypeFlags.Finite, + (v) => isFinite(v) ) /** @@ -167,37 +167,37 @@ export const finite: ISimpleType = new CoreType( */ // tslint:disable-next-line:variable-name export const boolean: ISimpleType = new CoreType( - "boolean", - TypeFlags.Boolean, - (v) => typeof v === "boolean" + "boolean", + TypeFlags.Boolean, + (v) => typeof v === "boolean" ) /** * `types.null` - The type of the value `null` */ export const nullType: ISimpleType = new CoreType( - "null", - TypeFlags.Null, - (v) => v === null + "null", + TypeFlags.Null, + (v) => v === null ) /** * `types.undefined` - The type of the value `undefined` */ export const undefinedType: ISimpleType = new CoreType( - "undefined", - TypeFlags.Undefined, - (v) => v === undefined + "undefined", + TypeFlags.Undefined, + (v) => v === undefined ) const _DatePrimitive = new CoreType( - "Date", - TypeFlags.Date, - (v) => typeof v === "number" || v instanceof Date, - (v) => (v instanceof Date ? v : new Date(v)) + "Date", + TypeFlags.Date, + (v) => typeof v === "number" || v instanceof Date, + (v) => (v instanceof Date ? v : new Date(v)) ) _DatePrimitive.getSnapshot = function (node: AnyNode) { - return node.storedValue.getTime() + return node.storedValue.getTime() } /** @@ -219,17 +219,17 @@ export const DatePrimitive: IType = _DatePrimitive * @hidden */ export function getPrimitiveFactoryFromValue(value: any): ISimpleType { - switch (typeof value) { - case "string": - return string - case "number": - return number // In the future, isInteger(value) ? integer : number would be interesting, but would be too breaking for now - case "boolean": - return boolean - case "object": - if (value instanceof Date) return DatePrimitive - } - throw fail("Cannot determine primitive type from value " + value) + switch (typeof value) { + case "string": + return string + case "number": + return number // In the future, isInteger(value) ? integer : number would be interesting, but would be too breaking for now + case "boolean": + return boolean + case "object": + if (value instanceof Date) return DatePrimitive + } + throw fail("Cannot determine primitive type from value " + value) } /** @@ -239,20 +239,16 @@ export function getPrimitiveFactoryFromValue(value: any): ISimpleType { * @returns */ export function isPrimitiveType< - IT extends - | ISimpleType - | ISimpleType - | ISimpleType - | typeof DatePrimitive + IT extends ISimpleType | ISimpleType | ISimpleType | typeof DatePrimitive >(type: IT): type is IT { - return ( - isType(type) && - (type.flags & - (TypeFlags.String | - TypeFlags.Number | - TypeFlags.Integer | - TypeFlags.Boolean | - TypeFlags.Date)) > - 0 - ) + return ( + isType(type) && + (type.flags & + (TypeFlags.String | + TypeFlags.Number | + TypeFlags.Integer | + TypeFlags.Boolean | + TypeFlags.Date)) > + 0 + ) } diff --git a/src/types/utility-types/custom.ts b/src/types/utility-types/custom.ts new file mode 100644 index 000000000..2fb61aa68 --- /dev/null +++ b/src/types/utility-types/custom.ts @@ -0,0 +1,138 @@ +import { + createScalarNode, + SimpleType, + IType, + TypeFlags, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + AnyObjectNode +} from "../../internal" + +export interface CustomTypeOptions { + /** Friendly name */ + name: string + /** given a serialized value and environment, how to turn it into the target type */ + fromSnapshot(snapshot: S, env?: any): T + /** return the serialization of the current value */ + toSnapshot(value: T): S + /** if true, this is a converted value, if false, it's a snapshot */ + isTargetType(value: T | S): boolean + /** a non empty string is assumed to be a validation error */ + getValidationMessage(snapshot: S): string + // TODO: isSnapshotEqual + // TODO: isValueEqual +} + +/** + * `types.custom` - Creates a custom type. Custom types can be used for arbitrary immutable values, that have a serializable representation. For example, to create your own Date representation, Decimal type etc. + * + * The signature of the options is: + * ```ts + * export interface CustomTypeOptions { + * // Friendly name + * name: string + * // given a serialized value and environment, how to turn it into the target type + * fromSnapshot(snapshot: S, env: any): T + * // return the serialization of the current value + * toSnapshot(value: T): S + * // if true, this is a converted value, if false, it's a snapshot + * isTargetType(value: T | S): value is T + * // a non empty string is assumed to be a validation error + * getValidationMessage?(snapshot: S): string + * } + * ``` + * + * Example: + * ```ts + * const DecimalPrimitive = types.custom({ + * name: "Decimal", + * fromSnapshot(value: string) { + * return new Decimal(value) + * }, + * toSnapshot(value: Decimal) { + * return value.toString() + * }, + * isTargetType(value: string | Decimal): boolean { + * return value instanceof Decimal + * }, + * getValidationMessage(value: string): string { + * if (/^-?\d+\.\d+$/.test(value)) return "" // OK + * return `'${value}' doesn't look like a valid decimal number` + * } + * }) + * + * const Wallet = types.model({ + * balance: DecimalPrimitive + * }) + * ``` + * + * @param options + * @returns + */ +export function custom(options: CustomTypeOptions): IType { + return new CustomType(options) +} + +/** + * @internal + * @hidden + */ +export class CustomType extends SimpleType { + readonly flags = TypeFlags.Custom + + constructor(protected readonly options: CustomTypeOptions) { + super(options.name) + } + + describe() { + return this.name + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (this.options.isTargetType(value)) return typeCheckSuccess() + + const typeError: string = this.options.getValidationMessage(value as S) + if (typeError) { + return typeCheckFailure(context, value, `Invalid value for type '${this.name}': ${typeError}`) + } + return typeCheckSuccess() + } + + getSnapshot(node: this["N"]): S { + return this.options.toSnapshot(node.storedValue) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: S | T + ): this["N"] { + const valueToStore: T = this.options.isTargetType(initialValue) + ? (initialValue as T) + : this.options.fromSnapshot(initialValue as S, parent && parent.root.environment) + return createScalarNode(this, parent, subpath, environment, valueToStore) + } + + reconcile(current: this["N"], value: S | T, parent: AnyObjectNode, subpath: string): this["N"] { + const isSnapshot = !this.options.isTargetType(value) + // in theory customs use scalar nodes which cannot be detached, but still... + if (!current.isDetaching) { + const unchanged = + current.type === this && + (isSnapshot ? value === current.snapshot : value === current.storedValue) + if (unchanged) { + current.setParent(parent, subpath) + return current + } + } + const valueToStore: T = isSnapshot + ? this.options.fromSnapshot(value as S, parent.root.environment) + : (value as T) + const newNode = this.instantiate(parent, subpath, undefined, valueToStore) + current.die() // noop if detaching + return newNode + } +} diff --git a/packages/mobx-state-tree/src/types/utility-types/enumeration.ts b/src/types/utility-types/enumeration.ts similarity index 77% rename from packages/mobx-state-tree/src/types/utility-types/enumeration.ts rename to src/types/utility-types/enumeration.ts index 1576a0235..44beb3f4e 100644 --- a/packages/mobx-state-tree/src/types/utility-types/enumeration.ts +++ b/src/types/utility-types/enumeration.ts @@ -9,11 +9,11 @@ export type UnionStringArray = T[number] // the only case where this doesn't work is when passing to the function an array variable with a mutable type constraint; // for these cases, it will just fallback and assume the type is a generic string. export function enumeration( - options: T + options: T ): ISimpleType> export function enumeration( - name: string, - options: T[] + name: string, + options: T[] ): ISimpleType> /** @@ -32,14 +32,14 @@ export function enumeration( * @returns */ export function enumeration(name: string | string[], options?: any): ISimpleType { - const realOptions: string[] = typeof name === "string" ? options! : name - // check all options - if (devMode()) { - realOptions.forEach((option, i) => { - assertIsString(option, i + 1) - }) - } - const type = union(...realOptions.map((option) => literal("" + option))) - if (typeof name === "string") type.name = name - return type + const realOptions: string[] = typeof name === "string" ? options! : name + // check all options + if (devMode()) { + realOptions.forEach((option, i) => { + assertIsString(option, i + 1) + }) + } + const type = union(...realOptions.map((option) => literal("" + option))) + if (typeof name === "string") type.name = name + return type } diff --git a/packages/mobx-state-tree/src/types/utility-types/frozen.ts b/src/types/utility-types/frozen.ts similarity index 63% rename from packages/mobx-state-tree/src/types/utility-types/frozen.ts rename to src/types/utility-types/frozen.ts index ad4a5eb7a..837a281e5 100644 --- a/packages/mobx-state-tree/src/types/utility-types/frozen.ts +++ b/src/types/utility-types/frozen.ts @@ -1,18 +1,18 @@ import { - isSerializable, - deepFreeze, - createScalarNode, - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - TypeFlags, - isType, - optional, - IType, - IAnyType, - AnyObjectNode, - SimpleType + isSerializable, + deepFreeze, + createScalarNode, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + TypeFlags, + isType, + optional, + IType, + IAnyType, + AnyObjectNode, + SimpleType } from "../../internal" /** @@ -20,37 +20,33 @@ import { * @hidden */ export class Frozen extends SimpleType { - flags = TypeFlags.Frozen + flags = TypeFlags.Frozen - constructor(private subType?: IAnyType) { - super(subType ? `frozen(${subType.name})` : "frozen") - } + constructor(private subType?: IAnyType) { + super(subType ? `frozen(${subType.name})` : "frozen") + } - describe() { - return "" - } + describe() { + return "" + } - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - value: this["C"] - ): this["N"] { - // create the node - return createScalarNode(this, parent, subpath, environment, deepFreeze(value)) - } + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + value: this["C"] + ): this["N"] { + // create the node + return createScalarNode(this, parent, subpath, environment, deepFreeze(value)) + } - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (!isSerializable(value)) { - return typeCheckFailure( - context, - value, - "Value is not serializable and cannot be frozen" - ) - } - if (this.subType) return this.subType.validate(value, context) - return typeCheckSuccess() + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (!isSerializable(value)) { + return typeCheckFailure(context, value, "Value is not serializable and cannot be frozen") } + if (this.subType) return this.subType.validate(value, context) + return typeCheckSuccess() + } } const untypedFrozenInstance = new Frozen() @@ -99,9 +95,9 @@ export function frozen(): IType // do not assume undefined by * @returns */ export function frozen(arg?: any): any { - if (arguments.length === 0) return untypedFrozenInstance - else if (isType(arg)) return new Frozen(arg) - else return optional(untypedFrozenInstance, arg) + if (arguments.length === 0) return untypedFrozenInstance + else if (isType(arg)) return new Frozen(arg) + else return optional(untypedFrozenInstance, arg) } /** @@ -111,5 +107,5 @@ export function frozen(arg?: any): any { * @returns */ export function isFrozenType, T = any>(type: IT): type is IT { - return isType(type) && (type.flags & TypeFlags.Frozen) > 0 + return isType(type) && (type.flags & TypeFlags.Frozen) > 0 } diff --git a/src/types/utility-types/identifier.ts b/src/types/utility-types/identifier.ts new file mode 100644 index 000000000..28db18a4b --- /dev/null +++ b/src/types/utility-types/identifier.ts @@ -0,0 +1,166 @@ +import { + fail, + createScalarNode, + SimpleType, + TypeFlags, + isType, + IValidationContext, + IValidationResult, + typeCheckFailure, + ModelType, + typeCheckSuccess, + ISimpleType, + AnyObjectNode, + ScalarNode, + assertArg +} from "../../internal" + +abstract class BaseIdentifierType extends SimpleType { + readonly flags = TypeFlags.Identifier + + constructor(name: string, private readonly validType: "string" | "number") { + super(name) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] + ): this["N"] { + if (!parent || !(parent.type instanceof ModelType)) + throw fail(`Identifier types can only be instantiated as direct child of a model type`) + + return createScalarNode(this, parent, subpath, environment, initialValue) + } + + reconcile(current: this["N"], newValue: this["C"], parent: AnyObjectNode, subpath: string) { + // we don't consider detaching here since identifier are scalar nodes, and scalar nodes cannot be detached + if (current.storedValue !== newValue) + throw fail( + `Tried to change identifier from '${current.storedValue}' to '${newValue}'. Changing identifiers is not allowed.` + ) + current.setParent(parent, subpath) + return current + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (typeof value !== this.validType) { + return typeCheckFailure( + context, + value, + `Value is not a valid ${this.describe()}, expected a ${this.validType}` + ) + } + return typeCheckSuccess() + } +} + +/** + * @internal + * @hidden + */ +export class IdentifierType extends BaseIdentifierType { + readonly flags = TypeFlags.Identifier + + constructor() { + super(`identifier`, "string") + } + + describe() { + return `identifier` + } +} + +/** + * @internal + * @hidden + */ +export class IdentifierNumberType extends BaseIdentifierType { + constructor() { + super("identifierNumber", "number") + } + + getSnapshot(node: ScalarNode): number { + return node.storedValue + } + + describe() { + return `identifierNumber` + } +} + +/** + * `types.identifier` - Identifiers are used to make references, lifecycle events and reconciling works. + * Inside a state tree, for each type can exist only one instance for each given identifier. + * For example there couldn't be 2 instances of user with id 1. If you need more, consider using references. + * Identifier can be used only as type property of a model. + * This type accepts as parameter the value type of the identifier field that can be either string or number. + * + * Example: + * ```ts + * const Todo = types.model("Todo", { + * id: types.identifier, + * title: types.string + * }) + * ``` + * + * @returns + */ +export const identifier: ISimpleType = new IdentifierType() + +/** + * `types.identifierNumber` - Similar to `types.identifier`. This one will serialize from / to a number when applying snapshots + * + * Example: + * ```ts + * const Todo = types.model("Todo", { + * id: types.identifierNumber, + * title: types.string + * }) + * ``` + * + * @returns + */ +export const identifierNumber: ISimpleType = new IdentifierNumberType() + +/** + * Returns if a given value represents an identifier type. + * + * @param type + * @returns + */ +export function isIdentifierType( + type: IT +): type is IT { + return isType(type) && (type.flags & TypeFlags.Identifier) > 0 +} + +/** + * Valid types for identifiers. + */ +export type ReferenceIdentifier = string | number + +/** + * @internal + * @hidden + */ +export function normalizeIdentifier(id: ReferenceIdentifier): string { + return "" + id +} + +/** + * @internal + * @hidden + */ +export function isValidIdentifier(id: any): id is ReferenceIdentifier { + return typeof id === "string" || typeof id === "number" +} + +/** + * @internal + * @hidden + */ +export function assertIsValidIdentifier(id: ReferenceIdentifier, argNumber: number | number[]) { + assertArg(id, isValidIdentifier, "string or number (identifier)", argNumber) +} diff --git a/src/types/utility-types/late.ts b/src/types/utility-types/late.ts new file mode 100644 index 000000000..572a86f48 --- /dev/null +++ b/src/types/utility-types/late.ts @@ -0,0 +1,139 @@ +import { + fail, + BaseType, + IValidationContext, + IValidationResult, + TypeFlags, + isType, + IAnyType, + typeCheckSuccess, + AnyObjectNode, + ExtractNodeType, + cannotDetermineSubtype, + devMode +} from "../../internal" + +class Late extends BaseType< + IT["CreationType"], + IT["SnapshotType"], + IT["TypeWithoutSTN"], + ExtractNodeType +> { + private _subType?: IT + + get flags() { + return (this._subType ? this._subType.flags : 0) | TypeFlags.Late + } + + getSubType(mustSucceed: true): IT + getSubType(mustSucceed: false): IT | undefined + getSubType(mustSucceed: boolean): IT | undefined { + if (!this._subType) { + let t = undefined + try { + t = this._definition() + } catch (e) { + if (e instanceof ReferenceError) + // can happen in strict ES5 code when a definition is self refering + t = undefined + else throw e + } + if (mustSucceed && t === undefined) + throw fail("Late type seems to be used too early, the definition (still) returns undefined") + if (t) { + if (devMode() && !isType(t)) + throw fail("Failed to determine subtype, make sure types.late returns a type definition.") + this._subType = t + } + } + return this._subType + } + + constructor(name: string, private readonly _definition: () => IT) { + super(name) + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + return this.getSubType(true).instantiate(parent, subpath, environment, initialValue) as any + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + return this.getSubType(true).reconcile(current, newValue, parent, subpath) as any + } + + describe() { + const t = this.getSubType(false) + return t ? t.name : "" + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + const t = this.getSubType(false) + if (!t) { + // See #916; the variable the definition closure is pointing to wasn't defined yet, so can't be evaluted yet here + return typeCheckSuccess() + } + return t.validate(value, context) + } + + isAssignableFrom(type: IAnyType) { + const t = this.getSubType(false) + return t ? t.isAssignableFrom(type) : false + } + + getSubTypes() { + const subtype = this.getSubType(false) + return subtype ? subtype : cannotDetermineSubtype + } +} + +export function late(type: () => T): T +export function late(name: string, type: () => T): T +/** + * `types.late` - Defines a type that gets implemented later. This is useful when you have to deal with circular dependencies. + * Please notice that when defining circular dependencies TypeScript isn't smart enough to inference them. + * + * Example: + * ```ts + * // TypeScript isn't smart enough to infer self referencing types. + * const Node = types.model({ + * children: types.array(types.late((): IAnyModelType => Node)) // then typecast each array element to Instance + * }) + * ``` + * + * @param name The name to use for the type that will be returned. + * @param type A function that returns the type that will be defined. + * @returns + */ +export function late(nameOrType: any, maybeType?: () => IAnyType): IAnyType { + const name = typeof nameOrType === "string" ? nameOrType : `late(${nameOrType.toString()})` + const type = typeof nameOrType === "string" ? maybeType : nameOrType + // checks that the type is actually a late type + if (devMode()) { + if (!(typeof type === "function" && type.length === 0)) + throw fail( + "Invalid late type, expected a function with zero arguments that returns a type, got: " + + type + ) + } + return new Late(name, type) +} + +/** + * Returns if a given value represents a late type. + * + * @param type + * @returns + */ +export function isLateType(type: IT): type is IT { + return isType(type) && (type.flags & TypeFlags.Late) > 0 +} diff --git a/src/types/utility-types/lazy.ts b/src/types/utility-types/lazy.ts new file mode 100644 index 000000000..aa73a42d6 --- /dev/null +++ b/src/types/utility-types/lazy.ts @@ -0,0 +1,114 @@ +import { action, IObservableArray, observable, when } from "mobx" +import { AnyNode } from "../../core/node/BaseNode" +import { IType } from "../../core/type/type" +import { + IValidationContext, + IValidationResult, + TypeFlags, + typeCheckSuccess, + AnyObjectNode, + SimpleType, + createScalarNode, + deepFreeze, + isSerializable, + typeCheckFailure +} from "../../internal" + +interface LazyOptions, U> { + loadType: () => Promise + shouldLoadPredicate: (parent: U) => boolean +} + +export function lazy, U>( + name: string, + options: LazyOptions +): T { + // TODO: fix this unknown casting to be stricter + return new Lazy(name, options) as unknown as T +} + +/** + * @internal + * @hidden + */ +export class Lazy, U> extends SimpleType { + flags = TypeFlags.Lazy + + private loadedType: T | null = null + private pendingNodeList: IObservableArray = observable.array() + + constructor(name: string, private readonly options: LazyOptions) { + super(name) + + when( + () => + this.pendingNodeList.length > 0 && + this.pendingNodeList.some( + (node) => + node.isAlive && this.options.shouldLoadPredicate(node.parent ? node.parent.value : null) + ), + () => { + this.options.loadType().then( + action((type: T) => { + this.loadedType = type + this.pendingNodeList.forEach((node) => { + if (!node.parent) return + if (!this.loadedType) return + + node.parent.applyPatches([ + { + op: "replace", + path: `/${node.subpath}`, + value: node.snapshot + } + ]) + }) + }) + ) + } + ) + } + + describe() { + return `` + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + value: this["C"] + ): this["N"] { + if (this.loadedType) { + return this.loadedType.instantiate(parent, subpath, environment, value) as this["N"] + } + + const node = createScalarNode(this, parent, subpath, environment, deepFreeze(value)) + this.pendingNodeList.push(node) + + when( + () => !node.isAlive, + () => this.pendingNodeList.splice(this.pendingNodeList.indexOf(node), 1) + ) + + return node + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (this.loadedType) { + return this.loadedType.validate(value, context) + } + if (!isSerializable(value)) { + return typeCheckFailure(context, value, "Value is not serializable and cannot be lazy") + } + return typeCheckSuccess() + } + + reconcile(current: this["N"], value: T, parent: AnyObjectNode, subpath: string): this["N"] { + if (this.loadedType) { + current.die() + return this.loadedType.instantiate(parent, subpath, parent.environment, value) as this["N"] + } + return super.reconcile(current, value, parent, subpath) + } +} diff --git a/src/types/utility-types/literal.ts b/src/types/utility-types/literal.ts new file mode 100644 index 000000000..83ca6a650 --- /dev/null +++ b/src/types/utility-types/literal.ts @@ -0,0 +1,84 @@ +import { + fail, + isPrimitive, + createScalarNode, + ISimpleType, + TypeFlags, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + isType, + Primitives, + AnyObjectNode, + SimpleType, + devMode +} from "../../internal" +import { assertArg } from "../../utils" + +/** + * @internal + * @hidden + */ +export class Literal extends SimpleType { + readonly value: T + readonly flags = TypeFlags.Literal + + constructor(value: T) { + super(JSON.stringify(value)) + this.value = value + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] + ): this["N"] { + return createScalarNode(this, parent, subpath, environment, initialValue) + } + + describe() { + return JSON.stringify(this.value) + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (isPrimitive(value) && value === this.value) { + return typeCheckSuccess() + } + return typeCheckFailure(context, value, `Value is not a literal ${JSON.stringify(this.value)}`) + } +} + +/** + * `types.literal` - The literal type will return a type that will match only the exact given type. + * The given value must be a primitive, in order to be serialized to a snapshot correctly. + * You can use literal to match exact strings for example the exact male or female string. + * + * Example: + * ```ts + * const Person = types.model({ + * name: types.string, + * gender: types.union(types.literal('male'), types.literal('female')) + * }) + * ``` + * + * @param value The value to use in the strict equal check + * @returns + */ +export function literal(value: S): ISimpleType { + // check that the given value is a primitive + assertArg(value, isPrimitive, "primitive", 1) + + return new Literal(value) +} + +/** + * Returns if a given value represents a literal type. + * + * @param type + * @returns + */ +export function isLiteralType>(type: IT): type is IT { + return isType(type) && (type.flags & TypeFlags.Literal) > 0 +} diff --git a/packages/mobx-state-tree/src/types/utility-types/maybe.ts b/src/types/utility-types/maybe.ts similarity index 73% rename from packages/mobx-state-tree/src/types/utility-types/maybe.ts rename to src/types/utility-types/maybe.ts index ea315ce85..c8d5168c8 100644 --- a/packages/mobx-state-tree/src/types/utility-types/maybe.ts +++ b/src/types/utility-types/maybe.ts @@ -1,11 +1,11 @@ import { - union, - optional, - IType, - undefinedType, - nullType, - IAnyType, - assertIsType + union, + optional, + IType, + undefinedType, + nullType, + IAnyType, + assertIsType } from "../../internal" const optionalUndefinedType = optional(undefinedType, undefined) @@ -13,7 +13,7 @@ const optionalNullType = optional(nullType, null) /** @hidden */ export interface IMaybeIType - extends IType {} + extends IType {} /** @hidden */ export interface IMaybe extends IMaybeIType {} @@ -29,9 +29,9 @@ export interface IMaybeNull extends IMaybeIType(type: IT): IMaybe { - assertIsType(type, 1) + assertIsType(type, 1) - return union(type, optionalUndefinedType) + return union(type, optionalUndefinedType) } /** @@ -42,7 +42,7 @@ export function maybe(type: IT): IMaybe { * @returns */ export function maybeNull(type: IT): IMaybeNull { - assertIsType(type, 1) + assertIsType(type, 1) - return union(type, optionalNullType) + return union(type, optionalNullType) } diff --git a/src/types/utility-types/optional.ts b/src/types/utility-types/optional.ts new file mode 100644 index 000000000..6d785f895 --- /dev/null +++ b/src/types/utility-types/optional.ts @@ -0,0 +1,231 @@ +import { + isStateTreeNode, + IType, + TypeFlags, + isType, + IValidationContext, + IValidationResult, + typecheckInternal, + typeCheckSuccess, + fail, + IAnyType, + AnyObjectNode, + BaseType, + assertIsType, + ExtractCSTWithSTN, + devMode +} from "../../internal" + +type IFunctionReturn = () => T + +type IOptionalValue = C | IFunctionReturn + +/** @hidden */ +export type ValidOptionalValue = string | boolean | number | null | undefined + +/** @hidden */ +export type ValidOptionalValues = [ValidOptionalValue, ...ValidOptionalValue[]] + +/** + * @hidden + * @internal + */ +export class OptionalValue< + IT extends IAnyType, + OptionalVals extends ValidOptionalValues +> extends BaseType< + IT["CreationType"] | OptionalVals[number], + IT["SnapshotType"], + IT["TypeWithoutSTN"] +> { + get flags() { + return this._subtype.flags | TypeFlags.Optional + } + + constructor( + private readonly _subtype: IT, + private readonly _defaultValue: IOptionalValue, + readonly optionalValues: OptionalVals + ) { + super(_subtype.name) + } + + describe() { + return this._subtype.describe() + "?" + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + if (this.optionalValues.indexOf(initialValue) >= 0) { + const defaultInstanceOrSnapshot = this.getDefaultInstanceOrSnapshot() + return this._subtype.instantiate(parent, subpath, environment, defaultInstanceOrSnapshot) + } + return this._subtype.instantiate(parent, subpath, environment, initialValue) + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + return this._subtype.reconcile( + current, + this.optionalValues.indexOf(newValue) < 0 && this._subtype.is(newValue) + ? newValue + : this.getDefaultInstanceOrSnapshot(), + parent, + subpath + ) + } + + getDefaultInstanceOrSnapshot(): this["C"] | this["T"] { + const defaultInstanceOrSnapshot = + typeof this._defaultValue === "function" + ? (this._defaultValue as IFunctionReturn)() + : this._defaultValue + + // while static values are already snapshots and checked on types.optional + // generator functions must always be rechecked just in case + if (typeof this._defaultValue === "function") { + typecheckInternal(this, defaultInstanceOrSnapshot) + } + + return defaultInstanceOrSnapshot + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + // defaulted values can be skipped + if (this.optionalValues.indexOf(value) >= 0) { + return typeCheckSuccess() + } + // bounce validation to the sub-type + return this._subtype.validate(value, context) + } + + isAssignableFrom(type: IAnyType) { + return this._subtype.isAssignableFrom(type) + } + + getSubTypes() { + return this._subtype + } +} + +/** @hidden */ +export type OptionalDefaultValueOrFunction = + | IT["CreationType"] + | IT["SnapshotType"] + | (() => ExtractCSTWithSTN) + +/** @hidden */ +export interface IOptionalIType + extends IType< + IT["CreationType"] | OptionalVals[number], + IT["SnapshotType"], + IT["TypeWithoutSTN"] + > {} + +function checkOptionalPreconditions( + type: IAnyType, + defaultValueOrFunction: OptionalDefaultValueOrFunction +) { + // make sure we never pass direct instances + if (typeof defaultValueOrFunction !== "function" && isStateTreeNode(defaultValueOrFunction)) { + throw fail( + "default value cannot be an instance, pass a snapshot or a function that creates an instance/snapshot instead" + ) + } + assertIsType(type, 1) + if (devMode()) { + // we only check default values if they are passed directly + // if they are generator functions they will be checked once they are generated + // we don't check generator function results here to avoid generating a node just for type-checking purposes + // which might generate side-effects + if (typeof defaultValueOrFunction !== "function") { + typecheckInternal(type, defaultValueOrFunction) + } + } +} + +export function optional( + type: IT, + defaultValueOrFunction: OptionalDefaultValueOrFunction +): IOptionalIType +export function optional( + type: IT, + defaultValueOrFunction: OptionalDefaultValueOrFunction, + optionalValues: OptionalVals +): IOptionalIType +/** + * `types.optional` - Can be used to create a property with a default value. + * + * Depending on the third argument (`optionalValues`) there are two ways of operation: + * - If the argument is not provided, then if a value is not provided in the snapshot (`undefined` or missing), + * it will default to the provided `defaultValue` + * - If the argument is provided, then if the value in the snapshot matches one of the optional values inside the array then it will + * default to the provided `defaultValue`. Additionally, if one of the optional values inside the array is `undefined` then a missing + * property is also valid. + * + * Note that it is also possible to include values of the same type as the intended subtype as optional values, + * in this case the optional value will be transformed into the `defaultValue` (e.g. `types.optional(types.string, "unnamed", [undefined, ""])` + * will transform the snapshot values `undefined` (and therefore missing) and empty strings into the string `"unnamed"` when it gets + * instantiated). + * + * If `defaultValue` is a function, the function will be invoked for every new instance. + * Applying a snapshot in which the optional value is one of the optional values (or `undefined`/_not_ present if none are provided) causes the + * value to be reset. + * + * Example: + * ```ts + * const Todo = types.model({ + * title: types.string, + * subtitle1: types.optional(types.string, "", [null]), + * subtitle2: types.optional(types.string, "", [null, undefined]), + * done: types.optional(types.boolean, false), + * created: types.optional(types.Date, () => new Date()), + * }) + * + * // if done is missing / undefined it will become false + * // if created is missing / undefined it will get a freshly generated timestamp + * // if subtitle1 is null it will default to "", but it cannot be missing or undefined + * // if subtitle2 is null or undefined it will default to ""; since it can be undefined it can also be missing + * const todo = Todo.create({ title: "Get coffee", subtitle1: null }) + * ``` + * + * @param type + * @param defaultValueOrFunction + * @param optionalValues an optional array with zero or more primitive values (string, number, boolean, null or undefined) + * that will be converted into the default. `[ undefined ]` is assumed when none is provided + * @returns + */ +export function optional( + type: IT, + defaultValueOrFunction: OptionalDefaultValueOrFunction, + optionalValues?: OptionalVals +): IOptionalIType { + checkOptionalPreconditions(type, defaultValueOrFunction) + + return new OptionalValue( + type, + defaultValueOrFunction, + optionalValues ? optionalValues : undefinedAsOptionalValues + ) +} + +const undefinedAsOptionalValues: [undefined] = [undefined] + +/** + * Returns if a value represents an optional type. + * + * @template IT + * @param type + * @returns + */ +export function isOptionalType(type: IT): type is IT { + return isType(type) && (type.flags & TypeFlags.Optional) > 0 +} diff --git a/src/types/utility-types/reference.ts b/src/types/utility-types/reference.ts new file mode 100644 index 000000000..cc2aa5b56 --- /dev/null +++ b/src/types/utility-types/reference.ts @@ -0,0 +1,567 @@ +import { + getStateTreeNode, + isStateTreeNode, + createScalarNode, + IType, + TypeFlags, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + fail, + IAnyType, + IAnyStateTreeNode, + IAnyComplexType, + Hook, + IDisposer, + maybe, + isModelType, + IMaybe, + NodeLifeCycle, + ReferenceIdentifier, + normalizeIdentifier, + getIdentifier, + applyPatch, + AnyNode, + AnyObjectNode, + SimpleType, + assertIsType, + isValidIdentifier, + IStateTreeNode, + devMode +} from "../../internal" + +export type OnReferenceInvalidatedEvent = { + parent: IAnyStateTreeNode + invalidTarget: STN | undefined + invalidId: ReferenceIdentifier + replaceRef: (newRef: STN | null | undefined) => void + removeRef: () => void + cause: "detach" | "destroy" | "invalidSnapshotReference" +} + +export type OnReferenceInvalidated = ( + event: OnReferenceInvalidatedEvent +) => void + +function getInvalidationCause(hook: Hook): "detach" | "destroy" | undefined { + switch (hook) { + case Hook.beforeDestroy: + return "destroy" + case Hook.beforeDetach: + return "detach" + default: + return undefined + } +} + +/** @hidden */ +export type ReferenceT = IT["TypeWithoutSTN"] & + IStateTreeNode> + +class StoredReference { + readonly identifier!: ReferenceIdentifier + node!: AnyNode + + private resolvedReference?: { + node: AnyObjectNode + lastCacheModification: string + } + + constructor(value: ReferenceT | ReferenceIdentifier, private readonly targetType: IT) { + if (isValidIdentifier(value)) { + this.identifier = value + } else if (isStateTreeNode(value)) { + const targetNode = getStateTreeNode(value) + if (!targetNode.identifierAttribute) + throw fail(`Can only store references with a defined identifier attribute.`) + const id = targetNode.unnormalizedIdentifier + if (id === null || id === undefined) { + throw fail(`Can only store references to tree nodes with a defined identifier.`) + } + this.identifier = id + } else { + throw fail(`Can only store references to tree nodes or identifiers, got: '${value}'`) + } + } + + private updateResolvedReference(node: AnyNode) { + const normalizedId = normalizeIdentifier(this.identifier) + const root = node.root + const lastCacheModification = root.identifierCache!.getLastCacheModificationPerId(normalizedId) + if ( + !this.resolvedReference || + this.resolvedReference.lastCacheModification !== lastCacheModification + ) { + const { targetType } = this + // reference was initialized with the identifier of the target + + const target = root.identifierCache!.resolve(targetType, normalizedId) + + if (!target) { + throw new InvalidReferenceError( + `[mobx-state-tree] Failed to resolve reference '${this.identifier}' to type '${this.targetType.name}' (from node: ${node.path})` + ) + } + + this.resolvedReference = { + node: target!, + lastCacheModification: lastCacheModification + } + } + } + + get resolvedValue(): ReferenceT { + this.updateResolvedReference(this.node) + return this.resolvedReference!.node.value + } +} + +/** + * @internal + * @hidden + */ +export class InvalidReferenceError extends Error { + constructor(m: string) { + super(m) + + Object.setPrototypeOf(this, InvalidReferenceError.prototype) + } +} + +/** + * @internal + * @hidden + */ +export abstract class BaseReferenceType extends SimpleType< + ReferenceIdentifier, + ReferenceIdentifier, + IT["TypeWithoutSTN"] +> { + readonly flags = TypeFlags.Reference + + constructor( + protected readonly targetType: IT, + private readonly onInvalidated?: OnReferenceInvalidated> + ) { + super(`reference(${targetType.name})`) + } + + describe() { + return this.name + } + + isAssignableFrom(type: IAnyType): boolean { + return this.targetType.isAssignableFrom(type) + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + return isValidIdentifier(value) + ? typeCheckSuccess() + : typeCheckFailure( + context, + value, + "Value is not a valid identifier, which is a string or a number" + ) + } + + private fireInvalidated( + cause: "detach" | "destroy" | "invalidSnapshotReference", + storedRefNode: this["N"], + referenceId: ReferenceIdentifier, + refTargetNode: AnyObjectNode | null + ) { + // to actually invalidate a reference we need an alive parent, + // since it is a scalar value (immutable-ish) and we need to change it + // from the parent + const storedRefParentNode = storedRefNode.parent + if (!storedRefParentNode || !storedRefParentNode.isAlive) { + return + } + const storedRefParentValue = storedRefParentNode.storedValue + if (!storedRefParentValue) { + return + } + this.onInvalidated!({ + cause, + parent: storedRefParentValue, + invalidTarget: refTargetNode ? refTargetNode.storedValue : undefined, + invalidId: referenceId, + replaceRef(newRef) { + applyPatch(storedRefNode.root.storedValue, { + op: "replace", + value: newRef, + path: storedRefNode.path + }) + }, + removeRef() { + if (isModelType(storedRefParentNode.type)) { + this.replaceRef(undefined as any) + } else { + applyPatch(storedRefNode.root.storedValue, { + op: "remove", + path: storedRefNode.path + }) + } + } + }) + } + + private addTargetNodeWatcher( + storedRefNode: this["N"], + referenceId: ReferenceIdentifier + ): IDisposer | undefined { + // this will make sure the target node becomes created + const refTargetValue = this.getValue(storedRefNode) + if (!refTargetValue) { + return undefined + } + const refTargetNode = getStateTreeNode(refTargetValue) + + const hookHandler = (_: AnyNode, refTargetNodeHook: Hook) => { + const cause = getInvalidationCause(refTargetNodeHook) + if (!cause) { + return + } + this.fireInvalidated(cause, storedRefNode, referenceId, refTargetNode) + } + + const refTargetDetachHookDisposer = refTargetNode.registerHook(Hook.beforeDetach, hookHandler) + const refTargetDestroyHookDisposer = refTargetNode.registerHook(Hook.beforeDestroy, hookHandler) + + return () => { + refTargetDetachHookDisposer() + refTargetDestroyHookDisposer() + } + } + + protected watchTargetNodeForInvalidations( + storedRefNode: this["N"], + identifier: ReferenceIdentifier, + customGetSet: ReferenceOptionsGetSet | undefined + ) { + if (!this.onInvalidated) { + return + } + + let onRefTargetDestroyedHookDisposer: IDisposer | undefined + + // get rid of the watcher hook when the stored ref node is destroyed + // detached is ignored since scalar nodes (where the reference resides) cannot be detached + storedRefNode.registerHook(Hook.beforeDestroy, () => { + if (onRefTargetDestroyedHookDisposer) { + onRefTargetDestroyedHookDisposer() + } + }) + + const startWatching = (sync: boolean) => { + // re-create hook in case the stored ref gets reattached + if (onRefTargetDestroyedHookDisposer) { + onRefTargetDestroyedHookDisposer() + } + + // make sure the target node is actually there and initialized + const storedRefParentNode = storedRefNode.parent + const storedRefParentValue = storedRefParentNode && storedRefParentNode.storedValue + if (storedRefParentNode && storedRefParentNode.isAlive && storedRefParentValue) { + let refTargetNodeExists: boolean + if (customGetSet) { + refTargetNodeExists = !!customGetSet.get(identifier, storedRefParentValue) + } else { + refTargetNodeExists = storedRefNode.root.identifierCache!.has( + this.targetType, + normalizeIdentifier(identifier) + ) + } + + if (!refTargetNodeExists) { + // we cannot change the reference in sync mode + // since we are in the middle of a reconciliation/instantiation and the change would be overwritten + // for those cases just let the wrong reference be assigned and fail upon usage + // (like current references do) + // this means that effectively this code will only run when it is created from a snapshot + if (!sync) { + this.fireInvalidated("invalidSnapshotReference", storedRefNode, identifier, null) + } + } else { + onRefTargetDestroyedHookDisposer = this.addTargetNodeWatcher(storedRefNode, identifier) + } + } + } + + if (storedRefNode.state === NodeLifeCycle.FINALIZED) { + // already attached, so the whole tree is ready + startWatching(true) + } else { + if (!storedRefNode.isRoot) { + // start watching once the whole tree is ready + storedRefNode.root.registerHook(Hook.afterCreationFinalization, () => { + // make sure to attach it so it can start listening + if (storedRefNode.parent) { + storedRefNode.parent.createObservableInstanceIfNeeded() + } + }) + } + // start watching once the node is attached somewhere / parent changes + storedRefNode.registerHook(Hook.afterAttach, () => { + startWatching(false) + }) + } + } +} + +/** + * @internal + * @hidden + */ +export class IdentifierReferenceType extends BaseReferenceType { + constructor(targetType: IT, onInvalidated?: OnReferenceInvalidated>) { + super(targetType, onInvalidated) + } + + getValue(storedRefNode: this["N"]) { + if (!storedRefNode.isAlive) return undefined + const storedRef: StoredReference = storedRefNode.storedValue + return storedRef.resolvedValue as any + } + + getSnapshot(storedRefNode: this["N"]) { + const ref: StoredReference = storedRefNode.storedValue + return ref.identifier + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + const identifier = isStateTreeNode(initialValue) ? getIdentifier(initialValue)! : initialValue + const storedRef = new StoredReference(initialValue, this.targetType as any) + const storedRefNode: this["N"] = createScalarNode( + this, + parent, + subpath, + environment, + storedRef as any + ) + storedRef.node = storedRefNode + this.watchTargetNodeForInvalidations(storedRefNode, identifier as string, undefined) + return storedRefNode + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + if (!current.isDetaching && current.type === this) { + const compareByValue = isStateTreeNode(newValue) + const ref: StoredReference = current.storedValue + if ( + (!compareByValue && ref.identifier === newValue) || + (compareByValue && ref.resolvedValue === newValue) + ) { + current.setParent(parent, subpath) + return current + } + } + const newNode = this.instantiate(parent, subpath, undefined, newValue) + current.die() // noop if detaching + return newNode + } +} + +/** + * @internal + * @hidden + */ +export class CustomReferenceType extends BaseReferenceType { + constructor( + targetType: IT, + private readonly options: ReferenceOptionsGetSet, + onInvalidated?: OnReferenceInvalidated> + ) { + super(targetType, onInvalidated) + } + + getValue(storedRefNode: this["N"]) { + if (!storedRefNode.isAlive) return undefined as any + const referencedNode = this.options.get( + storedRefNode.storedValue, + storedRefNode.parent ? storedRefNode.parent.storedValue : null + ) + return referencedNode + } + + getSnapshot(storedRefNode: this["N"]) { + return storedRefNode.storedValue + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + newValue: this["C"] | this["T"] + ): this["N"] { + const identifier = isStateTreeNode(newValue) + ? this.options.set(newValue as any, parent ? parent.storedValue : null) + : newValue + const storedRefNode: this["N"] = createScalarNode( + this, + parent, + subpath, + environment, + identifier as any + ) + this.watchTargetNodeForInvalidations(storedRefNode, identifier as string, this.options) + return storedRefNode + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + const newIdentifier = isStateTreeNode(newValue) + ? this.options.set(newValue as any, current ? current.storedValue : null) + : newValue + if (!current.isDetaching && current.type === this && current.storedValue === newIdentifier) { + current.setParent(parent, subpath) + return current + } + const newNode = this.instantiate(parent, subpath, undefined, newIdentifier) + current.die() // noop if detaching + return newNode + } +} + +export interface ReferenceOptionsGetSet { + get(identifier: ReferenceIdentifier, parent: IAnyStateTreeNode | null): ReferenceT + set(value: ReferenceT, parent: IAnyStateTreeNode | null): ReferenceIdentifier +} + +export interface ReferenceOptionsOnInvalidated { + // called when the current reference is about to become invalid + onInvalidated: OnReferenceInvalidated> +} + +export type ReferenceOptions = + | ReferenceOptionsGetSet + | ReferenceOptionsOnInvalidated + | (ReferenceOptionsGetSet & ReferenceOptionsOnInvalidated) + +/** @hidden */ +export interface IReferenceType + extends IType {} + +/** + * `types.reference` - Creates a reference to another type, which should have defined an identifier. + * See also the [reference and identifiers](https://github.com/mobxjs/mobx-state-tree#references-and-identifiers) section. + */ +export function reference( + subType: IT, + options?: ReferenceOptions +): IReferenceType { + assertIsType(subType, 1) + if (devMode()) { + if (arguments.length === 2 && typeof arguments[1] === "string") { + // istanbul ignore next + throw fail("References with base path are no longer supported. Please remove the base path.") + } + } + + const getSetOptions = options ? (options as ReferenceOptionsGetSet) : undefined + const onInvalidated = options + ? (options as ReferenceOptionsOnInvalidated).onInvalidated + : undefined + + if (getSetOptions && (getSetOptions.get || getSetOptions.set)) { + if (devMode()) { + if (!getSetOptions.get || !getSetOptions.set) { + throw fail( + "reference options must either contain both a 'get' and a 'set' method or none of them" + ) + } + } + + return new CustomReferenceType( + subType, + { + get: getSetOptions.get, + set: getSetOptions.set + }, + onInvalidated + ) + } else { + return new IdentifierReferenceType(subType, onInvalidated) + } +} + +/** + * Returns if a given value represents a reference type. + * + * @param type + * @returns + */ +export function isReferenceType>(type: IT): type is IT { + return (type.flags & TypeFlags.Reference) > 0 +} + +export function safeReference( + subType: IT, + options: (ReferenceOptionsGetSet | {}) & { + acceptsUndefined: false + onInvalidated?: OnReferenceInvalidated> + } +): IReferenceType +export function safeReference( + subType: IT, + options?: (ReferenceOptionsGetSet | {}) & { + acceptsUndefined?: boolean + onInvalidated?: OnReferenceInvalidated> + } +): IMaybe> +/** + * `types.safeReference` - A safe reference is like a standard reference, except that it accepts the undefined value by default + * and automatically sets itself to undefined (when the parent is a model) / removes itself from arrays and maps + * when the reference it is pointing to gets detached/destroyed. + * + * The optional options parameter object accepts a parameter named `acceptsUndefined`, which is set to true by default, so it is suitable + * for model properties. + * When used inside collections (arrays/maps), it is recommended to set this option to false so it can't take undefined as value, + * which is usually the desired in those cases. + * Additionally, the optional options parameter object accepts a parameter named `onInvalidated`, which will be called when the reference target node that the reference is pointing to is about to be detached/destroyed + * + * Strictly speaking it is a `types.maybe(types.reference(X))` (when `acceptsUndefined` is set to true, the default) and + * `types.reference(X)` (when `acceptsUndefined` is set to false), both of them with a customized `onInvalidated` option. + * + * @param subType + * @param options + * @returns + */ +export function safeReference( + subType: IT, + options?: (ReferenceOptionsGetSet | {}) & { + acceptsUndefined?: boolean + onInvalidated?: OnReferenceInvalidated> + } +): IReferenceType | IMaybe> { + const refType = reference(subType, { + ...options, + onInvalidated(ev) { + if (options && options.onInvalidated) { + options.onInvalidated(ev) + } + ev.removeRef() + } + }) + + if (options && options.acceptsUndefined === false) { + return refType + } else { + return maybe(refType) + } +} diff --git a/src/types/utility-types/refinement.ts b/src/types/utility-types/refinement.ts new file mode 100644 index 000000000..976e3ef30 --- /dev/null +++ b/src/types/utility-types/refinement.ts @@ -0,0 +1,126 @@ +import { + isStateTreeNode, + getStateTreeNode, + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + isType, + fail, + TypeFlags, + IAnyType, + AnyObjectNode, + BaseType, + ExtractNodeType, + assertIsType, + devMode +} from "../../internal" +import { assertIsString, assertIsFunction } from "../../utils" + +class Refinement extends BaseType< + IT["CreationType"], + IT["SnapshotType"], + IT["TypeWithoutSTN"], + ExtractNodeType +> { + get flags() { + return this._subtype.flags | TypeFlags.Refinement + } + + constructor( + name: string, + private readonly _subtype: IT, + private readonly _predicate: (v: IT["CreationType"]) => boolean, + private readonly _message: (v: IT["CreationType"]) => string + ) { + super(name) + } + + describe() { + return this.name + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + // create the child type + return this._subtype.instantiate(parent, subpath, environment, initialValue) as any + } + + isAssignableFrom(type: IAnyType) { + return this._subtype.isAssignableFrom(type) + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + const subtypeErrors = this._subtype.validate(value, context) + if (subtypeErrors.length > 0) return subtypeErrors + + const snapshot = isStateTreeNode(value) ? getStateTreeNode(value).snapshot : value + + if (!this._predicate(snapshot)) { + return typeCheckFailure(context, value, this._message(value)) + } + + return typeCheckSuccess() + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + return this._subtype.reconcile(current, newValue, parent, subpath) as any + } + + getSubTypes() { + return this._subtype + } +} + +export function refinement( + name: string, + type: IT, + predicate: (snapshot: IT["CreationType"]) => boolean, + message?: string | ((v: IT["CreationType"]) => string) +): IT +export function refinement( + type: IT, + predicate: (snapshot: IT["CreationType"]) => boolean, + message?: string | ((v: IT["CreationType"]) => string) +): IT + +/** + * `types.refinement` - Creates a type that is more specific than the base type, e.g. `types.refinement(types.string, value => value.length > 5)` to create a type of strings that can only be longer then 5. + * + * @param name + * @param type + * @param predicate + * @returns + */ +export function refinement(...args: any[]): IAnyType { + const name = typeof args[0] === "string" ? args.shift() : isType(args[0]) ? args[0].name : null + const type = args[0] + const predicate = args[1] + const message = args[2] ? args[2] : (v: any) => "Value does not respect the refinement predicate" + // ensures all parameters are correct + assertIsType(type, [1, 2]) + assertIsString(name, 1) + assertIsFunction(predicate, [2, 3]) + assertIsFunction(message, [3, 4]) + + return new Refinement(name, type, predicate, message) +} + +/** + * Returns if a given value is a refinement type. + * + * @param type + * @returns + */ +export function isRefinementType(type: IT): type is IT { + return (type.flags & TypeFlags.Refinement) > 0 +} diff --git a/src/types/utility-types/snapshotProcessor.ts b/src/types/utility-types/snapshotProcessor.ts new file mode 100644 index 000000000..b94b94fed --- /dev/null +++ b/src/types/utility-types/snapshotProcessor.ts @@ -0,0 +1,268 @@ +import { + IType, + IAnyType, + BaseType, + isStateTreeNode, + IValidationContext, + IValidationResult, + AnyObjectNode, + TypeFlags, + ExtractNodeType, + assertIsType, + isType, + getSnapshot, + devMode, + ComplexType, + typeCheckFailure, + isUnionType +} from "../../internal" + +/** @hidden */ +declare const $mstNotCustomized: unique symbol + +/** @hidden */ +const $preProcessorFailed: unique symbol = Symbol("$preProcessorFailed") + +/** @hidden */ +// tslint:disable-next-line:class-name +export interface _NotCustomized { + // only for typings + readonly [$mstNotCustomized]: undefined +} +/** @hidden */ +export type _CustomOrOther = Custom extends _NotCustomized ? Other : Custom + +class SnapshotProcessor extends BaseType< + _CustomOrOther, + _CustomOrOther, + IT["TypeWithoutSTN"], + ExtractNodeType +> { + get flags() { + return this._subtype.flags | TypeFlags.SnapshotProcessor + } + + constructor( + private readonly _subtype: IT, + private readonly _processors: ISnapshotProcessors< + IT["CreationType"], + CustomC, + IT["SnapshotType"], + CustomS + >, + name?: string + ) { + super(name || _subtype.name) + } + + describe() { + return `snapshotProcessor(${this._subtype.describe()})` + } + + private preProcessSnapshot(sn: this["C"]): IT["CreationType"] { + if (this._processors.preProcessor) { + return this._processors.preProcessor.call(null, sn) + } + return sn as any + } + + private preProcessSnapshotSafe(sn: this["C"]): IT["CreationType"] | typeof $preProcessorFailed { + try { + return this.preProcessSnapshot(sn) + } catch (e) { + return $preProcessorFailed + } + } + + private postProcessSnapshot(sn: IT["SnapshotType"]): this["S"] { + if (this._processors.postProcessor) { + return this._processors.postProcessor.call(null, sn) as any + } + return sn + } + + private _fixNode(node: this["N"]): void { + // the node has to use these methods rather than the original type ones + proxyNodeTypeMethods(node.type, this, "create") + + const oldGetSnapshot = node.getSnapshot + node.getSnapshot = () => { + return this.postProcessSnapshot(oldGetSnapshot.call(node)) as any + } + if (!isUnionType(this._subtype)) { + node.getReconciliationType = () => { + return this + } + } + } + + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + const processedInitialValue = isStateTreeNode(initialValue) + ? initialValue + : this.preProcessSnapshot(initialValue) + const node = this._subtype.instantiate( + parent, + subpath, + environment, + processedInitialValue + ) as any + this._fixNode(node) + return node + } + + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + const node = this._subtype.reconcile( + current, + isStateTreeNode(newValue) ? newValue : this.preProcessSnapshot(newValue), + parent, + subpath + ) as any + if (node !== current) { + this._fixNode(node) + } + return node + } + + getSnapshot(node: this["N"], applyPostProcess: boolean = true): this["S"] { + const sn = this._subtype.getSnapshot(node) + return applyPostProcess ? this.postProcessSnapshot(sn) : sn + } + + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + const processedSn = this.preProcessSnapshotSafe(value) + if (processedSn === $preProcessorFailed) { + return typeCheckFailure(context, value, "Failed to preprocess value") + } + return this._subtype.validate(processedSn, context) + } + + getSubTypes() { + return this._subtype + } + + is(thing: any): thing is any { + const value = isType(thing) + ? this._subtype + : isStateTreeNode(thing) + ? getSnapshot(thing, false) + : this.preProcessSnapshotSafe(thing) + if (value === $preProcessorFailed) { + return false + } + return this._subtype.validate(value, [{ path: "", type: this._subtype }]).length === 0 + } + + isAssignableFrom(type: IAnyType): boolean { + return this._subtype.isAssignableFrom(type) + } + + isMatchingSnapshotId(current: this["N"], snapshot: this["C"]): boolean { + if (!(this._subtype instanceof ComplexType)) { + return false + } + const processedSn = this.preProcessSnapshot(snapshot) + return this._subtype.isMatchingSnapshotId(current as any, processedSn) + } +} + +function proxyNodeTypeMethods( + nodeType: any, + snapshotProcessorType: any, + ...methods: (keyof SnapshotProcessor)[] +) { + for (const method of methods) { + nodeType[method] = snapshotProcessorType[method].bind(snapshotProcessorType) + } +} + +// public API + +/** + * A type that has its snapshots processed. + */ +export interface ISnapshotProcessor + extends IType< + _CustomOrOther, + _CustomOrOther, + IT["TypeWithoutSTN"] + > {} + +/** + * Snapshot processors. + */ +export interface ISnapshotProcessors { + /** + * Function that transforms an input snapshot. + */ + preProcessor?(snapshot: CustomC): C + /** + * Function that transforms an output snapshot. + * @param snapshot + */ + postProcessor?(snapshot: S): CustomS +} + +/** + * `types.snapshotProcessor` - Runs a pre/post snapshot processor before/after serializing a given type. + * + * Example: + * ```ts + * const Todo1 = types.model({ text: types.string }) + * // in the backend the text type must be null when empty + * interface BackendTodo { + * text: string | null + * } + * const Todo2 = types.snapshotProcessor(Todo1, { + * // from snapshot to instance + * preProcessor(sn: BackendTodo) { + * return { + * text: sn.text || ""; + * } + * }, + * // from instance to snapshot + * postProcessor(sn): BackendTodo { + * return { + * text: !sn.text ? null : sn.text + * } + * } + * }) + * ``` + * + * @param type Type to run the processors over. + * @param processors Processors to run. + * @param name Type name, or undefined to inherit the inner type one. + * @returns + */ +export function snapshotProcessor< + IT extends IAnyType, + CustomC = _NotCustomized, + CustomS = _NotCustomized +>( + type: IT, + processors: ISnapshotProcessors, + name?: string +): ISnapshotProcessor { + assertIsType(type, 1) + if (devMode()) { + if (processors.postProcessor && typeof processors.postProcessor !== "function") { + // istanbul ignore next + throw fail("postSnapshotProcessor must be a function") + } + if (processors.preProcessor && typeof processors.preProcessor !== "function") { + // istanbul ignore next + throw fail("preSnapshotProcessor must be a function") + } + } + + return new SnapshotProcessor(type, processors, name) +} diff --git a/packages/mobx-state-tree/src/types/utility-types/union.ts b/src/types/utility-types/union.ts similarity index 82% rename from packages/mobx-state-tree/src/types/utility-types/union.ts rename to src/types/utility-types/union.ts index b1a76db2a..60ac01a87 100644 --- a/packages/mobx-state-tree/src/types/utility-types/union.ts +++ b/src/types/utility-types/union.ts @@ -1,34 +1,34 @@ import { - IValidationContext, - IValidationResult, - typeCheckSuccess, - typeCheckFailure, - flattenTypeErrors, - isType, - TypeFlags, - IType, - fail, - isPlainObject, - IAnyType, - IValidationError, - IModelType, - ModelProperties, - ModelInstanceType, - ModelSnapshotType2, - ModelCreationType2, - _NotCustomized, - AnyObjectNode, - BaseType, - devMode, - assertIsType, - assertArg + IValidationContext, + IValidationResult, + typeCheckSuccess, + typeCheckFailure, + flattenTypeErrors, + isType, + TypeFlags, + IType, + fail, + isPlainObject, + IAnyType, + IValidationError, + IModelType, + ModelProperties, + ModelInstanceType, + ModelSnapshotType2, + ModelCreationType2, + _NotCustomized, + AnyObjectNode, + BaseType, + devMode, + assertIsType, + assertArg } from "../../internal" export type ITypeDispatcher = (snapshot: any) => IAnyType export interface UnionOptions { - eager?: boolean - dispatcher?: ITypeDispatcher + eager?: boolean + dispatcher?: ITypeDispatcher } /** @@ -36,110 +36,108 @@ export interface UnionOptions { * @hidden */ export class Union extends BaseType { - private readonly _dispatcher?: ITypeDispatcher - private readonly _eager: boolean = true + private readonly _dispatcher?: ITypeDispatcher + private readonly _eager: boolean = true - get flags() { - let result: TypeFlags = TypeFlags.Union + get flags() { + let result: TypeFlags = TypeFlags.Union - this._types.forEach((type) => { - result |= type.flags - }) + this._types.forEach((type) => { + result |= type.flags + }) - return result - } + return result + } - constructor(name: string, private readonly _types: IAnyType[], options?: UnionOptions) { - super(name) - options = { - eager: true, - dispatcher: undefined, - ...options - } - this._dispatcher = options.dispatcher - if (!options.eager) this._eager = false + constructor(name: string, private readonly _types: IAnyType[], options?: UnionOptions) { + super(name) + options = { + eager: true, + dispatcher: undefined, + ...options } + this._dispatcher = options.dispatcher + if (!options.eager) this._eager = false + } - isAssignableFrom(type: IAnyType) { - return this._types.some((subType) => subType.isAssignableFrom(type)) - } + isAssignableFrom(type: IAnyType) { + return this._types.some((subType) => subType.isAssignableFrom(type)) + } - describe() { - return "(" + this._types.map((factory) => factory.describe()).join(" | ") + ")" - } - - instantiate( - parent: AnyObjectNode | null, - subpath: string, - environment: any, - initialValue: this["C"] | this["T"] - ): this["N"] { - const type = this.determineType(initialValue, undefined) - if (!type) throw fail("No matching type for union " + this.describe()) // can happen in prod builds - return type.instantiate(parent, subpath, environment, initialValue) - } + describe() { + return "(" + this._types.map((factory) => factory.describe()).join(" | ") + ")" + } - reconcile( - current: this["N"], - newValue: this["C"] | this["T"], - parent: AnyObjectNode, - subpath: string - ): this["N"] { - const type = this.determineType(newValue, current.getReconciliationType()) - if (!type) throw fail("No matching type for union " + this.describe()) // can happen in prod builds - return type.reconcile(current, newValue, parent, subpath) - } + instantiate( + parent: AnyObjectNode | null, + subpath: string, + environment: any, + initialValue: this["C"] | this["T"] + ): this["N"] { + const type = this.determineType(initialValue, undefined) + if (!type) throw fail("No matching type for union " + this.describe()) // can happen in prod builds + return type.instantiate(parent, subpath, environment, initialValue) + } - determineType( - value: this["C"] | this["T"], - reconcileCurrentType: IAnyType | undefined - ): IAnyType | undefined { - // try the dispatcher, if defined - if (this._dispatcher) { - return this._dispatcher(value) - } + reconcile( + current: this["N"], + newValue: this["C"] | this["T"], + parent: AnyObjectNode, + subpath: string + ): this["N"] { + const type = this.determineType(newValue, current.getReconciliationType()) + if (!type) throw fail("No matching type for union " + this.describe()) // can happen in prod builds + return type.reconcile(current, newValue, parent, subpath) + } - // find the most accomodating type - // if we are using reconciliation try the current node type first (fix for #1045) - if (reconcileCurrentType) { - if (reconcileCurrentType.is(value)) { - return reconcileCurrentType - } - return this._types - .filter((t) => t !== reconcileCurrentType) - .find((type) => type.is(value)) - } else { - return this._types.find((type) => type.is(value)) - } + determineType( + value: this["C"] | this["T"], + reconcileCurrentType: IAnyType | undefined + ): IAnyType | undefined { + // try the dispatcher, if defined + if (this._dispatcher) { + return this._dispatcher(value) } - isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { - if (this._dispatcher) { - return this._dispatcher(value).validate(value, context) - } - - const allErrors: IValidationError[][] = [] - let applicableTypes = 0 - for (let i = 0; i < this._types.length; i++) { - const type = this._types[i] - const errors = type.validate(value, context) - if (errors.length === 0) { - if (this._eager) return typeCheckSuccess() - else applicableTypes++ - } else { - allErrors.push(errors) - } - } + // find the most accomodating type + // if we are using reconciliation try the current node type first (fix for #1045) + if (reconcileCurrentType) { + if (reconcileCurrentType.is(value)) { + return reconcileCurrentType + } + return this._types.filter((t) => t !== reconcileCurrentType).find((type) => type.is(value)) + } else { + return this._types.find((type) => type.is(value)) + } + } - if (applicableTypes === 1) return typeCheckSuccess() - return typeCheckFailure(context, value, "No type is applicable for the union").concat( - flattenTypeErrors(allErrors) - ) + isValidSnapshot(value: this["C"], context: IValidationContext): IValidationResult { + if (this._dispatcher) { + return this._dispatcher(value).validate(value, context) } - getSubTypes() { - return this._types + const allErrors: IValidationError[][] = [] + let applicableTypes = 0 + for (let i = 0; i < this._types.length; i++) { + const type = this._types[i] + const errors = type.validate(value, context) + if (errors.length === 0) { + if (this._eager) return typeCheckSuccess() + else applicableTypes++ + } else { + allErrors.push(errors) + } } + + if (applicableTypes === 1) return typeCheckSuccess() + return typeCheckFailure(context, value, "No type is applicable for the union").concat( + flattenTypeErrors(allErrors) + ) + } + + getSubTypes() { + return this._types + } } /** @@ -147,12 +145,12 @@ export class Union extends BaseType { * @hidden */ export type _CustomCSProcessor = Exclude extends never - ? _NotCustomized - : Exclude + ? _NotCustomized + : Exclude /** @hidden */ export interface ITypeUnion - extends IType<_CustomCSProcessor, _CustomCSProcessor, T> {} + extends IType<_CustomCSProcessor, _CustomCSProcessor, T> {} // generated with packages/mobx-state-tree/scripts/generate-union-types.js // prettier-ignore @@ -252,25 +250,25 @@ export function union(dispatchOrType: UnionOptions | IAnyType, ...otherTypes: IA * @returns */ export function union(optionsOrType: UnionOptions | IAnyType, ...otherTypes: IAnyType[]): IAnyType { - const options = isType(optionsOrType) ? undefined : optionsOrType - const types = isType(optionsOrType) ? [optionsOrType, ...otherTypes] : otherTypes - const name = "(" + types.map((type) => type.name).join(" | ") + ")" + const options = isType(optionsOrType) ? undefined : optionsOrType + const types = isType(optionsOrType) ? [optionsOrType, ...otherTypes] : otherTypes + const name = "(" + types.map((type) => type.name).join(" | ") + ")" - // check all options - if (devMode()) { - if (options) { - assertArg( - options, - (o) => isPlainObject(o), - "object { eager?: boolean, dispatcher?: Function }", - 1 - ) - } - types.forEach((type, i) => { - assertIsType(type, options ? i + 2 : i + 1) - }) + // check all options + if (devMode()) { + if (options) { + assertArg( + options, + (o) => isPlainObject(o), + "object { eager?: boolean, dispatcher?: Function }", + 1 + ) } - return new Union(name, types, options) + types.forEach((type, i) => { + assertIsType(type, options ? i + 2 : i + 1) + }) + } + return new Union(name, types, options) } /** @@ -280,5 +278,5 @@ export function union(optionsOrType: UnionOptions | IAnyType, ...otherTypes: IAn * @returns */ export function isUnionType(type: IT): type is IT { - return (type.flags & TypeFlags.Union) > 0 + return (type.flags & TypeFlags.Union) > 0 } diff --git a/src/utils.ts b/src/utils.ts new file mode 100644 index 000000000..084a9f4ea --- /dev/null +++ b/src/utils.ts @@ -0,0 +1,499 @@ +import { + isObservableArray, + isObservableObject, + _getGlobalState, + defineProperty as mobxDefineProperty +} from "mobx" +import { Primitives } from "./core/type/type" + +const plainObjectString = Object.toString() + +/** + * @internal + * @hidden + */ +declare const global: any + +/** + * @internal + * @hidden + */ +export const EMPTY_ARRAY: ReadonlyArray = Object.freeze([]) + +/** + * @internal + * @hidden + */ +export const EMPTY_OBJECT: {} = Object.freeze({}) + +/** + * @internal + * @hidden + */ +export const mobxShallow = _getGlobalState().useProxies + ? { deep: false } + : { deep: false, proxy: false } +Object.freeze(mobxShallow) + +/** + * A generic disposer. + */ +export type IDisposer = () => void + +/** + * @internal + * @hidden + */ +export function fail(message = "Illegal state"): Error { + return new Error("[mobx-state-tree] " + message) +} + +/** + * @internal + * @hidden + */ +export function identity(_: any): any { + return _ +} + +/** + * @internal + * @hidden + */ +export function noop() {} + +/** + * @internal + * @hidden + */ +export const isInteger = Number.isInteger + +/** + * @internal + * @hidden + */ +export function isFloat(val: any) { + return Number(val) === val && val % 1 !== 0 +} + +/** + * @internal + * @hidden + */ +export function isFinite(val: any) { + return Number.isFinite(val) +} + +/** + * @internal + * @hidden + */ +export function isArray(val: any): val is any[] { + return Array.isArray(val) || isObservableArray(val) +} + +/** + * @internal + * @hidden + */ +export function asArray(val: undefined | null | T | T[] | ReadonlyArray): T[] { + if (!val) return EMPTY_ARRAY as any as T[] + if (isArray(val)) return val as T[] + return [val] as T[] +} + +/** + * @internal + * @hidden + */ +export function extend(a: A, b: B): A & B +/** + * @internal + * @hidden + */ +export function extend(a: A, b: B, c: C): A & B & C +/** + * @internal + * @hidden + */ +export function extend(a: A, b: B, c: C, d: D): A & B & C & D +/** + * @internal + * @hidden + */ +export function extend(a: any, ...b: any[]): any +/** + * @internal + * @hidden + */ +export function extend(a: any, ...b: any[]) { + for (let i = 0; i < b.length; i++) { + const current = b[i] + for (let key in current) a[key] = current[key] + } + return a +} + +/** + * @internal + * @hidden + */ +export function isPlainObject(value: any): value is { [k: string]: any } { + if (value === null || typeof value !== "object") return false + const proto = Object.getPrototypeOf(value) + if (proto == null) return true + return proto.constructor?.toString() === plainObjectString +} + +/** + * @internal + * @hidden + */ +export function isMutable(value: any) { + return ( + value !== null && + typeof value === "object" && + !(value instanceof Date) && + !(value instanceof RegExp) + ) +} + +/** + * @internal + * @hidden + */ +export function isPrimitive(value: any, includeDate = true): value is Primitives { + return ( + value === null || + value === undefined || + typeof value === "string" || + typeof value === "number" || + typeof value === "boolean" || + (includeDate && value instanceof Date) + ) +} + +/** + * @internal + * @hidden + * Freeze a value and return it (if not in production) + */ +export function freeze(value: T): T { + if (!devMode()) return value + return isPrimitive(value) || isObservableArray(value) ? value : Object.freeze(value) +} + +/** + * @internal + * @hidden + * Recursively freeze a value (if not in production) + */ +export function deepFreeze(value: T): T { + if (!devMode()) return value + freeze(value) + + if (isPlainObject(value)) { + Object.keys(value).forEach((propKey) => { + if (!isPrimitive((value as any)[propKey]) && !Object.isFrozen((value as any)[propKey])) { + deepFreeze((value as any)[propKey]) + } + }) + } + + return value +} + +/** + * @internal + * @hidden + */ +export function isSerializable(value: any) { + return typeof value !== "function" +} + +/** + * @internal + * @hidden + */ +export function defineProperty(object: any, key: PropertyKey, descriptor: PropertyDescriptor) { + isObservableObject(object) + ? mobxDefineProperty(object, key, descriptor) + : Object.defineProperty(object, key, descriptor) +} + +/** + * @internal + * @hidden + */ +export function addHiddenFinalProp(object: any, propName: string, value: any) { + defineProperty(object, propName, { + enumerable: false, + writable: false, + configurable: true, + value + }) +} + +/** + * @internal + * @hidden + */ +export function addHiddenWritableProp(object: any, propName: string, value: any) { + defineProperty(object, propName, { + enumerable: false, + writable: true, + configurable: true, + value + }) +} + +/** + * @internal + * @hidden + */ +export type ArgumentTypes = F extends (...args: infer A) => any ? A : never + +/** + * @internal + * @hidden + */ +class EventHandler { + private handlers: F[] = [] + + get hasSubscribers(): boolean { + return this.handlers.length > 0 + } + + register(fn: F, atTheBeginning = false): IDisposer { + if (atTheBeginning) { + this.handlers.unshift(fn) + } else { + this.handlers.push(fn) + } + return () => { + this.unregister(fn) + } + } + + has(fn: F): boolean { + return this.handlers.indexOf(fn) >= 0 + } + + unregister(fn: F) { + const index = this.handlers.indexOf(fn) + if (index >= 0) { + this.handlers.splice(index, 1) + } + } + + clear() { + this.handlers.length = 0 + } + + emit(...args: ArgumentTypes) { + // make a copy just in case it changes + const handlers = this.handlers.slice() + handlers.forEach((f) => f(...args)) + } +} + +/** + * @internal + * @hidden + */ +export class EventHandlers { + private eventHandlers?: { [k in keyof E]?: EventHandler } + + hasSubscribers(event: keyof E): boolean { + const handler = this.eventHandlers && this.eventHandlers[event] + return !!handler && handler!.hasSubscribers + } + + register(event: N, fn: E[N], atTheBeginning = false): IDisposer { + if (!this.eventHandlers) { + this.eventHandlers = {} + } + let handler = this.eventHandlers[event] + if (!handler) { + handler = this.eventHandlers[event] = new EventHandler() + } + return handler.register(fn, atTheBeginning) + } + + has(event: N, fn: E[N]): boolean { + const handler = this.eventHandlers && this.eventHandlers[event] + return !!handler && handler!.has(fn) + } + + unregister(event: N, fn: E[N]) { + const handler = this.eventHandlers && this.eventHandlers[event] + if (handler) { + handler!.unregister(fn) + } + } + + clear(event: N) { + if (this.eventHandlers) { + delete this.eventHandlers[event] + } + } + + clearAll() { + this.eventHandlers = undefined + } + + emit(event: N, ...args: ArgumentTypes) { + const handler = this.eventHandlers && this.eventHandlers[event] + if (handler) { + ;(handler!.emit as any)(...args) + } + } +} + +const prototypeHasOwnProperty = Object.prototype.hasOwnProperty + +/** + * @internal + * @hidden + */ +export function hasOwnProperty(object: Object, propName: string) { + return prototypeHasOwnProperty.call(object, propName) +} + +/** + * @internal + * @hidden + */ +export function argsToArray(args: IArguments): any[] { + const res = new Array(args.length) + for (let i = 0; i < args.length; i++) res[i] = args[i] + return res +} + +/** + * @internal + * @hidden + */ +export function stringStartsWith(str: string, beginning: string) { + return str.indexOf(beginning) === 0 +} + +/** + * @internal + * @hidden + */ +export type DeprecatedFunction = Function & { ids?: { [id: string]: true } } + +/** + * @internal + * @hidden + */ +export const deprecated: DeprecatedFunction = function (id: string, message: string): void { + // skip if running production + if (!devMode()) return + // warn if hasn't been warned before + if (deprecated.ids && !deprecated.ids.hasOwnProperty(id)) { + warnError("Deprecation warning: " + message) + } + // mark as warned to avoid duplicate warn message + if (deprecated.ids) deprecated.ids[id] = true +} +deprecated.ids = {} + +/** + * @internal + * @hidden + */ +export function warnError(msg: string) { + console.warn(new Error(`[mobx-state-tree] ${msg}`)) +} +/** + * @internal + * @hidden + */ +export function isTypeCheckingEnabled() { + return ( + devMode() || + (typeof process !== "undefined" && process.env && process.env.ENABLE_TYPE_CHECK === "true") + ) +} + +/** + * @internal + * @hidden + */ +export function devMode() { + return process.env.NODE_ENV !== "production" +} + +/** + * @internal + * @hidden + */ +export function assertArg( + value: T, + fn: (value: T) => boolean, + typeName: string, + argNumber: number | number[] +) { + if (devMode()) { + if (!fn(value)) { + // istanbul ignore next + throw fail( + `expected ${typeName} as argument ${asArray(argNumber).join(" or ")}, got ${value} instead` + ) + } + } +} + +/** + * @internal + * @hidden + */ +export function assertIsFunction(value: Function, argNumber: number | number[]) { + assertArg(value, (fn) => typeof fn === "function", "function", argNumber) +} + +/** + * @internal + * @hidden + */ +export function assertIsNumber( + value: number, + argNumber: number | number[], + min?: number, + max?: number +) { + assertArg(value, (n) => typeof n === "number", "number", argNumber) + if (min !== undefined) { + assertArg(value, (n) => n >= min, `number greater than ${min}`, argNumber) + } + if (max !== undefined) { + assertArg(value, (n) => n <= max, `number lesser than ${max}`, argNumber) + } +} + +/** + * @internal + * @hidden + */ +export function assertIsString(value: string, argNumber: number | number[], canBeEmpty = true) { + assertArg(value, (s) => typeof s === "string", "string", argNumber) + if (!canBeEmpty) { + assertArg(value, (s) => s !== "", "not empty string", argNumber) + } +} + +/** + * @internal + * @hidden + */ +export function setImmediateWithFallback(fn: (...args: any[]) => void) { + if (typeof queueMicrotask === "function") { + queueMicrotask(fn) + } else if (typeof setImmediate === "function") { + setImmediate(fn) + } else { + setTimeout(fn, 1) + } +} diff --git a/test-results/.gitkeep b/test-results/.gitkeep new file mode 100644 index 000000000..e69de29bb diff --git a/test-results/mobx-state-tree/.gitkeep b/test-results/mobx-state-tree/.gitkeep deleted file mode 100644 index 49cc8ef0e..000000000 Binary files a/test-results/mobx-state-tree/.gitkeep and /dev/null differ diff --git a/test-results/mst-middlewares/.gitkeep b/test-results/mst-middlewares/.gitkeep deleted file mode 100644 index 49cc8ef0e..000000000 Binary files a/test-results/mst-middlewares/.gitkeep and /dev/null differ diff --git a/tsconfig.base.json b/tsconfig.json similarity index 85% rename from tsconfig.base.json rename to tsconfig.json index 9e2c48e8f..30b2ba0d8 100644 --- a/tsconfig.base.json +++ b/tsconfig.json @@ -1,5 +1,6 @@ { "compilerOptions": { + "outDir": "lib/", "target": "es5", "sourceMap": false, "declaration": true, @@ -18,6 +19,7 @@ "stripInternal": true, "downlevelIteration": true, "lib": ["es6"], - "useDefineForClassFields": true, - } + "useDefineForClassFields": true + }, + "files": ["src/index.ts"] } diff --git a/typedocconfig.js b/typedocconfig.js new file mode 100644 index 000000000..7b4e2ab6b --- /dev/null +++ b/typedocconfig.js @@ -0,0 +1,14 @@ +module.exports = { + src: ["src/index.ts"], + module: "commonjs", + excludeNotExported: true, + excludePrivate: true, + excludeProtected: true, + mode: "file", + readme: "none", + out: "./docs/API", + theme: "docusaurus", + tsconfig: "tsconfig.json", + listInvalidSymbolLinks: true, + mdHideSources: true +} diff --git a/website/i18n/en.json b/website/i18n/en.json index 9d7cab9ce..9990e3d17 100644 --- a/website/i18n/en.json +++ b/website/i18n/en.json @@ -9,7 +9,7 @@ "title": "API_header" }, "API/index": { - "title": "mobx-state-tree - v5.2.0-alpha.1", + "title": "mobx-state-tree - v5.3.0-alpha.1", "sidebar_label": "Globals" }, "API/interfaces/customtypeoptions": { @@ -192,9 +192,6 @@ "title": "Handle circular dependencies between files and types using `late`", "sidebar_label": "Circular dependencies" }, - "tips/contributing": { - "title": "Contributing" - }, "tips/faq": { "title": "Frequently Asked Questions" }, diff --git a/yarn.lock b/yarn.lock index 6f9a81f67..8dd5bbcd5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2,16 +2,16 @@ # yarn lockfile v1 -"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.3", "@babel/code-frame@^7.10.4", "@babel/code-frame@^7.8.3": +"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.10.3", "@babel/code-frame@^7.8.3": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.14.5.tgz#23b08d740e83f49c5e59945fbf1b43e80bbf4edb" + resolved "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.14.5.tgz" integrity sha512-9pzDqyc6OLDaqe+zbACgFkb6fKMNG6CObKpnYXChRsvYGyEdc7CA2BaqeOM+vOtCS5ndmJicPJhKAwYRI6UfFw== dependencies: "@babel/highlight" "^7.14.5" "@babel/core@^7.1.0", "@babel/core@^7.7.5": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/core/-/core-7.10.3.tgz#73b0e8ddeec1e3fdd7a2de587a60e17c440ec77e" + resolved "https://registry.npmjs.org/@babel/core/-/core-7.10.3.tgz" integrity sha512-5YqWxYE3pyhIi84L84YcwjeEgS+fa7ZjK6IBVGTjDVfm64njkR2lfDhVR5OudLk8x2GK59YoSyVv+L/03k1q9w== dependencies: "@babel/code-frame" "^7.10.3" @@ -33,7 +33,7 @@ "@babel/generator@^7.10.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/generator/-/generator-7.10.3.tgz#32b9a0d963a71d7a54f5f6c15659c3dbc2a523a5" + resolved "https://registry.npmjs.org/@babel/generator/-/generator-7.10.3.tgz" integrity sha512-drt8MUHbEqRzNR0xnF8nMehbY11b1SDkRw03PSNH/3Rb2Z35oxkddVSi3rcaak0YJQ86PCuE7Qx1jSFhbLNBMA== dependencies: "@babel/types" "^7.10.3" @@ -43,7 +43,7 @@ "@babel/helper-function-name@^7.10.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz#79316cd75a9fa25ba9787ff54544307ed444f197" + resolved "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.10.3.tgz" integrity sha512-FvSj2aiOd8zbeqijjgqdMDSyxsGHaMt5Tr0XjQsGKHD3/1FP3wksjnLAWzxw7lvXiej8W1Jt47SKTZ6upQNiRw== dependencies: "@babel/helper-get-function-arity" "^7.10.3" @@ -52,28 +52,28 @@ "@babel/helper-get-function-arity@^7.10.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz#3a28f7b28ccc7719eacd9223b659fdf162e4c45e" + resolved "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.10.3.tgz" integrity sha512-iUD/gFsR+M6uiy69JA6fzM5seno8oE85IYZdbVVEuQaZlEzMO2MXblh+KSPJgsZAUx0EEbWXU0yJaW7C9CdAVg== dependencies: "@babel/types" "^7.10.3" "@babel/helper-member-expression-to-functions@^7.10.1": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz#bc3663ac81ac57c39148fef4c69bf48a77ba8dd6" + resolved "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.10.3.tgz" integrity sha512-q7+37c4EPLSjNb2NmWOjNwj0+BOyYlssuQ58kHEWk1Z78K5i8vTUsteq78HMieRPQSl/NtpQyJfdjt3qZ5V2vw== dependencies: "@babel/types" "^7.10.3" "@babel/helper-module-imports@^7.10.1": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz#766fa1d57608e53e5676f23ae498ec7a95e1b11a" + resolved "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.10.3.tgz" integrity sha512-Jtqw5M9pahLSUWA+76nhK9OG8nwYXzhQzVIGFoNaHnXF/r4l7kz4Fl0UAW7B6mqC5myoJiBP5/YQlXQTMfHI9w== dependencies: "@babel/types" "^7.10.3" "@babel/helper-module-transforms@^7.10.1": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz#24e2f08ee6832c60b157bb0936c86bef7210c622" + resolved "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.10.1.tgz" integrity sha512-RLHRCAzyJe7Q7sF4oy2cB+kRnU4wDZY/H2xJFGof+M+SJEGhZsb+GFj5j1AD8NiSaVBJ+Pf0/WObiXu/zxWpFg== dependencies: "@babel/helper-module-imports" "^7.10.1" @@ -86,19 +86,19 @@ "@babel/helper-optimise-call-expression@^7.10.1": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz#f53c4b6783093195b0f69330439908841660c530" + resolved "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.10.3.tgz" integrity sha512-kT2R3VBH/cnSz+yChKpaKRJQJWxdGoc6SjioRId2wkeV3bK0wLLioFpJROrX0U4xr/NmxSSAWT/9Ih5snwIIzg== dependencies: "@babel/types" "^7.10.3" "@babel/helper-plugin-utils@^7.0.0", "@babel/helper-plugin-utils@^7.10.1", "@babel/helper-plugin-utils@^7.8.0": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz#aac45cccf8bc1873b99a85f34bceef3beb5d3244" + resolved "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.10.3.tgz" integrity sha512-j/+j8NAWUTxOtx4LKHybpSClxHoq6I91DQ/mKgAXn5oNUPIUiGppjPIX3TDtJWPrdfP9Kfl7e4fgVMiQR9VE/g== "@babel/helper-replace-supers@^7.10.1": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz#ec6859d20c5d8087f6a2dc4e014db7228975f13d" + resolved "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.10.1.tgz" integrity sha512-SOwJzEfpuQwInzzQJGjGaiG578UYmyi2Xw668klPWV5n07B73S0a9btjLk/52Mlcxa+5AdIYqws1KyXRfMoB7A== dependencies: "@babel/helper-member-expression-to-functions" "^7.10.1" @@ -108,7 +108,7 @@ "@babel/helper-simple-access@^7.10.1": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz#08fb7e22ace9eb8326f7e3920a1c2052f13d851e" + resolved "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.10.1.tgz" integrity sha512-VSWpWzRzn9VtgMJBIWTZ+GP107kZdQ4YplJlCmIrjoLVSi/0upixezHCDG8kpPVTBJpKfxTH01wDhh+jS2zKbw== dependencies: "@babel/template" "^7.10.1" @@ -116,19 +116,19 @@ "@babel/helper-split-export-declaration@^7.10.1": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz#c6f4be1cbc15e3a868e4c64a17d5d31d754da35f" + resolved "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.10.1.tgz" integrity sha512-UQ1LVBPrYdbchNhLwj6fetj46BcFwfS4NllJo/1aJsT+1dLTEnXJL0qHqtY7gPzF8S2fXBJamf1biAXV3X077g== dependencies: "@babel/types" "^7.10.1" "@babel/helper-validator-identifier@^7.10.3", "@babel/helper-validator-identifier@^7.14.5": version "7.15.7" - resolved "https://registry.yarnpkg.com/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz#220df993bfe904a4a6b02ab4f3385a5ebf6e2389" + resolved "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.15.7.tgz" integrity sha512-K4JvCtQqad9OY2+yTU8w+E82ywk/fe+ELNlt1G8z3bVGlZfn/hOcQQsUhGhW/N+tb3fxK800wLtKOE/aM0m72w== "@babel/helpers@^7.10.1": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/helpers/-/helpers-7.10.1.tgz#a6827b7cb975c9d9cef5fd61d919f60d8844a973" + resolved "https://registry.npmjs.org/@babel/helpers/-/helpers-7.10.1.tgz" integrity sha512-muQNHF+IdU6wGgkaJyhhEmI54MOZBKsFfsXFhboz1ybwJ1Kl7IHlbm2a++4jwrmY5UYsgitt5lfqo1wMFcHmyw== dependencies: "@babel/template" "^7.10.1" @@ -137,7 +137,7 @@ "@babel/highlight@^7.14.5": version "7.14.5" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.14.5.tgz#6861a52f03966405001f6aa534a01a24d99e8cd9" + resolved "https://registry.npmjs.org/@babel/highlight/-/highlight-7.14.5.tgz" integrity sha512-qf9u2WFWVV0MppaL877j2dBtQIDgmidgjGk5VIMw3OadXvYaXn66U1BFlH2t4+t3i+8PhedppRv+i40ABzd+gg== dependencies: "@babel/helper-validator-identifier" "^7.14.5" @@ -146,96 +146,96 @@ "@babel/parser@^7.1.0", "@babel/parser@^7.10.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/parser/-/parser-7.10.3.tgz#7e71d892b0d6e7d04a1af4c3c79d72c1f10f5315" + resolved "https://registry.npmjs.org/@babel/parser/-/parser-7.10.3.tgz" integrity sha512-oJtNJCMFdIMwXGmx+KxuaD7i3b8uS7TTFYW/FNG2BT8m+fmGHoiPYoH0Pe3gya07WuFmM5FCDIr1x0irkD/hyA== "@babel/plugin-syntax-async-generators@^7.8.4": version "7.8.4" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz#a983fb1aeb2ec3f6ed042a210f640e90e786fe0d" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz" integrity sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-bigint@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz#4c9a6f669f5d0cdf1b90a1671e9a146be5300cea" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz" integrity sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-class-properties@^7.8.3": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz#d5bc0645913df5b17ad7eda0fa2308330bde34c5" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.10.1.tgz" integrity sha512-Gf2Yx/iRs1JREDtVZ56OrjjgFHCaldpTnuy9BHla10qyVT3YkIIGEtoDWhyop0ksu1GvNjHIoYRBqm3zoR1jyQ== dependencies: "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-syntax-import-meta@^7.8.3": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.1.tgz#3e59120ed8b3c2ccc5abb1cfc7aaa3ea01cd36b6" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.1.tgz" integrity sha512-ypC4jwfIVF72og0dgvEcFRdOM2V9Qm1tu7RGmdZOlhsccyK0wisXmMObGuWEOd5jQ+K9wcIgSNftCpk2vkjUfQ== dependencies: "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-syntax-json-strings@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz#01ca21b668cd8218c9e640cb6dd88c5412b2c96a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz" integrity sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-logical-assignment-operators@^7.8.3": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.1.tgz#fffee77b4934ce77f3b427649ecdddbec1958550" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.1.tgz" integrity sha512-XyHIFa9kdrgJS91CUH+ccPVTnJShr8nLGc5bG2IhGXv5p1Rd+8BleGE5yzIg2Nc1QZAdHDa0Qp4m6066OL96Iw== dependencies: "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-syntax-nullish-coalescing-operator@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz#167ed70368886081f74b5c36c65a88c03b66d1a9" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz" integrity sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-numeric-separator@^7.8.3": version "7.10.1" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz#25761ee7410bc8cf97327ba741ee94e4a61b7d99" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.1.tgz" integrity sha512-uTd0OsHrpe3tH5gRPTxG8Voh99/WCU78vIm5NMRYPAqC8lR4vajt6KkCAknCHrx24vkPdd/05yfdGSB4EIY2mg== dependencies: "@babel/helper-plugin-utils" "^7.10.1" "@babel/plugin-syntax-object-rest-spread@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz#60e225edcbd98a640332a2e72dd3e66f1af55871" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz" integrity sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-catch-binding@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz#6111a265bcfb020eb9efd0fdfd7d26402b9ed6c1" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz" integrity sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/plugin-syntax-optional-chaining@^7.8.3": version "7.8.3" - resolved "https://registry.yarnpkg.com/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz#4f69c2ab95167e0180cd5336613f8c5788f7d48a" + resolved "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz" integrity sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg== dependencies: "@babel/helper-plugin-utils" "^7.8.0" "@babel/runtime@^7.13.8": version "7.15.4" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.15.4.tgz#fd17d16bfdf878e6dd02d19753a39fa8a8d9c84a" + resolved "https://registry.npmjs.org/@babel/runtime/-/runtime-7.15.4.tgz" integrity sha512-99catp6bHCaxr4sJ/DbTGgHS4+Rs2RVd2g7iOap6SLGPDknRK9ztKNsE/Fg6QhSeh1FGE5f6gHGQmvvn3I3xhw== dependencies: regenerator-runtime "^0.13.4" "@babel/template@^7.10.1", "@babel/template@^7.10.3", "@babel/template@^7.3.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.10.3.tgz#4d13bc8e30bf95b0ce9d175d30306f42a2c9a7b8" + resolved "https://registry.npmjs.org/@babel/template/-/template-7.10.3.tgz" integrity sha512-5BjI4gdtD+9fHZUsaxPHPNpwa+xRkDO7c7JbhYn2afvrkDu5SfAAbi9AIMXw2xEhO/BR35TqiW97IqNvCo/GqA== dependencies: "@babel/code-frame" "^7.10.3" @@ -244,7 +244,7 @@ "@babel/traverse@^7.1.0", "@babel/traverse@^7.10.1", "@babel/traverse@^7.10.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/traverse/-/traverse-7.10.3.tgz#0b01731794aa7b77b214bcd96661f18281155d7e" + resolved "https://registry.npmjs.org/@babel/traverse/-/traverse-7.10.3.tgz" integrity sha512-qO6623eBFhuPm0TmmrUFMT1FulCmsSeJuVGhiLodk2raUDFhhTECLd9E9jC4LBIWziqt4wgF6KuXE4d+Jz9yug== dependencies: "@babel/code-frame" "^7.10.3" @@ -259,7 +259,7 @@ "@babel/types@^7.0.0", "@babel/types@^7.10.1", "@babel/types@^7.10.3", "@babel/types@^7.3.0", "@babel/types@^7.3.3": version "7.10.3" - resolved "https://registry.yarnpkg.com/@babel/types/-/types-7.10.3.tgz#6535e3b79fea86a6b09e012ea8528f935099de8e" + resolved "https://registry.npmjs.org/@babel/types/-/types-7.10.3.tgz" integrity sha512-nZxaJhBXBQ8HVoIcGsf9qWep3Oh3jCENK54V4mRF7qaJabVsAYdbTtmSD8WmAp1R6ytPiu5apMwSXyxB1WlaBA== dependencies: "@babel/helper-validator-identifier" "^7.10.3" @@ -268,104 +268,25 @@ "@bcoe/v8-coverage@^0.2.3": version "0.2.3" - resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" + resolved "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz" integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== "@cnakazawa/watch@^1.0.3": version "1.0.4" - resolved "https://registry.yarnpkg.com/@cnakazawa/watch/-/watch-1.0.4.tgz#f864ae85004d0fcab6f50be9141c4da368d1656a" + resolved "https://registry.npmjs.org/@cnakazawa/watch/-/watch-1.0.4.tgz" integrity sha512-v9kIhKwjeZThiWrLmj0y17CWoyddASLj9O2yvbZkbvw/N3rWOYy9zkV66ursAoVr0mV15bL8g0c4QZUE6cdDoQ== dependencies: exec-sh "^0.3.2" minimist "^1.2.0" -"@evocateur/libnpmaccess@^3.1.2": - version "3.1.2" - resolved "https://registry.yarnpkg.com/@evocateur/libnpmaccess/-/libnpmaccess-3.1.2.tgz#ecf7f6ce6b004e9f942b098d92200be4a4b1c845" - integrity sha512-KSCAHwNWro0CF2ukxufCitT9K5LjL/KuMmNzSu8wuwN2rjyKHD8+cmOsiybK+W5hdnwc5M1SmRlVCaMHQo+3rg== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - aproba "^2.0.0" - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - npm-package-arg "^6.1.0" - -"@evocateur/libnpmpublish@^1.2.2": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@evocateur/libnpmpublish/-/libnpmpublish-1.2.2.tgz#55df09d2dca136afba9c88c759ca272198db9f1a" - integrity sha512-MJrrk9ct1FeY9zRlyeoyMieBjGDG9ihyyD9/Ft6MMrTxql9NyoEx2hw9casTIP4CdqEVu+3nQ2nXxoJ8RCXyFg== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - aproba "^2.0.0" - figgy-pudding "^3.5.1" - get-stream "^4.0.0" - lodash.clonedeep "^4.5.0" - normalize-package-data "^2.4.0" - npm-package-arg "^6.1.0" - semver "^5.5.1" - ssri "^6.0.1" - -"@evocateur/npm-registry-fetch@^4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@evocateur/npm-registry-fetch/-/npm-registry-fetch-4.0.0.tgz#8c4c38766d8d32d3200fcb0a83f064b57365ed66" - integrity sha512-k1WGfKRQyhJpIr+P17O5vLIo2ko1PFLKwoetatdduUSt/aQ4J2sJrJwwatdI5Z3SiYk/mRH9S3JpdmMFd/IK4g== - dependencies: - JSONStream "^1.3.4" - bluebird "^3.5.1" - figgy-pudding "^3.4.1" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - npm-package-arg "^6.1.0" - safe-buffer "^5.1.2" - -"@evocateur/pacote@^9.6.3": - version "9.6.5" - resolved "https://registry.yarnpkg.com/@evocateur/pacote/-/pacote-9.6.5.tgz#33de32ba210b6f17c20ebab4d497efc6755f4ae5" - integrity sha512-EI552lf0aG2nOV8NnZpTxNo2PcXKPmDbF9K8eCBFQdIZwHNGN/mi815fxtmUMa2wTa1yndotICIDt/V0vpEx2w== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - bluebird "^3.5.3" - cacache "^12.0.3" - chownr "^1.1.2" - figgy-pudding "^3.5.1" - get-stream "^4.1.0" - glob "^7.1.4" - infer-owner "^1.0.4" - lru-cache "^5.1.1" - make-fetch-happen "^5.0.0" - minimatch "^3.0.4" - minipass "^2.3.5" - mississippi "^3.0.0" - mkdirp "^0.5.1" - normalize-package-data "^2.5.0" - npm-package-arg "^6.1.0" - npm-packlist "^1.4.4" - npm-pick-manifest "^3.0.0" - osenv "^0.1.5" - promise-inflight "^1.0.1" - promise-retry "^1.1.1" - protoduck "^5.0.1" - rimraf "^2.6.3" - safe-buffer "^5.2.0" - semver "^5.7.0" - ssri "^6.0.1" - tar "^4.4.10" - unique-filename "^1.1.1" - which "^1.3.1" - "@gar/promisify@^1.0.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.2.tgz#30aa825f11d438671d585bd44e7fd564535fc210" + resolved "https://registry.npmjs.org/@gar/promisify/-/promisify-1.1.2.tgz" integrity sha512-82cpyJyKRoQoRi+14ibCeGPu0CwypgtBAdBhq1WfvagpCZNKqwXbKwXllYSMG91DhmG4jt9gN8eP6lGOtozuaw== -"@hutson/parse-repository-url@^3.0.0": - version "3.0.2" - resolved "https://registry.yarnpkg.com/@hutson/parse-repository-url/-/parse-repository-url-3.0.2.tgz#98c23c950a3d9b6c8f0daed06da6c3af06981340" - integrity sha512-H9XAx3hc0BQHY6l+IFSWHDySypcXsvsuLhgYLUGywmJ5pswRVQJUHpOsobnLYp2ZUaUlKiKDrgWWhosOwAEM8Q== - "@istanbuljs/load-nyc-config@^1.0.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz#fd3db1d59ecf7cf121e80650bb86712f9b55eced" + resolved "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz" integrity sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ== dependencies: camelcase "^5.3.1" @@ -376,12 +297,12 @@ "@istanbuljs/schema@^0.1.2": version "0.1.2" - resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" + resolved "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz" integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== "@jest/console@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/console/-/console-26.1.0.tgz#f67c89e4f4d04dbcf7b052aed5ab9c74f915b954" + resolved "https://registry.npmjs.org/@jest/console/-/console-26.1.0.tgz" integrity sha512-+0lpTHMd/8pJp+Nd4lyip+/Iyf2dZJvcCqrlkeZQoQid+JlThA4M9vxHtheyrQ99jJTMQam+es4BcvZ5W5cC3A== dependencies: "@jest/types" "^26.1.0" @@ -392,7 +313,7 @@ "@jest/core@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.1.0.tgz#4580555b522de412a7998b3938c851e4f9da1c18" + resolved "https://registry.npmjs.org/@jest/core/-/core-26.1.0.tgz" integrity sha512-zyizYmDJOOVke4OO/De//aiv8b07OwZzL2cfsvWF3q9YssfpcKfcnZAwDY8f+A76xXSMMYe8i/f/LPocLlByfw== dependencies: "@jest/console" "^26.1.0" @@ -425,7 +346,7 @@ "@jest/environment@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/environment/-/environment-26.1.0.tgz#378853bcdd1c2443b4555ab908cfbabb851e96da" + resolved "https://registry.npmjs.org/@jest/environment/-/environment-26.1.0.tgz" integrity sha512-86+DNcGongbX7ai/KE/S3/NcUVZfrwvFzOOWX/W+OOTvTds7j07LtC+MgGydH5c8Ri3uIrvdmVgd1xFD5zt/xA== dependencies: "@jest/fake-timers" "^26.1.0" @@ -434,7 +355,7 @@ "@jest/fake-timers@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/fake-timers/-/fake-timers-26.1.0.tgz#9a76b7a94c351cdbc0ad53e5a748789f819a65fe" + resolved "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-26.1.0.tgz" integrity sha512-Y5F3kBVWxhau3TJ825iuWy++BAuQzK/xEa+wD9vDH3RytW9f2DbMVodfUQC54rZDX3POqdxCgcKdgcOL0rYUpA== dependencies: "@jest/types" "^26.1.0" @@ -445,7 +366,7 @@ "@jest/globals@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.1.0.tgz#6cc5d7cbb79b76b120f2403d7d755693cf063ab1" + resolved "https://registry.npmjs.org/@jest/globals/-/globals-26.1.0.tgz" integrity sha512-MKiHPNaT+ZoG85oMaYUmGHEqu98y3WO2yeIDJrs2sJqHhYOy3Z6F7F/luzFomRQ8SQ1wEkmahFAz2291Iv8EAw== dependencies: "@jest/environment" "^26.1.0" @@ -454,7 +375,7 @@ "@jest/reporters@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.1.0.tgz#08952e90c90282e14ff49e927bdf1873617dae78" + resolved "https://registry.npmjs.org/@jest/reporters/-/reporters-26.1.0.tgz" integrity sha512-SVAysur9FOIojJbF4wLP0TybmqwDkdnFxHSPzHMMIYyBtldCW9gG+Q5xWjpMFyErDiwlRuPyMSJSU64A67Pazg== dependencies: "@bcoe/v8-coverage" "^0.2.3" @@ -486,7 +407,7 @@ "@jest/source-map@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/source-map/-/source-map-26.1.0.tgz#a6a020d00e7d9478f4b690167c5e8b77e63adb26" + resolved "https://registry.npmjs.org/@jest/source-map/-/source-map-26.1.0.tgz" integrity sha512-XYRPYx4eEVX15cMT9mstnO7hkHP3krNtKfxUYd8L7gbtia8JvZZ6bMzSwa6IQJENbudTwKMw5R1BePRD+bkEmA== dependencies: callsites "^3.0.0" @@ -495,7 +416,7 @@ "@jest/test-result@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-result/-/test-result-26.1.0.tgz#a93fa15b21ad3c7ceb21c2b4c35be2e407d8e971" + resolved "https://registry.npmjs.org/@jest/test-result/-/test-result-26.1.0.tgz" integrity sha512-Xz44mhXph93EYMA8aYDz+75mFbarTV/d/x0yMdI3tfSRs/vh4CqSxgzVmCps1fPkHDCtn0tU8IH9iCKgGeGpfw== dependencies: "@jest/console" "^26.1.0" @@ -505,7 +426,7 @@ "@jest/test-sequencer@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.1.0.tgz#41a6fc8b850c3f33f48288ea9ea517c047e7f14e" + resolved "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-26.1.0.tgz" integrity sha512-Z/hcK+rTq56E6sBwMoQhSRDVjqrGtj1y14e2bIgcowARaIE1SgOanwx6gvY4Q9gTKMoZQXbXvptji+q5GYxa6Q== dependencies: "@jest/test-result" "^26.1.0" @@ -516,7 +437,7 @@ "@jest/transform@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/transform/-/transform-26.1.0.tgz#697f48898c2a2787c9b4cb71d09d7e617464e509" + resolved "https://registry.npmjs.org/@jest/transform/-/transform-26.1.0.tgz" integrity sha512-ICPm6sUXmZJieq45ix28k0s+d/z2E8CHDsq+WwtWI6kW8m7I8kPqarSEcUN86entHQ570ZBRci5OWaKL0wlAWw== dependencies: "@babel/core" "^7.1.0" @@ -537,7 +458,7 @@ "@jest/types@^25.5.0": version "25.5.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-25.5.0.tgz#4d6a4793f7b9599fc3680877b856a97dbccf2a9d" + resolved "https://registry.npmjs.org/@jest/types/-/types-25.5.0.tgz" integrity sha512-OXD0RgQ86Tu3MazKo8bnrkDRaDXXMGUqd+kTtLtK1Zb7CRzQcaSRPPPV37SvYTdevXEBVxe0HXylEjs8ibkmCw== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" @@ -547,7 +468,7 @@ "@jest/types@^26.1.0": version "26.1.0" - resolved "https://registry.yarnpkg.com/@jest/types/-/types-26.1.0.tgz#f8afaaaeeb23b5cad49dd1f7779689941dcb6057" + resolved "https://registry.npmjs.org/@jest/types/-/types-26.1.0.tgz" integrity sha512-GXigDDsp6ZlNMhXQDeuy/iYCDsRIHJabWtDzvnn36+aqFfG14JmFV0e/iXxY4SP9vbXSiPNOWdehU5MeqrYHBQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.0" @@ -555,1373 +476,9 @@ "@types/yargs" "^15.0.0" chalk "^4.0.0" -"@lerna/add@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-3.21.0.tgz#27007bde71cc7b0a2969ab3c2f0ae41578b4577b" - integrity sha512-vhUXXF6SpufBE1EkNEXwz1VLW03f177G9uMOFMQkp6OJ30/PWg4Ekifuz9/3YfgB2/GH8Tu4Lk3O51P2Hskg/A== - dependencies: - "@evocateur/pacote" "^9.6.3" - "@lerna/bootstrap" "3.21.0" - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/validation-error" "3.13.0" - dedent "^0.7.0" - npm-package-arg "^6.1.0" - p-map "^2.1.0" - semver "^6.2.0" - -"@lerna/add@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/add/-/add-4.0.0.tgz#c36f57d132502a57b9e7058d1548b7a565ef183f" - integrity sha512-cpmAH1iS3k8JBxNvnMqrGTTjbY/ZAiKa1ChJzFevMYY3eeqbvhsBKnBcxjRXtdrJ6bd3dCQM+ZtK+0i682Fhng== - dependencies: - "@lerna/bootstrap" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - npm-package-arg "^8.1.0" - p-map "^4.0.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/bootstrap@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-3.21.0.tgz#bcd1b651be5b0970b20d8fae04c864548123aed6" - integrity sha512-mtNHlXpmvJn6JTu0KcuTTPl2jLsDNud0QacV/h++qsaKbhAaJr/FElNZ5s7MwZFUM3XaDmvWzHKaszeBMHIbBw== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/has-npm-version" "3.16.5" - "@lerna/npm-install" "3.16.5" - "@lerna/package-graph" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/rimraf-dir" "3.16.5" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/symlink-binary" "3.17.0" - "@lerna/symlink-dependencies" "3.17.0" - "@lerna/validation-error" "3.13.0" - dedent "^0.7.0" - get-port "^4.2.0" - multimatch "^3.0.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - p-finally "^1.0.0" - p-map "^2.1.0" - p-map-series "^1.0.0" - p-waterfall "^1.0.0" - read-package-tree "^5.1.6" - semver "^6.2.0" - -"@lerna/bootstrap@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/bootstrap/-/bootstrap-4.0.0.tgz#5f5c5e2c6cfc8fcec50cb2fbe569a8c607101891" - integrity sha512-RkS7UbeM2vu+kJnHzxNRCLvoOP9yGNgkzRdy4UV2hNalD7EP41bLvRVOwRYQ7fhc2QcbhnKNdOBihYRL0LcKtw== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/has-npm-version" "4.0.0" - "@lerna/npm-install" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - get-port "^5.1.1" - multimatch "^5.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - read-package-tree "^5.3.1" - semver "^7.3.4" - -"@lerna/changed@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-3.21.0.tgz#108e15f679bfe077af500f58248c634f1044ea0b" - integrity sha512-hzqoyf8MSHVjZp0gfJ7G8jaz+++mgXYiNs9iViQGA8JlN/dnWLI5sWDptEH3/B30Izo+fdVz0S0s7ydVE3pWIw== - dependencies: - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/listable" "3.18.5" - "@lerna/output" "3.13.0" - -"@lerna/changed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/changed/-/changed-4.0.0.tgz#b9fc76cea39b9292a6cd263f03eb57af85c9270b" - integrity sha512-cD+KuPRp6qiPOD+BO6S6SN5cARspIaWSOqGBpGnYzLb4uWT8Vk4JzKyYtc8ym1DIwyoFXHosXt8+GDAgR8QrgQ== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/check-working-tree@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-3.16.5.tgz#b4f8ae61bb4523561dfb9f8f8d874dd46bb44baa" - integrity sha512-xWjVBcuhvB8+UmCSb5tKVLB5OuzSpw96WEhS2uz6hkWVa/Euh1A0/HJwn2cemyK47wUrCQXtczBUiqnq9yX5VQ== - dependencies: - "@lerna/collect-uncommitted" "3.16.5" - "@lerna/describe-ref" "3.16.5" - "@lerna/validation-error" "3.13.0" - -"@lerna/check-working-tree@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/check-working-tree/-/check-working-tree-4.0.0.tgz#257e36a602c00142e76082a19358e3e1ae8dbd58" - integrity sha512-/++bxM43jYJCshBiKP5cRlCTwSJdRSxVmcDAXM+1oUewlZJVSVlnks5eO0uLxokVFvLhHlC5kHMc7gbVFPHv6Q== - dependencies: - "@lerna/collect-uncommitted" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/validation-error" "4.0.0" - -"@lerna/child-process@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-3.16.5.tgz#38fa3c18064aa4ac0754ad80114776a7b36a69b2" - integrity sha512-vdcI7mzei9ERRV4oO8Y1LHBZ3A5+ampRKg1wq5nutLsUA4mEBN6H7JqjWOMY9xZemv6+kATm2ofjJ3lW5TszQg== - dependencies: - chalk "^2.3.1" - execa "^1.0.0" - strong-log-transformer "^2.0.0" - -"@lerna/child-process@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-4.0.0.tgz#341b96a57dffbd9705646d316e231df6fa4df6e1" - integrity sha512-XtCnmCT9eyVsUUHx6y/CTBYdV9g2Cr/VxyseTWBgfIur92/YKClfEtJTbOh94jRT62hlKLqSvux/UhxXVh613Q== - dependencies: - chalk "^4.1.0" - execa "^5.0.0" - strong-log-transformer "^2.1.0" - -"@lerna/clean@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-3.21.0.tgz#c0b46b5300cc3dae2cda3bec14b803082da3856d" - integrity sha512-b/L9l+MDgE/7oGbrav6rG8RTQvRiZLO1zTcG17zgJAAuhlsPxJExMlh2DFwJEVi2les70vMhHfST3Ue1IMMjpg== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/rimraf-dir" "3.16.5" - p-map "^2.1.0" - p-map-series "^1.0.0" - p-waterfall "^1.0.0" - -"@lerna/clean@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/clean/-/clean-4.0.0.tgz#8f778b6f2617aa2a936a6b5e085ae62498e57dc5" - integrity sha512-uugG2iN9k45ITx2jtd8nEOoAtca8hNlDCUM0N3lFgU/b1mEQYAPRkqr1qs4FLRl/Y50ZJ41wUz1eazS+d/0osA== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/rimraf-dir" "4.0.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - p-waterfall "^2.1.1" - -"@lerna/cli@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-3.18.5.tgz#c90c461542fcd35b6d5b015a290fb0dbfb41d242" - integrity sha512-erkbxkj9jfc89vVs/jBLY/fM0I80oLmJkFUV3Q3wk9J3miYhP14zgVEBsPZY68IZlEjT6T3Xlq2xO1AVaatHsA== - dependencies: - "@lerna/global-options" "3.13.0" - dedent "^0.7.0" - npmlog "^4.1.2" - yargs "^14.2.2" - -"@lerna/cli@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/cli/-/cli-4.0.0.tgz#8eabd334558836c1664df23f19acb95e98b5bbf3" - integrity sha512-Neaw3GzFrwZiRZv2g7g6NwFjs3er1vhraIniEs0jjVLPMNC4eata0na3GfE5yibkM/9d3gZdmihhZdZ3EBdvYA== - dependencies: - "@lerna/global-options" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - yargs "^16.2.0" - -"@lerna/collect-uncommitted@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-3.16.5.tgz#a494d61aac31cdc7aec4bbe52c96550274132e63" - integrity sha512-ZgqnGwpDZiWyzIQVZtQaj9tRizsL4dUOhuOStWgTAw1EMe47cvAY2kL709DzxFhjr6JpJSjXV5rZEAeU3VE0Hg== - dependencies: - "@lerna/child-process" "3.16.5" - chalk "^2.3.1" - figgy-pudding "^3.5.1" - npmlog "^4.1.2" - -"@lerna/collect-uncommitted@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-uncommitted/-/collect-uncommitted-4.0.0.tgz#855cd64612969371cfc2453b90593053ff1ba779" - integrity sha512-ufSTfHZzbx69YNj7KXQ3o66V4RC76ffOjwLX0q/ab//61bObJ41n03SiQEhSlmpP+gmFbTJ3/7pTe04AHX9m/g== - dependencies: - "@lerna/child-process" "4.0.0" - chalk "^4.1.0" - npmlog "^4.1.2" - -"@lerna/collect-updates@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-3.20.0.tgz#62f9d76ba21a25b7d9fbf31c02de88744a564bd1" - integrity sha512-qBTVT5g4fupVhBFuY4nI/3FSJtQVcDh7/gEPOpRxoXB/yCSnT38MFHXWl+y4einLciCjt/+0x6/4AG80fjay2Q== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/describe-ref" "3.16.5" - minimatch "^3.0.4" - npmlog "^4.1.2" - slash "^2.0.0" - -"@lerna/collect-updates@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/collect-updates/-/collect-updates-4.0.0.tgz#8e208b1bafd98a372ff1177f7a5e288f6bea8041" - integrity sha512-bnNGpaj4zuxsEkyaCZLka9s7nMs58uZoxrRIPJ+nrmrZYp1V5rrd+7/NYTuunOhY2ug1sTBvTAxj3NZQ+JKnOw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/describe-ref" "4.0.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - slash "^3.0.0" - -"@lerna/command@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-3.21.0.tgz#9a2383759dc7b700dacfa8a22b2f3a6e190121f7" - integrity sha512-T2bu6R8R3KkH5YoCKdutKv123iUgUbW8efVjdGCDnCMthAQzoentOJfDeodBwn0P2OqCl3ohsiNVtSn9h78fyQ== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/package-graph" "3.18.5" - "@lerna/project" "3.21.0" - "@lerna/validation-error" "3.13.0" - "@lerna/write-log-file" "3.13.0" - clone-deep "^4.0.1" - dedent "^0.7.0" - execa "^1.0.0" - is-ci "^2.0.0" - npmlog "^4.1.2" - -"@lerna/command@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/command/-/command-4.0.0.tgz#991c7971df8f5bf6ae6e42c808869a55361c1b98" - integrity sha512-LM9g3rt5FsPNFqIHUeRwWXLNHJ5NKzOwmVKZ8anSp4e1SPrv2HNc1V02/9QyDDZK/w+5POXH5lxZUI1CHaOK/A== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/project" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/write-log-file" "4.0.0" - clone-deep "^4.0.1" - dedent "^0.7.0" - execa "^5.0.0" - is-ci "^2.0.0" - npmlog "^4.1.2" - -"@lerna/conventional-commits@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-3.22.0.tgz#2798f4881ee2ef457bdae027ab7d0bf0af6f1e09" - integrity sha512-z4ZZk1e8Mhz7+IS8NxHr64wyklHctCJyWpJKEZZPJiLFJ8yKto/x38O80R10pIzC0rr8Sy/OsjSH4bl0TbbgqA== - dependencies: - "@lerna/validation-error" "3.13.0" - conventional-changelog-angular "^5.0.3" - conventional-changelog-core "^3.1.6" - conventional-recommended-bump "^5.0.0" - fs-extra "^8.1.0" - get-stream "^4.0.0" - lodash.template "^4.5.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - pify "^4.0.1" - semver "^6.2.0" - -"@lerna/conventional-commits@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/conventional-commits/-/conventional-commits-4.0.0.tgz#660fb2c7b718cb942ead70110df61f18c6f99750" - integrity sha512-CSUQRjJHFrH8eBn7+wegZLV3OrNc0Y1FehYfYGhjLE2SIfpCL4bmfu/ViYuHh9YjwHaA+4SX6d3hR+xkeseKmw== - dependencies: - "@lerna/validation-error" "4.0.0" - conventional-changelog-angular "^5.0.12" - conventional-changelog-core "^4.2.2" - conventional-recommended-bump "^6.1.0" - fs-extra "^9.1.0" - get-stream "^6.0.0" - lodash.template "^4.5.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - semver "^7.3.4" - -"@lerna/create-symlink@3.16.2": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-3.16.2.tgz#412cb8e59a72f5a7d9463e4e4721ad2070149967" - integrity sha512-pzXIJp6av15P325sgiIRpsPXLFmkisLhMBCy4764d+7yjf2bzrJ4gkWVMhsv4AdF0NN3OyZ5jjzzTtLNqfR+Jw== - dependencies: - "@zkochan/cmd-shim" "^3.1.0" - fs-extra "^8.1.0" - npmlog "^4.1.2" - -"@lerna/create-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create-symlink/-/create-symlink-4.0.0.tgz#8c5317ce5ae89f67825443bd7651bf4121786228" - integrity sha512-I0phtKJJdafUiDwm7BBlEUOtogmu8+taxq6PtIrxZbllV9hWg59qkpuIsiFp+no7nfRVuaasNYHwNUhDAVQBig== - dependencies: - cmd-shim "^4.1.0" - fs-extra "^9.1.0" - npmlog "^4.1.2" - -"@lerna/create@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-3.22.0.tgz#d6bbd037c3dc5b425fe5f6d1b817057c278f7619" - integrity sha512-MdiQQzCcB4E9fBF1TyMOaAEz9lUjIHp1Ju9H7f3lXze5JK6Fl5NYkouAvsLgY6YSIhXMY8AHW2zzXeBDY4yWkw== - dependencies: - "@evocateur/pacote" "^9.6.3" - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/validation-error" "3.13.0" - camelcase "^5.0.0" - dedent "^0.7.0" - fs-extra "^8.1.0" - globby "^9.2.0" - init-package-json "^1.10.3" - npm-package-arg "^6.1.0" - p-reduce "^1.0.0" - pify "^4.0.1" - semver "^6.2.0" - slash "^2.0.0" - validate-npm-package-license "^3.0.3" - validate-npm-package-name "^3.0.0" - whatwg-url "^7.0.0" - -"@lerna/create@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/create/-/create-4.0.0.tgz#b6947e9b5dfb6530321952998948c3e63d64d730" - integrity sha512-mVOB1niKByEUfxlbKTM1UNECWAjwUdiioIbRQZEeEabtjCL69r9rscIsjlGyhGWCfsdAG5wfq4t47nlDXdLLag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - globby "^11.0.2" - init-package-json "^2.0.2" - npm-package-arg "^8.1.0" - p-reduce "^2.1.0" - pacote "^11.2.6" - pify "^5.0.0" - semver "^7.3.4" - slash "^3.0.0" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - whatwg-url "^8.4.0" - yargs-parser "20.2.4" - -"@lerna/describe-ref@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-3.16.5.tgz#a338c25aaed837d3dc70b8a72c447c5c66346ac0" - integrity sha512-c01+4gUF0saOOtDBzbLMFOTJDHTKbDFNErEY6q6i9QaXuzy9LNN62z+Hw4acAAZuJQhrVWncVathcmkkjvSVGw== - dependencies: - "@lerna/child-process" "3.16.5" - npmlog "^4.1.2" - -"@lerna/describe-ref@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/describe-ref/-/describe-ref-4.0.0.tgz#53c53b4ea65fdceffa072a62bfebe6772c45d9ec" - integrity sha512-eTU5+xC4C5Gcgz+Ey4Qiw9nV2B4JJbMulsYJMW8QjGcGh8zudib7Sduj6urgZXUYNyhYpRs+teci9M2J8u+UvQ== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - -"@lerna/diff@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-3.21.0.tgz#e6df0d8b9916167ff5a49fcb02ac06424280a68d" - integrity sha512-5viTR33QV3S7O+bjruo1SaR40m7F2aUHJaDAC7fL9Ca6xji+aw1KFkpCtVlISS0G8vikUREGMJh+c/VMSc8Usw== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/validation-error" "3.13.0" - npmlog "^4.1.2" - -"@lerna/diff@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/diff/-/diff-4.0.0.tgz#6d3071817aaa4205a07bf77cfc6e932796d48b92" - integrity sha512-jYPKprQVg41+MUMxx6cwtqsNm0Yxx9GDEwdiPLwcUTFx+/qKCEwifKNJ1oGIPBxyEHX2PFCOjkK39lHoj2qiag== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/validation-error" "4.0.0" - npmlog "^4.1.2" - -"@lerna/exec@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-3.21.0.tgz#17f07533893cb918a17b41bcc566dc437016db26" - integrity sha512-iLvDBrIE6rpdd4GIKTY9mkXyhwsJ2RvQdB9ZU+/NhR3okXfqKc6py/24tV111jqpXTtZUW6HNydT4dMao2hi1Q== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/profiler" "3.20.0" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - p-map "^2.1.0" - -"@lerna/exec@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/exec/-/exec-4.0.0.tgz#eb6cb95cb92d42590e9e2d628fcaf4719d4a8be6" - integrity sha512-VGXtL/b/JfY84NB98VWZpIExfhLOzy0ozm/0XaS4a2SmkAJc5CeUfrhvHxxkxiTBLkU+iVQUyYEoAT0ulQ8PCw== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/filter-options@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-3.20.0.tgz#0f0f5d5a4783856eece4204708cc902cbc8af59b" - integrity sha512-bmcHtvxn7SIl/R9gpiNMVG7yjx7WyT0HSGw34YVZ9B+3xF/83N3r5Rgtjh4hheLZ+Q91Or0Jyu5O3Nr+AwZe2g== - dependencies: - "@lerna/collect-updates" "3.20.0" - "@lerna/filter-packages" "3.18.0" - dedent "^0.7.0" - figgy-pudding "^3.5.1" - npmlog "^4.1.2" - -"@lerna/filter-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-options/-/filter-options-4.0.0.tgz#ac94cc515d7fa3b47e2f7d74deddeabb1de5e9e6" - integrity sha512-vV2ANOeZhOqM0rzXnYcFFCJ/kBWy/3OA58irXih9AMTAlQLymWAK0akWybl++sUJ4HB9Hx12TOqaXbYS2NM5uw== - dependencies: - "@lerna/collect-updates" "4.0.0" - "@lerna/filter-packages" "4.0.0" - dedent "^0.7.0" - npmlog "^4.1.2" - -"@lerna/filter-packages@3.18.0": - version "3.18.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-3.18.0.tgz#6a7a376d285208db03a82958cfb8172e179b4e70" - integrity sha512-6/0pMM04bCHNATIOkouuYmPg6KH3VkPCIgTfQmdkPJTullERyEQfNUKikrefjxo1vHOoCACDpy65JYyKiAbdwQ== - dependencies: - "@lerna/validation-error" "3.13.0" - multimatch "^3.0.0" - npmlog "^4.1.2" - -"@lerna/filter-packages@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/filter-packages/-/filter-packages-4.0.0.tgz#b1f70d70e1de9cdd36a4e50caa0ac501f8d012f2" - integrity sha512-+4AJIkK7iIiOaqCiVTYJxh/I9qikk4XjNQLhE3kixaqgMuHl1NQ99qXRR0OZqAWB9mh8Z1HA9bM5K1HZLBTOqA== - dependencies: - "@lerna/validation-error" "4.0.0" - multimatch "^5.0.0" - npmlog "^4.1.2" - -"@lerna/get-npm-exec-opts@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-3.13.0.tgz#d1b552cb0088199fc3e7e126f914e39a08df9ea5" - integrity sha512-Y0xWL0rg3boVyJk6An/vurKzubyJKtrxYv2sj4bB8Mc5zZ3tqtv0ccbOkmkXKqbzvNNF7VeUt1OJ3DRgtC/QZw== - dependencies: - npmlog "^4.1.2" - -"@lerna/get-npm-exec-opts@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-npm-exec-opts/-/get-npm-exec-opts-4.0.0.tgz#dc955be94a4ae75c374ef9bce91320887d34608f" - integrity sha512-yvmkerU31CTWS2c7DvmAWmZVeclPBqI7gPVr5VATUKNWJ/zmVcU4PqbYoLu92I9Qc4gY1TuUplMNdNuZTSL7IQ== - dependencies: - npmlog "^4.1.2" - -"@lerna/get-packed@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-3.16.0.tgz#1b316b706dcee86c7baa55e50b087959447852ff" - integrity sha512-AjsFiaJzo1GCPnJUJZiTW6J1EihrPkc2y3nMu6m3uWFxoleklsSCyImumzVZJssxMi3CPpztj8LmADLedl9kXw== - dependencies: - fs-extra "^8.1.0" - ssri "^6.0.1" - tar "^4.4.8" - -"@lerna/get-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/get-packed/-/get-packed-4.0.0.tgz#0989d61624ac1f97e393bdad2137c49cd7a37823" - integrity sha512-rfWONRsEIGyPJTxFzC8ECb3ZbsDXJbfqWYyeeQQDrJRPnEJErlltRLPLgC2QWbxFgFPsoDLeQmFHJnf0iDfd8w== - dependencies: - fs-extra "^9.1.0" - ssri "^8.0.1" - tar "^6.1.0" - -"@lerna/github-client@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-3.22.0.tgz#5d816aa4f76747ed736ae64ff962b8f15c354d95" - integrity sha512-O/GwPW+Gzr3Eb5bk+nTzTJ3uv+jh5jGho9BOqKlajXaOkMYGBELEAqV5+uARNGWZFvYAiF4PgqHb6aCUu7XdXg== - dependencies: - "@lerna/child-process" "3.16.5" - "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^16.28.4" - git-url-parse "^11.1.2" - npmlog "^4.1.2" - -"@lerna/github-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/github-client/-/github-client-4.0.0.tgz#2ced67721363ef70f8e12ffafce4410918f4a8a4" - integrity sha512-2jhsldZtTKXYUBnOm23Lb0Fx8G4qfSXF9y7UpyUgWUj+YZYd+cFxSuorwQIgk5P4XXrtVhsUesIsli+BYSThiw== - dependencies: - "@lerna/child-process" "4.0.0" - "@octokit/plugin-enterprise-rest" "^6.0.1" - "@octokit/rest" "^18.1.0" - git-url-parse "^11.4.4" - npmlog "^4.1.2" - -"@lerna/gitlab-client@3.15.0": - version "3.15.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-3.15.0.tgz#91f4ec8c697b5ac57f7f25bd50fe659d24aa96a6" - integrity sha512-OsBvRSejHXUBMgwWQqNoioB8sgzL/Pf1pOUhHKtkiMl6aAWjklaaq5HPMvTIsZPfS6DJ9L5OK2GGZuooP/5c8Q== - dependencies: - node-fetch "^2.5.0" - npmlog "^4.1.2" - whatwg-url "^7.0.0" - -"@lerna/gitlab-client@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/gitlab-client/-/gitlab-client-4.0.0.tgz#00dad73379c7b38951d4b4ded043504c14e2b67d" - integrity sha512-OMUpGSkeDWFf7BxGHlkbb35T7YHqVFCwBPSIR6wRsszY8PAzCYahtH3IaJzEJyUg6vmZsNl0FSr3pdA2skhxqA== - dependencies: - node-fetch "^2.6.1" - npmlog "^4.1.2" - whatwg-url "^8.4.0" - -"@lerna/global-options@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-3.13.0.tgz#217662290db06ad9cf2c49d8e3100ee28eaebae1" - integrity sha512-SlZvh1gVRRzYLVluz9fryY1nJpZ0FHDGB66U9tFfvnnxmueckRQxLopn3tXj3NU1kc3QANT2I5BsQkOqZ4TEFQ== - -"@lerna/global-options@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/global-options/-/global-options-4.0.0.tgz#c7d8b0de6a01d8a845e2621ea89e7f60f18c6a5f" - integrity sha512-TRMR8afAHxuYBHK7F++Ogop2a82xQjoGna1dvPOY6ltj/pEx59pdgcJfYcynYqMkFIk8bhLJJN9/ndIfX29FTQ== - -"@lerna/has-npm-version@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-3.16.5.tgz#ab83956f211d8923ea6afe9b979b38cc73b15326" - integrity sha512-WL7LycR9bkftyqbYop5rEGJ9sRFIV55tSGmbN1HLrF9idwOCD7CLrT64t235t3t4O5gehDnwKI5h2U3oxTrF8Q== - dependencies: - "@lerna/child-process" "3.16.5" - semver "^6.2.0" - -"@lerna/has-npm-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/has-npm-version/-/has-npm-version-4.0.0.tgz#d3fc3292c545eb28bd493b36e6237cf0279f631c" - integrity sha512-LQ3U6XFH8ZmLCsvsgq1zNDqka0Xzjq5ibVN+igAI5ccRWNaUsE/OcmsyMr50xAtNQMYMzmpw5GVLAivT2/YzCg== - dependencies: - "@lerna/child-process" "4.0.0" - semver "^7.3.4" - -"@lerna/import@3.22.0": - version "3.22.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-3.22.0.tgz#1a5f0394f38e23c4f642a123e5e1517e70d068d2" - integrity sha512-uWOlexasM5XR6tXi4YehODtH9Y3OZrFht3mGUFFT3OIl2s+V85xIGFfqFGMTipMPAGb2oF1UBLL48kR43hRsOg== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/validation-error" "3.13.0" - dedent "^0.7.0" - fs-extra "^8.1.0" - p-map-series "^1.0.0" - -"@lerna/import@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/import/-/import-4.0.0.tgz#bde656c4a451fa87ae41733ff8a8da60547c5465" - integrity sha512-FaIhd+4aiBousKNqC7TX1Uhe97eNKf5/SC7c5WZANVWtC7aBWdmswwDt3usrzCNpj6/Wwr9EtEbYROzxKH8ffg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/validation-error" "4.0.0" - dedent "^0.7.0" - fs-extra "^9.1.0" - p-map-series "^2.1.0" - -"@lerna/info@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-3.21.0.tgz#76696b676fdb0f35d48c83c63c1e32bb5e37814f" - integrity sha512-0XDqGYVBgWxUquFaIptW2bYSIu6jOs1BtkvRTWDDhw4zyEdp6q4eaMvqdSap1CG+7wM5jeLCi6z94wS0AuiuwA== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/output" "3.13.0" - envinfo "^7.3.1" - -"@lerna/info@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/info/-/info-4.0.0.tgz#b9fb0e479d60efe1623603958a831a88b1d7f1fc" - integrity sha512-8Uboa12kaCSZEn4XRfPz5KU9XXoexSPS4oeYGj76s2UQb1O1GdnEyfjyNWoUl1KlJ2i/8nxUskpXIftoFYH0/Q== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/output" "4.0.0" - envinfo "^7.7.4" - -"@lerna/init@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-3.21.0.tgz#1e810934dc8bf4e5386c031041881d3b4096aa5c" - integrity sha512-6CM0z+EFUkFfurwdJCR+LQQF6MqHbYDCBPyhu/d086LRf58GtYZYj49J8mKG9ktayp/TOIxL/pKKjgLD8QBPOg== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/command" "3.21.0" - fs-extra "^8.1.0" - p-map "^2.1.0" - write-json-file "^3.2.0" - -"@lerna/init@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/init/-/init-4.0.0.tgz#dadff67e6dfb981e8ccbe0e6a310e837962f6c7a" - integrity sha512-wY6kygop0BCXupzWj5eLvTUqdR7vIAm0OgyV9WHpMYQGfs1V22jhztt8mtjCloD/O0nEe4tJhdG62XU5aYmPNQ== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/command" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/link@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-3.21.0.tgz#8be68ff0ccee104b174b5bbd606302c2f06e9d9b" - integrity sha512-tGu9GxrX7Ivs+Wl3w1+jrLi1nQ36kNI32dcOssij6bg0oZ2M2MDEFI9UF2gmoypTaN9uO5TSsjCFS7aR79HbdQ== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/package-graph" "3.18.5" - "@lerna/symlink-dependencies" "3.17.0" - p-map "^2.1.0" - slash "^2.0.0" - -"@lerna/link@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/link/-/link-4.0.0.tgz#c3a38aabd44279d714e90f2451e31b63f0fb65ba" - integrity sha512-KlvPi7XTAcVOByfaLlOeYOfkkDcd+bejpHMCd1KcArcFTwijOwXOVi24DYomIeHvy6HsX/IUquJ4PPUJIeB4+w== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/package-graph" "4.0.0" - "@lerna/symlink-dependencies" "4.0.0" - p-map "^4.0.0" - slash "^3.0.0" - -"@lerna/list@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-3.21.0.tgz#42f76fafa56dea13b691ec8cab13832691d61da2" - integrity sha512-KehRjE83B1VaAbRRkRy6jLX1Cin8ltsrQ7FHf2bhwhRHK0S54YuA6LOoBnY/NtA8bHDX/Z+G5sMY78X30NS9tg== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/listable" "3.18.5" - "@lerna/output" "3.13.0" - -"@lerna/list@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/list/-/list-4.0.0.tgz#24b4e6995bd73f81c556793fe502b847efd9d1d7" - integrity sha512-L2B5m3P+U4Bif5PultR4TI+KtW+SArwq1i75QZ78mRYxPc0U/piau1DbLOmwrdqr99wzM49t0Dlvl6twd7GHFg== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/listable" "4.0.0" - "@lerna/output" "4.0.0" - -"@lerna/listable@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-3.18.5.tgz#e82798405b5ed8fc51843c8ef1e7a0e497388a1a" - integrity sha512-Sdr3pVyaEv5A7ZkGGYR7zN+tTl2iDcinryBPvtuv20VJrXBE8wYcOks1edBTcOWsPjCE/rMP4bo1pseyk3UTsg== - dependencies: - "@lerna/query-graph" "3.18.5" - chalk "^2.3.1" - columnify "^1.5.4" - -"@lerna/listable@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/listable/-/listable-4.0.0.tgz#d00d6cb4809b403f2b0374fc521a78e318b01214" - integrity sha512-/rPOSDKsOHs5/PBLINZOkRIX1joOXUXEtyUs5DHLM8q6/RP668x/1lFhw6Dx7/U+L0+tbkpGtZ1Yt0LewCLgeQ== - dependencies: - "@lerna/query-graph" "4.0.0" - chalk "^4.1.0" - columnify "^1.5.4" - -"@lerna/log-packed@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-3.16.0.tgz#f83991041ee77b2495634e14470b42259fd2bc16" - integrity sha512-Fp+McSNBV/P2mnLUYTaSlG8GSmpXM7krKWcllqElGxvAqv6chk2K3c2k80MeVB4WvJ9tRjUUf+i7HUTiQ9/ckQ== - dependencies: - byte-size "^5.0.1" - columnify "^1.5.4" - has-unicode "^2.0.1" - npmlog "^4.1.2" - -"@lerna/log-packed@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/log-packed/-/log-packed-4.0.0.tgz#95168fe2e26ac6a71e42f4be857519b77e57a09f" - integrity sha512-+dpCiWbdzgMAtpajLToy9PO713IHoE6GV/aizXycAyA07QlqnkpaBNZ8DW84gHdM1j79TWockGJo9PybVhrrZQ== - dependencies: - byte-size "^7.0.0" - columnify "^1.5.4" - has-unicode "^2.0.1" - npmlog "^4.1.2" - -"@lerna/npm-conf@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-3.16.0.tgz#1c10a89ae2f6c2ee96962557738685300d376827" - integrity sha512-HbO3DUrTkCAn2iQ9+FF/eisDpWY5POQAOF1m7q//CZjdC2HSW3UYbKEGsSisFxSfaF9Z4jtrV+F/wX6qWs3CuA== - dependencies: - config-chain "^1.1.11" - pify "^4.0.1" - -"@lerna/npm-conf@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-conf/-/npm-conf-4.0.0.tgz#b259fd1e1cee2bf5402b236e770140ff9ade7fd2" - integrity sha512-uS7H02yQNq3oejgjxAxqq/jhwGEE0W0ntr8vM3EfpCW1F/wZruwQw+7bleJQ9vUBjmdXST//tk8mXzr5+JXCfw== - dependencies: - config-chain "^1.1.12" - pify "^5.0.0" - -"@lerna/npm-dist-tag@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-3.18.5.tgz#9ef9abb7c104077b31f6fab22cc73b314d54ac55" - integrity sha512-xw0HDoIG6HreVsJND9/dGls1c+lf6vhu7yJoo56Sz5bvncTloYGLUppIfDHQr4ZvmPCK8rsh0euCVh2giPxzKQ== - dependencies: - "@evocateur/npm-registry-fetch" "^4.0.0" - "@lerna/otplease" "3.18.5" - figgy-pudding "^3.5.1" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - -"@lerna/npm-dist-tag@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-dist-tag/-/npm-dist-tag-4.0.0.tgz#d1e99b4eccd3414142f0548ad331bf2d53f3257a" - integrity sha512-F20sg28FMYTgXqEQihgoqSfwmq+Id3zT23CnOwD+XQMPSy9IzyLf1fFVH319vXIw6NF6Pgs4JZN2Qty6/CQXGw== - dependencies: - "@lerna/otplease" "4.0.0" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - -"@lerna/npm-install@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-3.16.5.tgz#d6bfdc16f81285da66515ae47924d6e278d637d3" - integrity sha512-hfiKk8Eku6rB9uApqsalHHTHY+mOrrHeWEs+gtg7+meQZMTS3kzv4oVp5cBZigndQr3knTLjwthT/FX4KvseFg== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/get-npm-exec-opts" "3.13.0" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - signal-exit "^3.0.2" - write-pkg "^3.1.0" - -"@lerna/npm-install@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-install/-/npm-install-4.0.0.tgz#31180be3ab3b7d1818a1a0c206aec156b7094c78" - integrity sha512-aKNxq2j3bCH3eXl3Fmu4D54s/YLL9WSwV8W7X2O25r98wzrO38AUN6AB9EtmAx+LV/SP15et7Yueg9vSaanRWg== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - fs-extra "^9.1.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - signal-exit "^3.0.3" - write-pkg "^4.0.0" - -"@lerna/npm-publish@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-3.18.5.tgz#240e4039959fd9816b49c5b07421e11b5cb000af" - integrity sha512-3etLT9+2L8JAx5F8uf7qp6iAtOLSMj+ZYWY6oUgozPi/uLqU0/gsMsEXh3F0+YVW33q0M61RpduBoAlOOZnaTg== - dependencies: - "@evocateur/libnpmpublish" "^1.2.2" - "@lerna/otplease" "3.18.5" - "@lerna/run-lifecycle" "3.16.2" - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - pify "^4.0.1" - read-package-json "^2.0.13" - -"@lerna/npm-publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-publish/-/npm-publish-4.0.0.tgz#84eb62e876fe949ae1fd62c60804423dbc2c4472" - integrity sha512-vQb7yAPRo5G5r77DRjHITc9piR9gvEKWrmfCH7wkfBnGWEqu7n8/4bFQ7lhnkujvc8RXOsYpvbMQkNfkYibD/w== - dependencies: - "@lerna/otplease" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - fs-extra "^9.1.0" - libnpmpublish "^4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - pify "^5.0.0" - read-package-json "^3.0.0" - -"@lerna/npm-run-script@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-3.16.5.tgz#9c2ec82453a26c0b46edc0bb7c15816c821f5c15" - integrity sha512-1asRi+LjmVn3pMjEdpqKJZFT/3ZNpb+VVeJMwrJaV/3DivdNg7XlPK9LTrORuKU4PSvhdEZvJmSlxCKyDpiXsQ== - dependencies: - "@lerna/child-process" "3.16.5" - "@lerna/get-npm-exec-opts" "3.13.0" - npmlog "^4.1.2" - -"@lerna/npm-run-script@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/npm-run-script/-/npm-run-script-4.0.0.tgz#dfebf4f4601442e7c0b5214f9fb0d96c9350743b" - integrity sha512-Jmyh9/IwXJjOXqKfIgtxi0bxi1pUeKe5bD3S81tkcy+kyng/GNj9WSqD5ZggoNP2NP//s4CLDAtUYLdP7CU9rA== - dependencies: - "@lerna/child-process" "4.0.0" - "@lerna/get-npm-exec-opts" "4.0.0" - npmlog "^4.1.2" - -"@lerna/otplease@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-3.18.5.tgz#b77b8e760b40abad9f7658d988f3ea77d4fd0231" - integrity sha512-S+SldXAbcXTEDhzdxYLU0ZBKuYyURP/ND2/dK6IpKgLxQYh/z4ScljPDMyKymmEvgiEJmBsPZAAPfmNPEzxjog== - dependencies: - "@lerna/prompt" "3.18.5" - figgy-pudding "^3.5.1" - -"@lerna/otplease@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/otplease/-/otplease-4.0.0.tgz#84972eb43448f8a1077435ba1c5e59233b725850" - integrity sha512-Sgzbqdk1GH4psNiT6hk+BhjOfIr/5KhGBk86CEfHNJTk9BK4aZYyJD4lpDbDdMjIV4g03G7pYoqHzH765T4fxw== - dependencies: - "@lerna/prompt" "4.0.0" - -"@lerna/output@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-3.13.0.tgz#3ded7cc908b27a9872228a630d950aedae7a4989" - integrity sha512-7ZnQ9nvUDu/WD+bNsypmPG5MwZBwu86iRoiW6C1WBuXXDxM5cnIAC1m2WxHeFnjyMrYlRXM9PzOQ9VDD+C15Rg== - dependencies: - npmlog "^4.1.2" - -"@lerna/output@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/output/-/output-4.0.0.tgz#b1d72215c0e35483e4f3e9994debc82c621851f2" - integrity sha512-Un1sHtO1AD7buDQrpnaYTi2EG6sLF+KOPEAMxeUYG5qG3khTs2Zgzq5WE3dt2N/bKh7naESt20JjIW6tBELP0w== - dependencies: - npmlog "^4.1.2" - -"@lerna/pack-directory@3.16.4": - version "3.16.4" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-3.16.4.tgz#3eae5f91bdf5acfe0384510ed53faddc4c074693" - integrity sha512-uxSF0HZeGyKaaVHz5FroDY9A5NDDiCibrbYR6+khmrhZtY0Bgn6hWq8Gswl9iIlymA+VzCbshWIMX4o2O8C8ng== - dependencies: - "@lerna/get-packed" "3.16.0" - "@lerna/package" "3.16.0" - "@lerna/run-lifecycle" "3.16.2" - figgy-pudding "^3.5.1" - npm-packlist "^1.4.4" - npmlog "^4.1.2" - tar "^4.4.10" - temp-write "^3.4.0" - -"@lerna/pack-directory@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pack-directory/-/pack-directory-4.0.0.tgz#8b617db95d20792f043aaaa13a9ccc0e04cb4c74" - integrity sha512-NJrmZNmBHS+5aM+T8N6FVbaKFScVqKlQFJNY2k7nsJ/uklNKsLLl6VhTQBPwMTbf6Tf7l6bcKzpy7aePuq9UiQ== - dependencies: - "@lerna/get-packed" "4.0.0" - "@lerna/package" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - npm-packlist "^2.1.4" - npmlog "^4.1.2" - tar "^6.1.0" - temp-write "^4.0.0" - -"@lerna/package-graph@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-3.18.5.tgz#c740e2ea3578d059e551633e950690831b941f6b" - integrity sha512-8QDrR9T+dBegjeLr+n9WZTVxUYUhIUjUgZ0gvNxUBN8S1WB9r6H5Yk56/MVaB64tA3oGAN9IIxX6w0WvTfFudA== - dependencies: - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/validation-error" "3.13.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - semver "^6.2.0" - -"@lerna/package-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package-graph/-/package-graph-4.0.0.tgz#16a00253a8ac810f72041481cb46bcee8d8123dd" - integrity sha512-QED2ZCTkfXMKFoTGoccwUzjHtZMSf3UKX14A4/kYyBms9xfFsesCZ6SLI5YeySEgcul8iuIWfQFZqRw+Qrjraw== - dependencies: - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/validation-error" "4.0.0" - npm-package-arg "^8.1.0" - npmlog "^4.1.2" - semver "^7.3.4" - -"@lerna/package@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-3.16.0.tgz#7e0a46e4697ed8b8a9c14d59c7f890e0d38ba13c" - integrity sha512-2lHBWpaxcBoiNVbtyLtPUuTYEaB/Z+eEqRS9duxpZs6D+mTTZMNy6/5vpEVSCBmzvdYpyqhqaYjjSLvjjr5Riw== - dependencies: - load-json-file "^5.3.0" - npm-package-arg "^6.1.0" - write-pkg "^3.1.0" - -"@lerna/package@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/package/-/package-4.0.0.tgz#1b4c259c4bcff45c876ee1d591a043aacbc0d6b7" - integrity sha512-l0M/izok6FlyyitxiQKr+gZLVFnvxRQdNhzmQ6nRnN9dvBJWn+IxxpM+cLqGACatTnyo9LDzNTOj2Db3+s0s8Q== - dependencies: - load-json-file "^6.2.0" - npm-package-arg "^8.1.0" - write-pkg "^4.0.0" - -"@lerna/prerelease-id-from-version@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-3.16.0.tgz#b24bfa789f5e1baab914d7b08baae9b7bd7d83a1" - integrity sha512-qZyeUyrE59uOK8rKdGn7jQz+9uOpAaF/3hbslJVFL1NqF9ELDTqjCPXivuejMX/lN4OgD6BugTO4cR7UTq/sZA== - dependencies: - semver "^6.2.0" - -"@lerna/prerelease-id-from-version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prerelease-id-from-version/-/prerelease-id-from-version-4.0.0.tgz#c7e0676fcee1950d85630e108eddecdd5b48c916" - integrity sha512-GQqguzETdsYRxOSmdFZ6zDBXDErIETWOqomLERRY54f4p+tk4aJjoVdd9xKwehC9TBfIFvlRbL1V9uQGHh1opg== - dependencies: - semver "^7.3.4" - -"@lerna/profiler@3.20.0": - version "3.20.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-3.20.0.tgz#0f6dc236f4ea8f9ea5f358c6703305a4f32ad051" - integrity sha512-bh8hKxAlm6yu8WEOvbLENm42i2v9SsR4WbrCWSbsmOElx3foRnMlYk7NkGECa+U5c3K4C6GeBbwgqs54PP7Ljg== - dependencies: - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" - npmlog "^4.1.2" - upath "^1.2.0" - -"@lerna/profiler@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/profiler/-/profiler-4.0.0.tgz#8a53ab874522eae15d178402bff90a14071908e9" - integrity sha512-/BaEbqnVh1LgW/+qz8wCuI+obzi5/vRE8nlhjPzdEzdmWmZXuCKyWSEzAyHOJWw1ntwMiww5dZHhFQABuoFz9Q== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - upath "^2.0.1" - -"@lerna/project@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-3.21.0.tgz#5d784d2d10c561a00f20320bcdb040997c10502d" - integrity sha512-xT1mrpET2BF11CY32uypV2GPtPVm6Hgtha7D81GQP9iAitk9EccrdNjYGt5UBYASl4CIDXBRxwmTTVGfrCx82A== - dependencies: - "@lerna/package" "3.16.0" - "@lerna/validation-error" "3.13.0" - cosmiconfig "^5.1.0" - dedent "^0.7.0" - dot-prop "^4.2.0" - glob-parent "^5.0.0" - globby "^9.2.0" - load-json-file "^5.3.0" - npmlog "^4.1.2" - p-map "^2.1.0" - resolve-from "^4.0.0" - write-json-file "^3.2.0" - -"@lerna/project@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/project/-/project-4.0.0.tgz#ff84893935833533a74deff30c0e64ddb7f0ba6b" - integrity sha512-o0MlVbDkD5qRPkFKlBZsXZjoNTWPyuL58564nSfZJ6JYNmgAptnWPB2dQlAc7HWRZkmnC2fCkEdoU+jioPavbg== - dependencies: - "@lerna/package" "4.0.0" - "@lerna/validation-error" "4.0.0" - cosmiconfig "^7.0.0" - dedent "^0.7.0" - dot-prop "^6.0.1" - glob-parent "^5.1.1" - globby "^11.0.2" - load-json-file "^6.2.0" - npmlog "^4.1.2" - p-map "^4.0.0" - resolve-from "^5.0.0" - write-json-file "^4.3.0" - -"@lerna/prompt@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-3.18.5.tgz#628cd545f225887d060491ab95df899cfc5218a1" - integrity sha512-rkKj4nm1twSbBEb69+Em/2jAERK8htUuV8/xSjN0NPC+6UjzAwY52/x9n5cfmpa9lyKf/uItp7chCI7eDmNTKQ== - dependencies: - inquirer "^6.2.0" - npmlog "^4.1.2" - -"@lerna/prompt@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/prompt/-/prompt-4.0.0.tgz#5ec69a803f3f0db0ad9f221dad64664d3daca41b" - integrity sha512-4Ig46oCH1TH5M7YyTt53fT6TuaKMgqUUaqdgxvp6HP6jtdak6+amcsqB8YGz2eQnw/sdxunx84DfI9XpoLj4bQ== - dependencies: - inquirer "^7.3.3" - npmlog "^4.1.2" - -"@lerna/publish@3.22.1": - version "3.22.1" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-3.22.1.tgz#b4f7ce3fba1e9afb28be4a1f3d88222269ba9519" - integrity sha512-PG9CM9HUYDreb1FbJwFg90TCBQooGjj+n/pb3gw/eH5mEDq0p8wKdLFe0qkiqUkm/Ub5C8DbVFertIo0Vd0zcw== - dependencies: - "@evocateur/libnpmaccess" "^3.1.2" - "@evocateur/npm-registry-fetch" "^4.0.0" - "@evocateur/pacote" "^9.6.3" - "@lerna/check-working-tree" "3.16.5" - "@lerna/child-process" "3.16.5" - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/describe-ref" "3.16.5" - "@lerna/log-packed" "3.16.0" - "@lerna/npm-conf" "3.16.0" - "@lerna/npm-dist-tag" "3.18.5" - "@lerna/npm-publish" "3.18.5" - "@lerna/otplease" "3.18.5" - "@lerna/output" "3.13.0" - "@lerna/pack-directory" "3.16.4" - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/prompt" "3.18.5" - "@lerna/pulse-till-done" "3.13.0" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - "@lerna/version" "3.22.1" - figgy-pudding "^3.5.1" - fs-extra "^8.1.0" - npm-package-arg "^6.1.0" - npmlog "^4.1.2" - p-finally "^1.0.0" - p-map "^2.1.0" - p-pipe "^1.2.0" - semver "^6.2.0" - -"@lerna/publish@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/publish/-/publish-4.0.0.tgz#f67011305adeba120066a3b6d984a5bb5fceef65" - integrity sha512-K8jpqjHrChH22qtkytA5GRKIVFEtqBF6JWj1I8dWZtHs4Jywn8yB1jQ3BAMLhqmDJjWJtRck0KXhQQKzDK2UPg== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/describe-ref" "4.0.0" - "@lerna/log-packed" "4.0.0" - "@lerna/npm-conf" "4.0.0" - "@lerna/npm-dist-tag" "4.0.0" - "@lerna/npm-publish" "4.0.0" - "@lerna/otplease" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/pack-directory" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/pulse-till-done" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - "@lerna/version" "4.0.0" - fs-extra "^9.1.0" - libnpmaccess "^4.0.1" - npm-package-arg "^8.1.0" - npm-registry-fetch "^9.0.0" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - pacote "^11.2.6" - semver "^7.3.4" - -"@lerna/pulse-till-done@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-3.13.0.tgz#c8e9ce5bafaf10d930a67d7ed0ccb5d958fe0110" - integrity sha512-1SOHpy7ZNTPulzIbargrgaJX387csN7cF1cLOGZiJQA6VqnS5eWs2CIrG8i8wmaUavj2QlQ5oEbRMVVXSsGrzA== - dependencies: - npmlog "^4.1.2" - -"@lerna/pulse-till-done@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/pulse-till-done/-/pulse-till-done-4.0.0.tgz#04bace7d483a8205c187b806bcd8be23d7bb80a3" - integrity sha512-Frb4F7QGckaybRhbF7aosLsJ5e9WuH7h0KUkjlzSByVycxY91UZgaEIVjS2oN9wQLrheLMHl6SiFY0/Pvo0Cxg== - dependencies: - npmlog "^4.1.2" - -"@lerna/query-graph@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-3.18.5.tgz#df4830bb5155273003bf35e8dda1c32d0927bd86" - integrity sha512-50Lf4uuMpMWvJ306be3oQDHrWV42nai9gbIVByPBYJuVW8dT8O8pA3EzitNYBUdLL9/qEVbrR0ry1HD7EXwtRA== - dependencies: - "@lerna/package-graph" "3.18.5" - figgy-pudding "^3.5.1" - -"@lerna/query-graph@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/query-graph/-/query-graph-4.0.0.tgz#09dd1c819ac5ee3f38db23931143701f8a6eef63" - integrity sha512-YlP6yI3tM4WbBmL9GCmNDoeQyzcyg1e4W96y/PKMZa5GbyUvkS2+Jc2kwPD+5KcXou3wQZxSPzR3Te5OenaDdg== - dependencies: - "@lerna/package-graph" "4.0.0" - -"@lerna/resolve-symlink@3.16.0": - version "3.16.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-3.16.0.tgz#37fc7095fabdbcf317c26eb74e0d0bde8efd2386" - integrity sha512-Ibj5e7njVHNJ/NOqT4HlEgPFPtPLWsO7iu59AM5bJDcAJcR96mLZ7KGVIsS2tvaO7akMEJvt2P+ErwCdloG3jQ== - dependencies: - fs-extra "^8.1.0" - npmlog "^4.1.2" - read-cmd-shim "^1.0.1" - -"@lerna/resolve-symlink@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/resolve-symlink/-/resolve-symlink-4.0.0.tgz#6d006628a210c9b821964657a9e20a8c9a115e14" - integrity sha512-RtX8VEUzqT+uLSCohx8zgmjc6zjyRlh6i/helxtZTMmc4+6O4FS9q5LJas2uGO2wKvBlhcD6siibGt7dIC3xZA== - dependencies: - fs-extra "^9.1.0" - npmlog "^4.1.2" - read-cmd-shim "^2.0.0" - -"@lerna/rimraf-dir@3.16.5": - version "3.16.5" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-3.16.5.tgz#04316ab5ffd2909657aaf388ea502cb8c2f20a09" - integrity sha512-bQlKmO0pXUsXoF8lOLknhyQjOZsCc0bosQDoX4lujBXSWxHVTg1VxURtWf2lUjz/ACsJVDfvHZbDm8kyBk5okA== - dependencies: - "@lerna/child-process" "3.16.5" - npmlog "^4.1.2" - path-exists "^3.0.0" - rimraf "^2.6.2" - -"@lerna/rimraf-dir@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/rimraf-dir/-/rimraf-dir-4.0.0.tgz#2edf3b62d4eb0ef4e44e430f5844667d551ec25a" - integrity sha512-QNH9ABWk9mcMJh2/muD9iYWBk1oQd40y6oH+f3wwmVGKYU5YJD//+zMiBI13jxZRtwBx0vmBZzkBkK1dR11cBg== - dependencies: - "@lerna/child-process" "4.0.0" - npmlog "^4.1.2" - path-exists "^4.0.0" - rimraf "^3.0.2" - -"@lerna/run-lifecycle@3.16.2": - version "3.16.2" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-3.16.2.tgz#67b288f8ea964db9ea4fb1fbc7715d5bbb0bce00" - integrity sha512-RqFoznE8rDpyyF0rOJy3+KjZCeTkO8y/OB9orPauR7G2xQ7PTdCpgo7EO6ZNdz3Al+k1BydClZz/j78gNCmL2A== - dependencies: - "@lerna/npm-conf" "3.16.0" - figgy-pudding "^3.5.1" - npm-lifecycle "^3.1.2" - npmlog "^4.1.2" - -"@lerna/run-lifecycle@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-lifecycle/-/run-lifecycle-4.0.0.tgz#e648a46f9210a9bcd7c391df6844498cb5079334" - integrity sha512-IwxxsajjCQQEJAeAaxF8QdEixfI7eLKNm4GHhXHrgBu185JcwScFZrj9Bs+PFKxwb+gNLR4iI5rpUdY8Y0UdGQ== - dependencies: - "@lerna/npm-conf" "4.0.0" - npm-lifecycle "^3.1.5" - npmlog "^4.1.2" - -"@lerna/run-topologically@3.18.5": - version "3.18.5" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-3.18.5.tgz#3cd639da20e967d7672cb88db0f756b92f2fdfc3" - integrity sha512-6N1I+6wf4hLOnPW+XDZqwufyIQ6gqoPfHZFkfWlvTQ+Ue7CuF8qIVQ1Eddw5HKQMkxqN10thKOFfq/9NQZ4NUg== - dependencies: - "@lerna/query-graph" "3.18.5" - figgy-pudding "^3.5.1" - p-queue "^4.0.0" - -"@lerna/run-topologically@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run-topologically/-/run-topologically-4.0.0.tgz#af846eeee1a09b0c2be0d1bfb5ef0f7b04bb1827" - integrity sha512-EVZw9hGwo+5yp+VL94+NXRYisqgAlj0jWKWtAIynDCpghRxCE5GMO3xrQLmQgqkpUl9ZxQFpICgYv5DW4DksQA== - dependencies: - "@lerna/query-graph" "4.0.0" - p-queue "^6.6.2" - -"@lerna/run@3.21.0": - version "3.21.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-3.21.0.tgz#2a35ec84979e4d6e42474fe148d32e5de1cac891" - integrity sha512-fJF68rT3veh+hkToFsBmUJ9MHc9yGXA7LSDvhziAojzOb0AI/jBDp6cEcDQyJ7dbnplba2Lj02IH61QUf9oW0Q== - dependencies: - "@lerna/command" "3.21.0" - "@lerna/filter-options" "3.20.0" - "@lerna/npm-run-script" "3.16.5" - "@lerna/output" "3.13.0" - "@lerna/profiler" "3.20.0" - "@lerna/run-topologically" "3.18.5" - "@lerna/timer" "3.13.0" - "@lerna/validation-error" "3.13.0" - p-map "^2.1.0" - -"@lerna/run@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/run/-/run-4.0.0.tgz#4bc7fda055a729487897c23579694f6183c91262" - integrity sha512-9giulCOzlMPzcZS/6Eov6pxE9gNTyaXk0Man+iCIdGJNMrCnW7Dme0Z229WWP/UoxDKg71F2tMsVVGDiRd8fFQ== - dependencies: - "@lerna/command" "4.0.0" - "@lerna/filter-options" "4.0.0" - "@lerna/npm-run-script" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/profiler" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/timer" "4.0.0" - "@lerna/validation-error" "4.0.0" - p-map "^4.0.0" - -"@lerna/symlink-binary@3.17.0": - version "3.17.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-3.17.0.tgz#8f8031b309863814883d3f009877f82e38aef45a" - integrity sha512-RLpy9UY6+3nT5J+5jkM5MZyMmjNHxZIZvXLV+Q3MXrf7Eaa1hNqyynyj4RO95fxbS+EZc4XVSk25DGFQbcRNSQ== - dependencies: - "@lerna/create-symlink" "3.16.2" - "@lerna/package" "3.16.0" - fs-extra "^8.1.0" - p-map "^2.1.0" - -"@lerna/symlink-binary@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-binary/-/symlink-binary-4.0.0.tgz#21009f62d53a425f136cb4c1a32c6b2a0cc02d47" - integrity sha512-zualodWC4q1QQc1pkz969hcFeWXOsVYZC5AWVtAPTDfLl+TwM7eG/O6oP+Rr3fFowspxo6b1TQ6sYfDV6HXNWA== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/package" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - -"@lerna/symlink-dependencies@3.17.0": - version "3.17.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-3.17.0.tgz#48d6360e985865a0e56cd8b51b308a526308784a" - integrity sha512-KmjU5YT1bpt6coOmdFueTJ7DFJL4H1w5eF8yAQ2zsGNTtZ+i5SGFBWpb9AQaw168dydc3s4eu0W0Sirda+F59Q== - dependencies: - "@lerna/create-symlink" "3.16.2" - "@lerna/resolve-symlink" "3.16.0" - "@lerna/symlink-binary" "3.17.0" - fs-extra "^8.1.0" - p-finally "^1.0.0" - p-map "^2.1.0" - p-map-series "^1.0.0" - -"@lerna/symlink-dependencies@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/symlink-dependencies/-/symlink-dependencies-4.0.0.tgz#8910eca084ae062642d0490d8972cf2d98e9ebbd" - integrity sha512-BABo0MjeUHNAe2FNGty1eantWp8u83BHSeIMPDxNq0MuW2K3CiQRaeWT3EGPAzXpGt0+hVzBrA6+OT0GPn7Yuw== - dependencies: - "@lerna/create-symlink" "4.0.0" - "@lerna/resolve-symlink" "4.0.0" - "@lerna/symlink-binary" "4.0.0" - fs-extra "^9.1.0" - p-map "^4.0.0" - p-map-series "^2.1.0" - -"@lerna/timer@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-3.13.0.tgz#bcd0904551db16e08364d6c18e5e2160fc870781" - integrity sha512-RHWrDl8U4XNPqY5MQHkToWS9jHPnkLZEt5VD+uunCKTfzlxGnRCr3/zVr8VGy/uENMYpVP3wJa4RKGY6M0vkRw== - -"@lerna/timer@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/timer/-/timer-4.0.0.tgz#a52e51bfcd39bfd768988049ace7b15c1fd7a6da" - integrity sha512-WFsnlaE7SdOvjuyd05oKt8Leg3ENHICnvX3uYKKdByA+S3g+TCz38JsNs7OUZVt+ba63nC2nbXDlUnuT2Xbsfg== - -"@lerna/validation-error@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-3.13.0.tgz#c86b8f07c5ab9539f775bd8a54976e926f3759c3" - integrity sha512-SiJP75nwB8GhgwLKQfdkSnDufAaCbkZWJqEDlKOUPUvVOplRGnfL+BPQZH5nvq2BYSRXsksXWZ4UHVnQZI/HYA== - dependencies: - npmlog "^4.1.2" - -"@lerna/validation-error@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/validation-error/-/validation-error-4.0.0.tgz#af9d62fe8304eaa2eb9a6ba1394f9aa807026d35" - integrity sha512-1rBOM5/koiVWlRi3V6dB863E1YzJS8v41UtsHgMr6gB2ncJ2LsQtMKlJpi3voqcgh41H8UsPXR58RrrpPpufyw== - dependencies: - npmlog "^4.1.2" - -"@lerna/version@3.22.1": - version "3.22.1" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-3.22.1.tgz#9805a9247a47ee62d6b81bd9fa5fb728b24b59e2" - integrity sha512-PSGt/K1hVqreAFoi3zjD0VEDupQ2WZVlVIwesrE5GbrL2BjXowjCsTDPqblahDUPy0hp6h7E2kG855yLTp62+g== - dependencies: - "@lerna/check-working-tree" "3.16.5" - "@lerna/child-process" "3.16.5" - "@lerna/collect-updates" "3.20.0" - "@lerna/command" "3.21.0" - "@lerna/conventional-commits" "3.22.0" - "@lerna/github-client" "3.22.0" - "@lerna/gitlab-client" "3.15.0" - "@lerna/output" "3.13.0" - "@lerna/prerelease-id-from-version" "3.16.0" - "@lerna/prompt" "3.18.5" - "@lerna/run-lifecycle" "3.16.2" - "@lerna/run-topologically" "3.18.5" - "@lerna/validation-error" "3.13.0" - chalk "^2.3.1" - dedent "^0.7.0" - load-json-file "^5.3.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - p-map "^2.1.0" - p-pipe "^1.2.0" - p-reduce "^1.0.0" - p-waterfall "^1.0.0" - semver "^6.2.0" - slash "^2.0.0" - temp-write "^3.4.0" - write-json-file "^3.2.0" - -"@lerna/version@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/version/-/version-4.0.0.tgz#532659ec6154d8a8789c5ab53878663e244e3228" - integrity sha512-otUgiqs5W9zGWJZSCCMRV/2Zm2A9q9JwSDS7s/tlKq4mWCYriWo7+wsHEA/nPTMDyYyBO5oyZDj+3X50KDUzeA== - dependencies: - "@lerna/check-working-tree" "4.0.0" - "@lerna/child-process" "4.0.0" - "@lerna/collect-updates" "4.0.0" - "@lerna/command" "4.0.0" - "@lerna/conventional-commits" "4.0.0" - "@lerna/github-client" "4.0.0" - "@lerna/gitlab-client" "4.0.0" - "@lerna/output" "4.0.0" - "@lerna/prerelease-id-from-version" "4.0.0" - "@lerna/prompt" "4.0.0" - "@lerna/run-lifecycle" "4.0.0" - "@lerna/run-topologically" "4.0.0" - "@lerna/validation-error" "4.0.0" - chalk "^4.1.0" - dedent "^0.7.0" - load-json-file "^6.2.0" - minimatch "^3.0.4" - npmlog "^4.1.2" - p-map "^4.0.0" - p-pipe "^3.1.0" - p-reduce "^2.1.0" - p-waterfall "^2.1.1" - semver "^7.3.4" - slash "^3.0.0" - temp-write "^4.0.0" - write-json-file "^4.3.0" - -"@lerna/write-log-file@3.13.0": - version "3.13.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-3.13.0.tgz#b78d9e4cfc1349a8be64d91324c4c8199e822a26" - integrity sha512-RibeMnDPvlL8bFYW5C8cs4mbI3AHfQef73tnJCQ/SgrXZHehmHnsyWUiE7qDQCAo+B1RfTapvSyFF69iPj326A== - dependencies: - npmlog "^4.1.2" - write-file-atomic "^2.3.0" - -"@lerna/write-log-file@4.0.0": - version "4.0.0" - resolved "https://registry.yarnpkg.com/@lerna/write-log-file/-/write-log-file-4.0.0.tgz#18221a38a6a307d6b0a5844dd592ad53fa27091e" - integrity sha512-XRG5BloiArpXRakcnPHmEHJp+4AtnhRtpDIHSghmXD5EichI1uD73J7FgPp30mm2pDRq3FdqB0NbwSEsJ9xFQg== - dependencies: - npmlog "^4.1.2" - write-file-atomic "^3.0.3" - -"@mrmlnc/readdir-enhanced@^2.2.1": - version "2.2.1" - resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" - integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== - dependencies: - call-me-maybe "^1.0.1" - glob-to-regexp "^0.3.0" - "@nodelib/fs.scandir@2.1.3": version "2.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b" + resolved "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz" integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw== dependencies: "@nodelib/fs.stat" "2.0.3" @@ -1929,30 +486,20 @@ "@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2": version "2.0.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3" + resolved "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz" integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA== -"@nodelib/fs.stat@^1.1.2": - version "1.1.3" - resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" - integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== - "@nodelib/fs.walk@^1.2.3": version "1.2.4" - resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976" + resolved "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz" integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ== dependencies: "@nodelib/fs.scandir" "2.1.3" fastq "^1.6.0" -"@npmcli/ci-detect@^1.0.0": - version "1.3.0" - resolved "https://registry.yarnpkg.com/@npmcli/ci-detect/-/ci-detect-1.3.0.tgz#6c1d2c625fb6ef1b9dea85ad0a5afcbef85ef22a" - integrity sha512-oN3y7FAROHhrAt7Rr7PnTSwrHrZVRTS2ZbyxeQwSSYD0ifwM3YNgQqbaRmjcWoPyq77MjchusjJDspbzMmip1Q== - "@npmcli/fs@^1.0.0": version "1.0.0" - resolved "https://registry.yarnpkg.com/@npmcli/fs/-/fs-1.0.0.tgz#589612cfad3a6ea0feafcb901d29c63fd52db09f" + resolved "https://registry.npmjs.org/@npmcli/fs/-/fs-1.0.0.tgz" integrity sha512-8ltnOpRR/oJbOp8vaGUnipOi3bqkcW+sLHFlyXIr08OGHmVJLB1Hn7QtGXbYcpVtH1gAYZTlmDXtE4YV0+AMMQ== dependencies: "@gar/promisify" "^1.0.1" @@ -1960,7 +507,7 @@ "@npmcli/git@^2.1.0": version "2.1.0" - resolved "https://registry.yarnpkg.com/@npmcli/git/-/git-2.1.0.tgz#2fbd77e147530247d37f325930d457b3ebe894f6" + resolved "https://registry.npmjs.org/@npmcli/git/-/git-2.1.0.tgz" integrity sha512-/hBFX/QG1b+N7PZBFs0bi+evgRZcK9nWBxQKZkGoXUT5hJSwl5c4d7y8/hm+NQZRPhQ67RzFaj5UM9YeyKoryw== dependencies: "@npmcli/promise-spawn" "^1.3.2" @@ -1974,7 +521,7 @@ "@npmcli/installed-package-contents@^1.0.6": version "1.0.7" - resolved "https://registry.yarnpkg.com/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz#ab7408c6147911b970a8abe261ce512232a3f4fa" + resolved "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-1.0.7.tgz" integrity sha512-9rufe0wnJusCQoLpV9ZPKIVP55itrM5BxOXs10DmdbRfgWtHy1LDyskbwRnBghuB0PrF7pNPOqREVtpz4HqzKw== dependencies: npm-bundled "^1.1.1" @@ -1982,26 +529,26 @@ "@npmcli/move-file@^1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@npmcli/move-file/-/move-file-1.0.1.tgz#de103070dac0f48ce49cf6693c23af59c0f70464" + resolved "https://registry.npmjs.org/@npmcli/move-file/-/move-file-1.0.1.tgz" integrity sha512-Uv6h1sT+0DrblvIrolFtbvM1FgWm+/sy4B3pvLp67Zys+thcukzS5ekn7HsZFGpWP4Q3fYJCljbWQE/XivMRLw== dependencies: mkdirp "^1.0.4" "@npmcli/node-gyp@^1.0.2": version "1.0.2" - resolved "https://registry.yarnpkg.com/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz#3cdc1f30e9736dbc417373ed803b42b1a0a29ede" + resolved "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-1.0.2.tgz" integrity sha512-yrJUe6reVMpktcvagumoqD9r08fH1iRo01gn1u0zoCApa9lnZGEigVKUd2hzsCId4gdtkZZIVscLhNxMECKgRg== "@npmcli/promise-spawn@^1.2.0", "@npmcli/promise-spawn@^1.3.2": version "1.3.2" - resolved "https://registry.yarnpkg.com/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz#42d4e56a8e9274fba180dabc0aea6e38f29274f5" + resolved "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-1.3.2.tgz" integrity sha512-QyAGYo/Fbj4MXeGdJcFzZ+FkDkomfRBrPM+9QYJSg+PxgAUL+LU3FneQk37rKR2/zjqkCV1BLHccX98wRXG3Sg== dependencies: infer-owner "^1.0.4" "@npmcli/run-script@^1.8.2": version "1.8.6" - resolved "https://registry.yarnpkg.com/@npmcli/run-script/-/run-script-1.8.6.tgz#18314802a6660b0d4baa4c3afe7f1ad39d8c28b7" + resolved "https://registry.npmjs.org/@npmcli/run-script/-/run-script-1.8.6.tgz" integrity sha512-e42bVZnC6VluBZBAFEr3YrdqSspG3bgilyg4nSLBJ7TRGNCzxHa92XAHxQBLYg0BmgwO4b2mf3h/l5EkEWRn3g== dependencies: "@npmcli/node-gyp" "^1.0.2" @@ -2009,201 +556,42 @@ node-gyp "^7.1.0" read-package-json-fast "^2.0.1" -"@octokit/auth-token@^2.4.0", "@octokit/auth-token@^2.4.4": - version "2.5.0" - resolved "https://registry.yarnpkg.com/@octokit/auth-token/-/auth-token-2.5.0.tgz#27c37ea26c205f28443402477ffd261311f21e36" - integrity sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g== - dependencies: - "@octokit/types" "^6.0.3" - -"@octokit/core@^3.5.1": - version "3.5.1" - resolved "https://registry.yarnpkg.com/@octokit/core/-/core-3.5.1.tgz#8601ceeb1ec0e1b1b8217b960a413ed8e947809b" - integrity sha512-omncwpLVxMP+GLpLPgeGJBF6IWJFjXDS5flY5VbppePYX9XehevbDykRH9PdCdvqt9TS5AOTiDide7h0qrkHjw== - dependencies: - "@octokit/auth-token" "^2.4.4" - "@octokit/graphql" "^4.5.8" - "@octokit/request" "^5.6.0" - "@octokit/request-error" "^2.0.5" - "@octokit/types" "^6.0.3" - before-after-hook "^2.2.0" - universal-user-agent "^6.0.0" - -"@octokit/endpoint@^6.0.1": - version "6.0.12" - resolved "https://registry.yarnpkg.com/@octokit/endpoint/-/endpoint-6.0.12.tgz#3b4d47a4b0e79b1027fb8d75d4221928b2d05658" - integrity sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA== - dependencies: - "@octokit/types" "^6.0.3" - is-plain-object "^5.0.0" - universal-user-agent "^6.0.0" - -"@octokit/graphql@^4.5.8": - version "4.8.0" - resolved "https://registry.yarnpkg.com/@octokit/graphql/-/graphql-4.8.0.tgz#664d9b11c0e12112cbf78e10f49a05959aa22cc3" - integrity sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg== - dependencies: - "@octokit/request" "^5.6.0" - "@octokit/types" "^6.0.3" - universal-user-agent "^6.0.0" - -"@octokit/openapi-types@^10.2.2": - version "10.2.2" - resolved "https://registry.yarnpkg.com/@octokit/openapi-types/-/openapi-types-10.2.2.tgz#6c1c839d7d169feabaf1d2a69c79439c75d979cd" - integrity sha512-EVcXQ+ZrC04cg17AMg1ofocWMxHDn17cB66ZHgYc0eUwjFtxS0oBzkyw2VqIrHBwVgtfoYrq1WMQfQmMjUwthw== - -"@octokit/plugin-enterprise-rest@^6.0.1": - version "6.0.1" - resolved "https://registry.yarnpkg.com/@octokit/plugin-enterprise-rest/-/plugin-enterprise-rest-6.0.1.tgz#e07896739618dab8da7d4077c658003775f95437" - integrity sha512-93uGjlhUD+iNg1iWhUENAtJata6w5nE+V4urXOAlIXdco6xNZtUSfYY8dzp3Udy74aqO/B5UZL80x/YMa5PKRw== - -"@octokit/plugin-paginate-rest@^1.1.1": - version "1.1.2" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-1.1.2.tgz#004170acf8c2be535aba26727867d692f7b488fc" - integrity sha512-jbsSoi5Q1pj63sC16XIUboklNw+8tL9VOnJsWycWYR78TKss5PVpIPb1TUUcMQ+bBh7cY579cVAWmf5qG+dw+Q== - dependencies: - "@octokit/types" "^2.0.1" - -"@octokit/plugin-paginate-rest@^2.16.0": - version "2.16.3" - resolved "https://registry.yarnpkg.com/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.16.3.tgz#6dbf74a12a53e04da6ca731d4c93f20c0b5c6fe9" - integrity sha512-kdc65UEsqze/9fCISq6BxLzeB9qf0vKvKojIfzgwf4tEF+Wy6c9dXnPFE6vgpoDFB1Z5Jek5WFVU6vL1w22+Iw== - dependencies: - "@octokit/types" "^6.28.1" - -"@octokit/plugin-request-log@^1.0.0", "@octokit/plugin-request-log@^1.0.4": - version "1.0.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz#5e50ed7083a613816b1e4a28aeec5fb7f1462e85" - integrity sha512-mLUsMkgP7K/cnFEw07kWqXGF5LKrOkD+lhCrKvPHXWDywAwuDUeDwWBpc69XK3pNX0uKiVt8g5z96PJ6z9xCFA== - -"@octokit/plugin-rest-endpoint-methods@2.4.0": - version "2.4.0" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-2.4.0.tgz#3288ecf5481f68c494dd0602fc15407a59faf61e" - integrity sha512-EZi/AWhtkdfAYi01obpX0DF7U6b1VRr30QNQ5xSFPITMdLSfhcBqjamE3F+sKcxPbD7eZuMHu3Qkk2V+JGxBDQ== - dependencies: - "@octokit/types" "^2.0.1" - deprecation "^2.3.1" - -"@octokit/plugin-rest-endpoint-methods@^5.9.0": - version "5.10.4" - resolved "https://registry.yarnpkg.com/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.10.4.tgz#97e85eb7375e30b9bf193894670f9da205e79408" - integrity sha512-Dh+EAMCYR9RUHwQChH94Skl0lM8Fh99auT8ggck/xTzjJrwVzvsd0YH68oRPqp/HxICzmUjLfaQ9sy1o1sfIiA== - dependencies: - "@octokit/types" "^6.28.1" - deprecation "^2.3.1" - -"@octokit/request-error@^1.0.2": - version "1.2.1" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-1.2.1.tgz#ede0714c773f32347576c25649dc013ae6b31801" - integrity sha512-+6yDyk1EES6WK+l3viRDElw96MvwfJxCt45GvmjDUKWjYIb3PJZQkq3i46TwGwoPD4h8NmTrENmtyA1FwbmhRA== - dependencies: - "@octokit/types" "^2.0.0" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request-error@^2.0.5", "@octokit/request-error@^2.1.0": - version "2.1.0" - resolved "https://registry.yarnpkg.com/@octokit/request-error/-/request-error-2.1.0.tgz#9e150357831bfc788d13a4fd4b1913d60c74d677" - integrity sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg== - dependencies: - "@octokit/types" "^6.0.3" - deprecation "^2.0.0" - once "^1.4.0" - -"@octokit/request@^5.2.0", "@octokit/request@^5.6.0": - version "5.6.1" - resolved "https://registry.yarnpkg.com/@octokit/request/-/request-5.6.1.tgz#f97aff075c37ab1d427c49082fefeef0dba2d8ce" - integrity sha512-Ls2cfs1OfXaOKzkcxnqw5MR6drMA/zWX/LIS/p8Yjdz7QKTPQLMsB3R+OvoxE6XnXeXEE2X7xe4G4l4X0gRiKQ== - dependencies: - "@octokit/endpoint" "^6.0.1" - "@octokit/request-error" "^2.1.0" - "@octokit/types" "^6.16.1" - is-plain-object "^5.0.0" - node-fetch "^2.6.1" - universal-user-agent "^6.0.0" - -"@octokit/rest@^16.28.4": - version "16.43.2" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-16.43.2.tgz#c53426f1e1d1044dee967023e3279c50993dd91b" - integrity sha512-ngDBevLbBTFfrHZeiS7SAMAZ6ssuVmXuya+F/7RaVvlysgGa1JKJkKWY+jV6TCJYcW0OALfJ7nTIGXcBXzycfQ== - dependencies: - "@octokit/auth-token" "^2.4.0" - "@octokit/plugin-paginate-rest" "^1.1.1" - "@octokit/plugin-request-log" "^1.0.0" - "@octokit/plugin-rest-endpoint-methods" "2.4.0" - "@octokit/request" "^5.2.0" - "@octokit/request-error" "^1.0.2" - atob-lite "^2.0.0" - before-after-hook "^2.0.0" - btoa-lite "^1.0.0" - deprecation "^2.0.0" - lodash.get "^4.4.2" - lodash.set "^4.3.2" - lodash.uniq "^4.5.0" - octokit-pagination-methods "^1.1.0" - once "^1.4.0" - universal-user-agent "^4.0.0" - -"@octokit/rest@^18.1.0": - version "18.10.0" - resolved "https://registry.yarnpkg.com/@octokit/rest/-/rest-18.10.0.tgz#8a0add9611253e0e31d3ed5b4bc941a3795a7648" - integrity sha512-esHR5OKy38bccL/sajHqZudZCvmv4yjovMJzyXlphaUo7xykmtOdILGJ3aAm0mFHmMLmPFmDMJXf39cAjNJsrw== - dependencies: - "@octokit/core" "^3.5.1" - "@octokit/plugin-paginate-rest" "^2.16.0" - "@octokit/plugin-request-log" "^1.0.4" - "@octokit/plugin-rest-endpoint-methods" "^5.9.0" - -"@octokit/types@^2.0.0", "@octokit/types@^2.0.1": - version "2.16.2" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-2.16.2.tgz#4c5f8da3c6fecf3da1811aef678fda03edac35d2" - integrity sha512-O75k56TYvJ8WpAakWwYRN8Bgu60KrmX0z1KqFp1kNiFNkgW+JW+9EBKZ+S33PU6SLvbihqd+3drvPxKK68Ee8Q== - dependencies: - "@types/node" ">= 8" - -"@octokit/types@^6.0.3", "@octokit/types@^6.16.1", "@octokit/types@^6.28.1": - version "6.28.1" - resolved "https://registry.yarnpkg.com/@octokit/types/-/types-6.28.1.tgz#ab990d1fe952226055e81c7650480e6bacfb877c" - integrity sha512-XlxDoQLFO5JnFZgKVQTYTvXRsQFfr/GwDUU108NJ9R5yFPkA2qXhTJjYuul3vE4eLXP40FA2nysOu2zd6boE+w== - dependencies: - "@octokit/openapi-types" "^10.2.2" - "@polka/url@^1.0.0-next.20": version "1.0.0-next.20" - resolved "https://registry.yarnpkg.com/@polka/url/-/url-1.0.0-next.20.tgz#111b5db0f501aa89b05076fa31f0ea0e0c292cd3" + resolved "https://registry.npmjs.org/@polka/url/-/url-1.0.0-next.20.tgz" integrity sha512-88p7+M0QGxKpmnkfXjS4V26AnoC/eiqZutE8GLdaI5X12NY75bXSdTY9NkmYb2Xyk1O+MmkuO6Frmsj84V6I8Q== "@sinonjs/commons@^1.7.0": version "1.8.0" - resolved "https://registry.yarnpkg.com/@sinonjs/commons/-/commons-1.8.0.tgz#c8d68821a854c555bba172f3b06959a0039b236d" + resolved "https://registry.npmjs.org/@sinonjs/commons/-/commons-1.8.0.tgz" integrity sha512-wEj54PfsZ5jGSwMX68G8ZXFawcSglQSXqCftWX3ec8MDUzQdHgcKvw97awHbY0efQEL5iKUOAmmVtoYgmrSG4Q== dependencies: type-detect "4.0.8" "@sinonjs/fake-timers@^6.0.1": version "6.0.1" - resolved "https://registry.yarnpkg.com/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz#293674fccb3262ac782c7aadfdeca86b10c75c40" + resolved "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-6.0.1.tgz" integrity sha512-MZPUxrmFubI36XS1DI3qmI0YdN1gks62JtFZvxR67ljjSNCeK6U08Zx4msEWOXuofgqUt6zPHSi1H9fbjR/NRA== dependencies: "@sinonjs/commons" "^1.7.0" "@sitespeed.io/tracium@^0.3.3": version "0.3.3" - resolved "https://registry.yarnpkg.com/@sitespeed.io/tracium/-/tracium-0.3.3.tgz#b497a4a8d5837db1fd9e3053c99b78f6c0e1f53b" + resolved "https://registry.npmjs.org/@sitespeed.io/tracium/-/tracium-0.3.3.tgz" integrity sha512-dNZafjM93Y+F+sfwTO5gTpsGXlnc/0Q+c2+62ViqP3gkMWvHEMSKkaEHgVJLcLg3i/g19GSIPziiKpgyne07Bw== dependencies: debug "^4.1.1" "@size-limit/file@5.0.3": version "5.0.3" - resolved "https://registry.yarnpkg.com/@size-limit/file/-/file-5.0.3.tgz#6b12240f4880e25736534542168ffd064a8e386f" + resolved "https://registry.npmjs.org/@size-limit/file/-/file-5.0.3.tgz" integrity sha512-tkxf5ntFdlZ1xHQAw4fYd+gIkH85S2D3Wb94upJhtOfPHwDsQoQycDFGQRwTgei07Eq5vA8Jj5f2mu/tAdoaXw== dependencies: semver "7.3.5" "@size-limit/preset-big-lib@^5.0.3": version "5.0.3" - resolved "https://registry.yarnpkg.com/@size-limit/preset-big-lib/-/preset-big-lib-5.0.3.tgz#c72e8461a118693d536fefb07d406910cdc8c8e0" + resolved "https://registry.npmjs.org/@size-limit/preset-big-lib/-/preset-big-lib-5.0.3.tgz" integrity sha512-/bI/Q8NVUdzRgjNFgksS5do9UCW1Tklwk6LZvhib0ofiu+Qwl7R5s1fdhQiGzBUqbA27qC+S0+CbseYsRjr/Ug== dependencies: "@size-limit/file" "5.0.3" @@ -2212,7 +600,7 @@ "@size-limit/time@5.0.3": version "5.0.3" - resolved "https://registry.yarnpkg.com/@size-limit/time/-/time-5.0.3.tgz#86c242ae0e590e02241a54cb4ea8863182072612" + resolved "https://registry.npmjs.org/@size-limit/time/-/time-5.0.3.tgz" integrity sha512-BGBR38hPPwlHRwa+p+yVDXZYdmyLZ8DT0InMBlnbrAa/FthF34zeccIAx7lh4NGp+8rntxT3VOL59PpcLn1fxQ== dependencies: estimo "^2.2.8" @@ -2220,7 +608,7 @@ "@size-limit/webpack@5.0.3": version "5.0.3" - resolved "https://registry.yarnpkg.com/@size-limit/webpack/-/webpack-5.0.3.tgz#d5d72ca9b0ac9f3642794aa8412c9fd7d553a4ce" + resolved "https://registry.npmjs.org/@size-limit/webpack/-/webpack-5.0.3.tgz" integrity sha512-G8UutozNS3jfG2AyKdeHsYeYJ0jXBfHdzzhVUi1zuv6B+HvCDExE0cnbnIAhLyGNp1uTY/miOHLyCKQsxold/g== dependencies: css-loader "^5.2.6" @@ -2236,17 +624,17 @@ "@tootallnate/once@1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@tootallnate/once/-/once-1.1.2.tgz#ccb91445360179a04e7fe6aff78c00ffc1eeaf82" + resolved "https://registry.npmjs.org/@tootallnate/once/-/once-1.1.2.tgz" integrity sha512-RbzJvlNzmRq5c3O09UipeuXno4tA1FE6ikOjxZK0tuxVv3412l64l5t1W5pj4+rJq9vpkm/kwiR07aZXnsKPxw== "@trysound/sax@0.2.0": version "0.2.0" - resolved "https://registry.yarnpkg.com/@trysound/sax/-/sax-0.2.0.tgz#cccaab758af56761eb7bf37af6f03f326dd798ad" + resolved "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz" integrity sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA== "@types/babel__core@^7.0.0", "@types/babel__core@^7.1.7": version "7.1.9" - resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.9.tgz#77e59d438522a6fb898fa43dc3455c6e72f3963d" + resolved "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.1.9.tgz" integrity sha512-sY2RsIJ5rpER1u3/aQ8OFSI7qGIy8o1NEEbgb2UaJcvOtXOMpd39ko723NBpjQFg9SIX7TXtjejZVGeIMLhoOw== dependencies: "@babel/parser" "^7.1.0" @@ -2257,14 +645,14 @@ "@types/babel__generator@*": version "7.6.1" - resolved "https://registry.yarnpkg.com/@types/babel__generator/-/babel__generator-7.6.1.tgz#4901767b397e8711aeb99df8d396d7ba7b7f0e04" + resolved "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.1.tgz" integrity sha512-bBKm+2VPJcMRVwNhxKu8W+5/zT7pwNEqeokFOmbvVSqGzFneNxYcEBro9Ac7/N9tlsaPYnZLK8J1LWKkMsLAew== dependencies: "@babel/types" "^7.0.0" "@types/babel__template@*": version "7.0.2" - resolved "https://registry.yarnpkg.com/@types/babel__template/-/babel__template-7.0.2.tgz#4ff63d6b52eddac1de7b975a5223ed32ecea9307" + resolved "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.0.2.tgz" integrity sha512-/K6zCpeW7Imzgab2bLkLEbz0+1JlFSrUMdw7KoIIu+IUdu51GWaBZpd3y1VXGVXzynvGa4DaIaxNZHiON3GXUg== dependencies: "@babel/parser" "^7.1.0" @@ -2272,51 +660,43 @@ "@types/babel__traverse@*", "@types/babel__traverse@^7.0.6": version "7.0.12" - resolved "https://registry.yarnpkg.com/@types/babel__traverse/-/babel__traverse-7.0.12.tgz#22f49a028e69465390f87bb103ebd61bd086b8f5" + resolved "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.0.12.tgz" integrity sha512-t4CoEokHTfcyfb4hUaF9oOHu9RmmNWnm1CP0YmMqOOfClKascOmvlEM736vlqeScuGvBDsHkf8R2INd4DWreQA== dependencies: "@babel/types" "^7.3.0" "@types/color-name@^1.1.1": version "1.1.1" - resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" + resolved "https://registry.npmjs.org/@types/color-name/-/color-name-1.1.1.tgz" integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== "@types/estree@0.0.39": version "0.0.39" - resolved "https://registry.yarnpkg.com/@types/estree/-/estree-0.0.39.tgz#e177e699ee1b8c22d23174caaa7422644389509f" + resolved "https://registry.npmjs.org/@types/estree/-/estree-0.0.39.tgz" integrity sha512-EYNwp3bU+98cpU4lAWYYL7Zz+2gryWH1qbdDTidVd6hkiR6weksdbMadyXKXNPEkQFhXM+hVO9ZygomHXp+AIw== -"@types/glob@^7.1.1": - version "7.1.4" - resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.4.tgz#ea59e21d2ee5c517914cb4bc8e4153b99e566672" - integrity sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA== - dependencies: - "@types/minimatch" "*" - "@types/node" "*" - "@types/graceful-fs@^4.1.2": version "4.1.3" - resolved "https://registry.yarnpkg.com/@types/graceful-fs/-/graceful-fs-4.1.3.tgz#039af35fe26bec35003e8d86d2ee9c586354348f" + resolved "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.3.tgz" integrity sha512-AiHRaEB50LQg0pZmm659vNBb9f4SJ0qrAnteuzhSeAUcJKxoYgEnprg/83kppCnc2zvtCKbdZry1a5pVY3lOTQ== dependencies: "@types/node" "*" "@types/istanbul-lib-coverage@*", "@types/istanbul-lib-coverage@^2.0.0", "@types/istanbul-lib-coverage@^2.0.1": version "2.0.3" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" + resolved "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz" integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== "@types/istanbul-lib-report@*": version "3.0.0" - resolved "https://registry.yarnpkg.com/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#c14c24f18ea8190c118ee7562b7ff99a36552686" + resolved "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" integrity sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg== dependencies: "@types/istanbul-lib-coverage" "*" "@types/istanbul-reports@^1.1.1": version "1.1.2" - resolved "https://registry.yarnpkg.com/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz#e875cc689e47bce549ec81f3df5e6f6f11cfaeb2" + resolved "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-1.1.2.tgz" integrity sha512-P/W9yOX/3oPZSpaYOCQzGqgCQRXn0FFO/V8bWrCQs+wLmvVVxk6CRBXALEvNs9OHIatlnlFokfhuDo2ug01ciw== dependencies: "@types/istanbul-lib-coverage" "*" @@ -2324,7 +704,7 @@ "@types/jest@^26.0.3": version "26.0.3" - resolved "https://registry.yarnpkg.com/@types/jest/-/jest-26.0.3.tgz#79534e0e94857171c0edc596db0ebe7cb7863251" + resolved "https://registry.npmjs.org/@types/jest/-/jest-26.0.3.tgz" integrity sha512-v89ga1clpVL/Y1+YI0eIu1VMW+KU7Xl8PhylVtDKVWaSUHBHYPLXMQGBdrpHewaKoTvlXkksbYqPgz8b4cmRZg== dependencies: jest-diff "^25.2.1" @@ -2332,78 +712,68 @@ "@types/json-schema@^7.0.8": version "7.0.9" - resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.9.tgz#97edc9037ea0c38585320b28964dde3b39e4660d" + resolved "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz" integrity sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ== -"@types/minimatch@*", "@types/minimatch@3.0.3", "@types/minimatch@^3.0.3": +"@types/minimatch@3.0.3": version "3.0.3" - resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" + resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz" integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== -"@types/minimist@^1.2.0": - version "1.2.2" - resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.2.tgz#ee771e2ba4b3dc5b372935d549fd9617bf345b8c" - integrity sha512-jhuKLIRrhvCPLqwPcx6INqmKeiA5EWrsCOPhrlFSrbrmU4ZMPjj5Ul/oLCMDO98XRUIwVm78xICz4EPCektzeQ== - -"@types/node@*", "@types/node@>= 8", "@types/node@^16.9.2": - version "16.9.2" - resolved "https://registry.yarnpkg.com/@types/node/-/node-16.9.2.tgz#81f5a039d6ed1941f8cc57506c74e7c2b8fc64b9" - integrity sha512-ZHty/hKoOLZvSz6BtP1g7tc7nUeJhoCf3flLjh8ZEv1vFKBWHXcnMbJMyN/pftSljNyy0kNW/UqI3DccnBnZ8w== - -"@types/node@^12.0.2": +"@types/node@*", "@types/node@^12.0.2": version "12.20.25" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.20.25.tgz#882bea2ca0d2ec22126b92b4dd2dc24b35a07469" + resolved "https://registry.npmjs.org/@types/node/-/node-12.20.25.tgz" integrity sha512-hcTWqk7DR/HrN9Xe7AlJwuCaL13Vcd9/g/T54YrJz4Q3ESM5mr33YCzW2bOfzSIc3aZMeGBvbLGvgN6mIJ0I5Q== "@types/normalize-package-data@^2.4.0": version "2.4.0" - resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" + resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz" integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA== "@types/parse-json@^4.0.0": version "4.0.0" - resolved "https://registry.yarnpkg.com/@types/parse-json/-/parse-json-4.0.0.tgz#2f8bb441434d163b35fb8ffdccd7138927ffb8c0" + resolved "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz" integrity sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA== "@types/prettier@^2.0.0": version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/prettier/-/prettier-2.0.1.tgz#b6e98083f13faa1e5231bfa3bdb1b0feff536b6d" + resolved "https://registry.npmjs.org/@types/prettier/-/prettier-2.0.1.tgz" integrity sha512-boy4xPNEtiw6N3abRhBi/e7hNvy3Tt8E9ZRAQrwAGzoCGZS/1wjo9KY7JHhnfnEsG5wSjDbymCozUM9a3ea7OQ== "@types/resolve@0.0.8": version "0.0.8" - resolved "https://registry.yarnpkg.com/@types/resolve/-/resolve-0.0.8.tgz#f26074d238e02659e323ce1a13d041eee280e194" + resolved "https://registry.npmjs.org/@types/resolve/-/resolve-0.0.8.tgz" integrity sha512-auApPaJf3NPfe18hSoJkp8EbZzer2ISk7o8mCC3M9he/a04+gbMF97NkpD2S8riMGvm4BMRI59/SZQSaLTKpsQ== dependencies: "@types/node" "*" "@types/stack-utils@^1.0.1": version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/stack-utils/-/stack-utils-1.0.1.tgz#0a851d3bd96498fa25c33ab7278ed3bd65f06c3e" + resolved "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-1.0.1.tgz" integrity sha512-l42BggppR6zLmpfU6fq9HEa2oGPEI8yrSPL3GITjfRInppYFahObbIQOQK3UGxEnyQpltZLaPe75046NOZQikw== "@types/yargs-parser@*": version "15.0.0" - resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" + resolved "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-15.0.0.tgz" integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== "@types/yargs@^15.0.0": version "15.0.5" - resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.5.tgz#947e9a6561483bdee9adffc983e91a6902af8b79" + resolved "https://registry.npmjs.org/@types/yargs/-/yargs-15.0.5.tgz" integrity sha512-Dk/IDOPtOgubt/IaevIUbTgV7doaKkoorvOyYM2CMwuDyP89bekI7H4xLIwunNYiK9jhCkmc6pUrJk3cj2AB9w== dependencies: "@types/yargs-parser" "*" "@types/yauzl@^2.9.1": version "2.9.2" - resolved "https://registry.yarnpkg.com/@types/yauzl/-/yauzl-2.9.2.tgz#c48e5d56aff1444409e39fa164b0b4d4552a7b7a" + resolved "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.9.2.tgz" integrity sha512-8uALY5LTvSuHgloDVUvWP3pIauILm+8/0pDMokuDYIoNsOkSwd5AiHBTSEJjKTDcZr5z8UpgOWZkxBF4iJftoA== dependencies: "@types/node" "*" "@webassemblyjs/ast@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ast/-/ast-1.9.0.tgz#bd850604b4042459a5a41cd7d338cbed695ed964" + resolved "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.9.0.tgz" integrity sha512-C6wW5L+b7ogSDVqymbkkvuW9kruN//YisMED04xzeBBqjHa2FYnmvOlS6Xj68xWQRgWvI9cIglsjFowH/RJyEA== dependencies: "@webassemblyjs/helper-module-context" "1.9.0" @@ -2412,46 +782,46 @@ "@webassemblyjs/floating-point-hex-parser@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz#3c3d3b271bddfc84deb00f71344438311d52ffb4" + resolved "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.9.0.tgz" integrity sha512-TG5qcFsS8QB4g4MhrxK5TqfdNe7Ey/7YL/xN+36rRjl/BlGE/NcBvJcqsRgCP6Z92mRE+7N50pRIi8SmKUbcQA== "@webassemblyjs/helper-api-error@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz#203f676e333b96c9da2eeab3ccef33c45928b6a2" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.9.0.tgz" integrity sha512-NcMLjoFMXpsASZFxJ5h2HZRcEhDkvnNFOAKneP5RbKRzaWJN36NC4jqQHKwStIhGXu5mUWlUUk7ygdtrO8lbmw== "@webassemblyjs/helper-buffer@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz#a1442d269c5feb23fcbc9ef759dac3547f29de00" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.9.0.tgz" integrity sha512-qZol43oqhq6yBPx7YM3m9Bv7WMV9Eevj6kMi6InKOuZxhw+q9hOkvq5e/PpKSiLfyetpaBnogSbNCfBwyB00CA== "@webassemblyjs/helper-code-frame@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz#647f8892cd2043a82ac0c8c5e75c36f1d9159f27" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.9.0.tgz" integrity sha512-ERCYdJBkD9Vu4vtjUYe8LZruWuNIToYq/ME22igL+2vj2dQ2OOujIZr3MEFvfEaqKoVqpsFKAGsRdBSBjrIvZA== dependencies: "@webassemblyjs/wast-printer" "1.9.0" "@webassemblyjs/helper-fsm@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz#c05256b71244214671f4b08ec108ad63b70eddb8" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.9.0.tgz" integrity sha512-OPRowhGbshCb5PxJ8LocpdX9Kl0uB4XsAjl6jH/dWKlk/mzsANvhwbiULsaiqT5GZGT9qinTICdj6PLuM5gslw== "@webassemblyjs/helper-module-context@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz#25d8884b76839871a08a6c6f806c3979ef712f07" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.9.0.tgz" integrity sha512-MJCW8iGC08tMk2enck1aPW+BE5Cw8/7ph/VGZxwyvGbJwjktKkDK7vy7gAmMDx88D7mhDTCNKAW5tED+gZ0W8g== dependencies: "@webassemblyjs/ast" "1.9.0" "@webassemblyjs/helper-wasm-bytecode@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz#4fed8beac9b8c14f8c58b70d124d549dd1fe5790" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.9.0.tgz" integrity sha512-R7FStIzyNcd7xKxCZH5lE0Bqy+hGTwS3LJjuv1ZVxd9O7eHCedSdrId/hMOd20I+v8wDXEn+bjfKDLzTepoaUw== "@webassemblyjs/helper-wasm-section@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz#5a4138d5a6292ba18b04c5ae49717e4167965346" + resolved "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.9.0.tgz" integrity sha512-XnMB8l3ek4tvrKUUku+IVaXNHz2YsJyOOmz+MMkZvh8h1uSJpSen6vYnw3IoQ7WwEuAhL8Efjms1ZWjqh2agvw== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2461,26 +831,26 @@ "@webassemblyjs/ieee754@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz#15c7a0fbaae83fb26143bbacf6d6df1702ad39e4" + resolved "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.9.0.tgz" integrity sha512-dcX8JuYU/gvymzIHc9DgxTzUUTLexWwt8uCTWP3otys596io0L5aW02Gb1RjYpx2+0Jus1h4ZFqjla7umFniTg== dependencies: "@xtuc/ieee754" "^1.2.0" "@webassemblyjs/leb128@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/leb128/-/leb128-1.9.0.tgz#f19ca0b76a6dc55623a09cffa769e838fa1e1c95" + resolved "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.9.0.tgz" integrity sha512-ENVzM5VwV1ojs9jam6vPys97B/S65YQtv/aanqnU7D8aSoHFX8GyhGg0CMfyKNIHBuAVjy3tlzd5QMMINa7wpw== dependencies: "@xtuc/long" "4.2.2" "@webassemblyjs/utf8@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/utf8/-/utf8-1.9.0.tgz#04d33b636f78e6a6813227e82402f7637b6229ab" + resolved "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.9.0.tgz" integrity sha512-GZbQlWtopBTP0u7cHrEx+73yZKrQoBMpwkGEIqlacljhXCkVM1kMQge/Mf+csMJAjEdSwhOyLAS0AoR3AG5P8w== "@webassemblyjs/wasm-edit@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz#3fe6d79d3f0f922183aa86002c42dd256cfee9cf" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.9.0.tgz" integrity sha512-FgHzBm80uwz5M8WKnMTn6j/sVbqilPdQXTWraSjBwFXSYGirpkSWE2R9Qvz9tNiTKQvoKILpCuTjBKzOIm0nxw== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2494,7 +864,7 @@ "@webassemblyjs/wasm-gen@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz#50bc70ec68ded8e2763b01a1418bf43491a7a49c" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.9.0.tgz" integrity sha512-cPE3o44YzOOHvlsb4+E9qSqjc9Qf9Na1OO/BHFy4OI91XDE14MjFN4lTMezzaIWdPqHnsTodGGNP+iRSYfGkjA== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2505,7 +875,7 @@ "@webassemblyjs/wasm-opt@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz#2211181e5b31326443cc8112eb9f0b9028721a61" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.9.0.tgz" integrity sha512-Qkjgm6Anhm+OMbIL0iokO7meajkzQD71ioelnfPEj6r4eOFuqm4YC3VBPqXjFyyNwowzbMD+hizmprP/Fwkl2A== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2515,7 +885,7 @@ "@webassemblyjs/wasm-parser@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz#9d48e44826df4a6598294aa6c87469d642fff65e" + resolved "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.9.0.tgz" integrity sha512-9+wkMowR2AmdSWQzsPEjFU7njh8HTO5MqO8vjwEHuM+AMHioNqSBONRdr0NQQ3dVQrzp0s8lTcYqzUdb7YgELA== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2527,7 +897,7 @@ "@webassemblyjs/wast-parser@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz#3031115d79ac5bd261556cecc3fa90a3ef451914" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.9.0.tgz" integrity sha512-qsqSAP3QQ3LyZjNC/0jBJ/ToSxfYJ8kYyuiGvtn/8MK89VrNEfwj7BPQzJVHi0jGTRK2dGdJ5PRqhtjzoww+bw== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2539,7 +909,7 @@ "@webassemblyjs/wast-printer@1.9.0": version "1.9.0" - resolved "https://registry.yarnpkg.com/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz#4935d54c85fef637b00ce9f52377451d00d47899" + resolved "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.9.0.tgz" integrity sha512-2J0nE95rHXHyQ24cWjMKJ1tqB/ds8z/cyeOZxJhcb+rW+SQASVjuznUSmdz5GpVJTzU8JkhYut0D3siFDD6wsA== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -2548,49 +918,32 @@ "@xtuc/ieee754@^1.2.0": version "1.2.0" - resolved "https://registry.yarnpkg.com/@xtuc/ieee754/-/ieee754-1.2.0.tgz#eef014a3145ae477a1cbc00cd1e552336dceb790" + resolved "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz" integrity sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA== "@xtuc/long@4.2.2": version "4.2.2" - resolved "https://registry.yarnpkg.com/@xtuc/long/-/long-4.2.2.tgz#d291c6a4e97989b5c61d9acf396ae4fe133a718d" + resolved "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz" integrity sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ== "@yarnpkg/lockfile@^1.1.0": version "1.1.0" - resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" + resolved "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz" integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== -"@zkochan/cmd-shim@^3.1.0": - version "3.1.0" - resolved "https://registry.yarnpkg.com/@zkochan/cmd-shim/-/cmd-shim-3.1.0.tgz#2ab8ed81f5bb5452a85f25758eb9b8681982fd2e" - integrity sha512-o8l0+x7C7sMZU3v9GuJIAU10qQLtwR1dtRQIOmlNMtyaqhmpXOzx1HWiYoWfmmf9HHZoAkXpc9TM9PQYF9d4Jg== - dependencies: - is-windows "^1.0.0" - mkdirp-promise "^5.0.1" - mz "^2.5.0" - -JSONStream@^1.0.4, JSONStream@^1.3.4: - version "1.3.5" - resolved "https://registry.yarnpkg.com/JSONStream/-/JSONStream-1.3.5.tgz#3208c1f08d3a4d99261ab64f92302bc15e111ca0" - integrity sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ== - dependencies: - jsonparse "^1.2.0" - through ">=2.2.7 <3" - abab@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/abab/-/abab-2.0.3.tgz#623e2075e02eb2d3f2475e49f99c91846467907a" + resolved "https://registry.npmjs.org/abab/-/abab-2.0.3.tgz" integrity sha512-tsFzPpcttalNjFBCFMqsKYQcWxxen1pgJR56by//QwvJc4/OUS3kPOOttx2tSIfjsylB0pYu7f5D3K1RCxUnUg== abbrev@1: version "1.1.1" - resolved "https://registry.yarnpkg.com/abbrev/-/abbrev-1.1.1.tgz#f8f2c887ad10bf67f634f005b6987fed3179aac8" + resolved "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz" integrity sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q== acorn-globals@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/acorn-globals/-/acorn-globals-6.0.0.tgz#46cdd39f0f8ff08a876619b55f5ac8a6dc770b45" + resolved "https://registry.npmjs.org/acorn-globals/-/acorn-globals-6.0.0.tgz" integrity sha512-ZQl7LOWaF5ePqqcX4hLuv/bLXYQNfNWw2c0/yX/TsPRKamzHcTGQnlCjHT3TsmkOUVEPS3crCxiPfdzE/Trlhg== dependencies: acorn "^7.1.1" @@ -2598,65 +951,39 @@ acorn-globals@^6.0.0: acorn-walk@^7.1.1: version "7.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-7.2.0.tgz#0de889a601203909b0fbe07b8938dc21d2e967bc" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz" integrity sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA== acorn-walk@^8.0.0: version "8.2.0" - resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1" + resolved "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz" integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA== acorn@^6.4.1: version "6.4.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.1.tgz#531e58ba3f51b9dacb9a6646ca4debf5b14ca474" + resolved "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz" integrity sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA== acorn@^7.1.1: version "7.3.1" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-7.3.1.tgz#85010754db53c3fbaf3b9ea3e083aa5c5d147ffd" + resolved "https://registry.npmjs.org/acorn/-/acorn-7.3.1.tgz" integrity sha512-tLc0wSnatxAQHVHUapaHdz72pi9KUyHjq5KyHjGg9Y8Ifdc79pTh2XvI6I1/chZbnM7QtNKzh66ooDogPZSleA== acorn@^8.0.4: version "8.5.0" - resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.5.0.tgz#4512ccb99b3698c752591e9bb4472e38ad43cee2" + resolved "https://registry.npmjs.org/acorn/-/acorn-8.5.0.tgz" integrity sha512-yXbYeFy+jUuYd3/CDcg2NkIYE991XYX/bje7LmjJigUciaeO1JR4XxXgCIV1/Zc/dRuFEyw1L0pbA+qynJkW5Q== -add-stream@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" - integrity sha1-anmQQ3ynNtXhKI25K9MmbV9csqo= - -agent-base@4, agent-base@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee" - integrity sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg== - dependencies: - es6-promisify "^5.0.0" - agent-base@6, agent-base@^6.0.2: version "6.0.2" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-6.0.2.tgz#49fff58577cfee3f37176feab4c22e00f86d7f77" + resolved "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz" integrity sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ== dependencies: debug "4" -agent-base@~4.2.1: - version "4.2.1" - resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.2.1.tgz#d89e5999f797875674c07d87f260fc41e83e8ca9" - integrity sha512-JVwXMr9nHYTUXsBFKUqhJwvlcYU/blreOEUkhNR2eXZIvwd+c+o5V4MgDPKWnMS/56awN3TRzIP+KoPn+roQtg== - dependencies: - es6-promisify "^5.0.0" - -agentkeepalive@^3.4.1: - version "3.5.2" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-3.5.2.tgz#a113924dd3fa24a0bc3b78108c450c2abee00f67" - integrity sha512-e0L/HNe6qkQ7H19kTlRRqUibEAwDK5AFk6y3PtMsuut2VAH6+Q4xZml1tNDJD7kSAyqmbG/K08K5WEJYtUrSlQ== - dependencies: - humanize-ms "^1.2.1" - -agentkeepalive@^4.1.0, agentkeepalive@^4.1.3: +agentkeepalive@^4.1.3: version "4.1.4" - resolved "https://registry.yarnpkg.com/agentkeepalive/-/agentkeepalive-4.1.4.tgz#d928028a4862cb11718e55227872e842a44c945b" + resolved "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.1.4.tgz" integrity sha512-+V/rGa3EuU74H6wR04plBb7Ks10FbtUQgRj/FQOG7uUIEuaINI+AiqJR1k6t3SVNs7o7ZjIdus6706qqzVq8jQ== dependencies: debug "^4.1.0" @@ -2665,7 +992,7 @@ agentkeepalive@^4.1.0, agentkeepalive@^4.1.3: aggregate-error@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/aggregate-error/-/aggregate-error-3.1.0.tgz#92670ff50f5359bdb7a3e0d40d0ec30c5737687a" + resolved "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz" integrity sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA== dependencies: clean-stack "^2.0.0" @@ -2673,17 +1000,17 @@ aggregate-error@^3.0.0: ajv-errors@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/ajv-errors/-/ajv-errors-1.0.1.tgz#f35986aceb91afadec4102fbd85014950cefa64d" + resolved "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz" integrity sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ== ajv-keywords@^3.1.0, ajv-keywords@^3.4.1, ajv-keywords@^3.5.2: version "3.5.2" - resolved "https://registry.yarnpkg.com/ajv-keywords/-/ajv-keywords-3.5.2.tgz#31f29da5ab6e00d1c2d329acf7b5929614d5014d" + resolved "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz" integrity sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ== ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.5, ajv@^6.5.5: version "6.12.6" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4" + resolved "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz" integrity sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g== dependencies: fast-deep-equal "^3.1.1" @@ -2693,76 +1020,61 @@ ajv@^6.1.0, ajv@^6.10.2, ajv@^6.12.5, ajv@^6.5.5: alphanum-sort@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/alphanum-sort/-/alphanum-sort-1.0.2.tgz#97a1119649b211ad33691d9f9f486a8ec9fbe0a3" + resolved "https://registry.npmjs.org/alphanum-sort/-/alphanum-sort-1.0.2.tgz" integrity sha1-l6ERlkmyEa0zaR2fn0hqjsn74KM= ansi-align@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-align/-/ansi-align-3.0.0.tgz#b536b371cf687caaef236c18d3e21fe3797467cb" + resolved "https://registry.npmjs.org/ansi-align/-/ansi-align-3.0.0.tgz" integrity sha512-ZpClVKqXN3RGBmKibdfWzqCY4lnjEuoNzU5T0oEFpfd/z5qJHVarukridD4juLO2FXMiwUQxr9WqQtaYa8XRYw== dependencies: string-width "^3.0.0" ansi-colors@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/ansi-colors/-/ansi-colors-4.1.1.tgz#cbb9ae256bf750af1eab344f229aa27fe94ba348" + resolved "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz" integrity sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA== -ansi-escapes@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-3.2.0.tgz#8780b98ff9dbf5638152d1f1fe5c1d7b4442976b" - integrity sha512-cBhpre4ma+U0T1oM5fXg7Dy1Jw7zzwv7lt/GoCpr+hDQJoYnKVPLL4dCvSEFMmQurOQvSrwT7SL/DAlhBI97RQ== - ansi-escapes@^4.2.1, ansi-escapes@^4.3.0: version "4.3.1" - resolved "https://registry.yarnpkg.com/ansi-escapes/-/ansi-escapes-4.3.1.tgz#a5c47cc43181f1f38ffd7076837700d395522a61" + resolved "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz" integrity sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA== dependencies: type-fest "^0.11.0" ansi-regex@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-2.1.1.tgz#c3b33ab5ee360d86e0e628f0468ae7ef27d654df" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz" integrity sha1-w7M6te42DYbg5ijwRorn7yfWVN8= -ansi-regex@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-3.0.0.tgz#ed0317c322064f79466c02966bddb605ab37d998" - integrity sha1-7QMXwyIGT3lGbAKWa922Bas32Zg= - ansi-regex@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-4.1.0.tgz#8b9f8f08cf1acb843756a839ca8c7e3168c51997" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.0.tgz" integrity sha512-1apePfXM1UOSqw0o9IiFAovVz9M5S1Dg+4TrDwfMewQ6p/rmMueb7tWZjQ1rx4Loy1ArBggoqGpfqqdI4rondg== ansi-regex@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" + resolved "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz" integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== -ansi-styles@^3.2.0, ansi-styles@^3.2.1: +ansi-styles@^3.2.1: version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz" integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== dependencies: color-convert "^1.9.0" ansi-styles@^4.0.0, ansi-styles@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" + resolved "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.2.1.tgz" integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== dependencies: "@types/color-name" "^1.1.1" color-convert "^2.0.1" -any-promise@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/any-promise/-/any-promise-1.3.0.tgz#abc6afeedcea52e809cdc0376aed3ce39635d17f" - integrity sha1-q8av7tzqUugJzcA3au0845Y10X8= - anymatch@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-2.0.0.tgz#bcb24b4f37934d9aa7ac17b4adaf89e7c76ef2eb" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz" integrity sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw== dependencies: micromatch "^3.1.4" @@ -2770,7 +1082,7 @@ anymatch@^2.0.0: anymatch@^3.0.3, anymatch@~3.1.2: version "3.1.2" - resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.2.tgz#c0557c096af32f106198f4f4e2a383537e378716" + resolved "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz" integrity sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg== dependencies: normalize-path "^3.0.0" @@ -2778,17 +1090,12 @@ anymatch@^3.0.3, anymatch@~3.1.2: aproba@^1.0.3, aproba@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-1.2.0.tgz#6802e6264efd18c790a1b0d517f0f2627bf2c94a" + resolved "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz" integrity sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw== -aproba@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/aproba/-/aproba-2.0.0.tgz#52520b8ae5b569215b354efc0caa3fe1e45a8adc" - integrity sha512-lYe4Gx7QT+MKGbDsA+Z+he/Wtef0BiwDOlK/XkBrdfsh9J/jPPXbX0tE9x9cl27Tmu5gg3QUbUrQYa/y+KOHPQ== - are-we-there-yet@~1.1.2: version "1.1.5" - resolved "https://registry.yarnpkg.com/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz#4b35c2944f062a8bfcda66410760350fe9ddfc21" + resolved "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz" integrity sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w== dependencies: delegates "^1.0.0" @@ -2796,96 +1103,49 @@ are-we-there-yet@~1.1.2: arg@^4.1.0: version "4.1.1" - resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.1.tgz#485f8e7c390ce4c5f78257dbea80d4be11feda4c" + resolved "https://registry.npmjs.org/arg/-/arg-4.1.1.tgz" integrity sha512-SlmP3fEA88MBv0PypnXZ8ZfJhwmDeIE3SP71j37AiXQBXYosPV0x6uISAaHYSlSVhmHOVkomen0tbGk6Anlebw== argparse@^1.0.7: version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" + resolved "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz" integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== dependencies: sprintf-js "~1.0.2" argv@0.0.2: version "0.0.2" - resolved "https://registry.yarnpkg.com/argv/-/argv-0.0.2.tgz#ecbd16f8949b157183711b1bda334f37840185ab" + resolved "https://registry.npmjs.org/argv/-/argv-0.0.2.tgz" integrity sha1-7L0W+JSbFXGDcRsb2jNPN4QBhas= arr-diff@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" + resolved "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz" integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= arr-flatten@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" + resolved "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz" integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== arr-union@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" + resolved "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz" integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= -array-differ@^2.0.3: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-2.1.0.tgz#4b9c1c3f14b906757082925769e8ab904f4801b1" - integrity sha512-KbUpJgx909ZscOc/7CLATBFam7P1Z1QRQInvgT0UztM9Q72aGKCunKASAl7WNW0tnPmPyEMeMhdsfWhfmW037w== - -array-differ@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/array-differ/-/array-differ-3.0.0.tgz#3cbb3d0f316810eafcc47624734237d6aee4ae6b" - integrity sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg== - -array-find-index@^1.0.1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1" - integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E= - -array-ify@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/array-ify/-/array-ify-1.0.0.tgz#9e528762b4a9066ad163a6962a364418e9626ece" - integrity sha1-nlKHYrSpBmrRY6aWKjZEGOlibs4= - -array-union@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" - integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk= - dependencies: - array-uniq "^1.0.1" - array-union@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" + resolved "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== -array-uniq@^1.0.1: - version "1.0.3" - resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6" - integrity sha1-r2rId6Jcx/dOBYiUdThY39sk/bY= - array-unique@^0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" + resolved "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz" integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= -arrify@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" - integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= - -arrify@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/arrify/-/arrify-2.0.1.tgz#c9655e9331e0abcd588d2a7cad7e9956f66701fa" - integrity sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug== - -asap@^2.0.0: - version "2.0.6" - resolved "https://registry.yarnpkg.com/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" - integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= - asn1.js@^4.0.0: version "4.10.1" - resolved "https://registry.yarnpkg.com/asn1.js/-/asn1.js-4.10.1.tgz#b9c2bf5805f1e64aadeed6df3a2bfafb5a73f5a0" + resolved "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz" integrity sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw== dependencies: bn.js "^4.0.0" @@ -2894,19 +1154,19 @@ asn1.js@^4.0.0: asn1@~0.2.3: version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" + resolved "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz" integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== dependencies: safer-buffer "~2.1.0" assert-plus@1.0.0, assert-plus@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" + resolved "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz" integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= assert@^1.1.1: version "1.5.0" - resolved "https://registry.yarnpkg.com/assert/-/assert-1.5.0.tgz#55c109aaf6e0aefdb3dc4b71240c70bf574b18eb" + resolved "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz" integrity sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA== dependencies: object-assign "^4.1.1" @@ -2914,52 +1174,42 @@ assert@^1.1.1: assign-symbols@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" + resolved "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz" integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= astral-regex@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/astral-regex/-/astral-regex-2.0.0.tgz#483143c567aeed4785759c0865786dc77d7d2e31" + resolved "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz" integrity sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ== async-each@^1.0.1: version "1.0.3" - resolved "https://registry.yarnpkg.com/async-each/-/async-each-1.0.3.tgz#b727dbf87d7651602f06f4d4ac387f47d91b0cbf" + resolved "https://registry.npmjs.org/async-each/-/async-each-1.0.3.tgz" integrity sha512-z/WhQ5FPySLdvREByI2vZiTWwCnF0moMJ1hK9YQwDTHKh6I7/uSckMetoRGb5UBZPC1z0jlw+n/XCgjeH7y1AQ== asynckit@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" + resolved "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz" integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= -at-least-node@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/at-least-node/-/at-least-node-1.0.0.tgz#602cd4b46e844ad4effc92a8011a3c46e0238dc2" - integrity sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg== - -atob-lite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/atob-lite/-/atob-lite-2.0.0.tgz#0fef5ad46f1bd7a8502c65727f0367d5ee43d696" - integrity sha1-D+9a1G8b16hQLGVyfwNn1e5D1pY= - atob@^2.1.2: version "2.1.2" - resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" + resolved "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz" integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== aws-sign2@~0.7.0: version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" + resolved "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz" integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= aws4@^1.8.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.10.0.tgz#a17b3a8ea811060e74d47d306122400ad4497ae2" + resolved "https://registry.npmjs.org/aws4/-/aws4-1.10.0.tgz" integrity sha512-3YDiu347mtVtjpyV3u5kVqQLP242c06zwDOgpeRnybmXlYYsLbtTrUBUm8i8srONt+FWobl5aibnU1030PeeuA== babel-jest@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-jest/-/babel-jest-26.1.0.tgz#b20751185fc7569a0f135730584044d1cb934328" + resolved "https://registry.npmjs.org/babel-jest/-/babel-jest-26.1.0.tgz" integrity sha512-Nkqgtfe7j6PxLO6TnCQQlkMm8wdTdnIF8xrdpooHCuD5hXRzVEPbPneTJKknH5Dsv3L8ip9unHDAp48YQ54Dkg== dependencies: "@jest/transform" "^26.1.0" @@ -2973,7 +1223,7 @@ babel-jest@^26.1.0: babel-plugin-istanbul@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz#e159ccdc9af95e0b570c75b4573b7c34d671d765" + resolved "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.0.0.tgz" integrity sha512-AF55rZXpe7trmEylbaE1Gv54wn6rwU03aptvRoVIGP8YykoSxqdVLV1TfwflBCE/QtHmqtP8SWlTENqbK8GCSQ== dependencies: "@babel/helper-plugin-utils" "^7.0.0" @@ -2984,7 +1234,7 @@ babel-plugin-istanbul@^6.0.0: babel-plugin-jest-hoist@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.1.0.tgz#c6a774da08247a28285620a64dfadbd05dd5233a" + resolved "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-26.1.0.tgz" integrity sha512-qhqLVkkSlqmC83bdMhM8WW4Z9tB+JkjqAqlbbohS9sJLT5Ha2vfzuKqg5yenXrAjOPG2YC0WiXdH3a9PvB+YYw== dependencies: "@babel/template" "^7.3.3" @@ -2994,7 +1244,7 @@ babel-plugin-jest-hoist@^26.1.0: babel-preset-current-node-syntax@^0.1.2: version "0.1.3" - resolved "https://registry.yarnpkg.com/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz#b4b547acddbf963cba555ba9f9cbbb70bfd044da" + resolved "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-0.1.3.tgz" integrity sha512-uyexu1sVwcdFnyq9o8UQYsXwXflIh8LvrF5+cKrYam93ned1CStffB3+BEcsxGSgagoA3GEyjDqO4a/58hyPYQ== dependencies: "@babel/plugin-syntax-async-generators" "^7.8.4" @@ -3011,7 +1261,7 @@ babel-preset-current-node-syntax@^0.1.2: babel-preset-jest@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/babel-preset-jest/-/babel-preset-jest-26.1.0.tgz#612f714e5b457394acfd863793c564cbcdb7d1c1" + resolved "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-26.1.0.tgz" integrity sha512-na9qCqFksknlEj5iSdw1ehMVR06LCCTkZLGKeEtxDDdhg8xpUF09m29Kvh1pRbZ07h7AQ5ttLYUwpXL4tO6w7w== dependencies: babel-plugin-jest-hoist "^26.1.0" @@ -3019,24 +1269,24 @@ babel-preset-jest@^26.1.0: backbone@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/backbone/-/backbone-1.4.0.tgz#54db4de9df7c3811c3f032f34749a4cd27f3bd12" + resolved "https://registry.npmjs.org/backbone/-/backbone-1.4.0.tgz" integrity sha512-RLmDrRXkVdouTg38jcgHhyQ/2zjg7a8E6sz2zxfz21Hh17xDJYUHBZimVIt5fUyS8vbfpeSmTL3gUjTEvUV3qQ== dependencies: underscore ">=1.8.3" balanced-match@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" + resolved "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz" integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= base64-js@^1.0.2, base64-js@^1.3.1: version "1.5.1" - resolved "https://registry.yarnpkg.com/base64-js/-/base64-js-1.5.1.tgz#1b1b440160a5bf7ad40b650f095963481903930a" + resolved "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz" integrity sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA== base@^0.11.1: version "0.11.2" - resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" + resolved "https://registry.npmjs.org/base/-/base-0.11.2.tgz" integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== dependencies: cache-base "^1.0.1" @@ -3049,58 +1299,53 @@ base@^0.11.1: bcrypt-pbkdf@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" + resolved "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz" integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= dependencies: tweetnacl "^0.14.3" -before-after-hook@^2.0.0, before-after-hook@^2.2.0: - version "2.2.2" - resolved "https://registry.yarnpkg.com/before-after-hook/-/before-after-hook-2.2.2.tgz#a6e8ca41028d90ee2c24222f201c90956091613e" - integrity sha512-3pZEU3NT5BFUo/AD5ERPWOgQOCZITni6iavr5AUw5AUwQjMlI0kzu5btnyD39AF0gUEsDPwJT+oY1ORBJijPjQ== - big.js@^5.2.2: version "5.2.2" - resolved "https://registry.yarnpkg.com/big.js/-/big.js-5.2.2.tgz#65f0af382f578bcdc742bd9c281e9cb2d7768328" + resolved "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz" integrity sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ== binary-extensions@^1.0.0: version "1.13.1" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.13.1.tgz#598afe54755b2868a5330d2aff9d4ebb53209b65" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.13.1.tgz" integrity sha512-Un7MIEDdUC5gNpcGDV97op1Ywk748MpHcFTHoYs6qnj1Z3j7I53VG3nwZhKzoBZmbdRNnb6WRdFlwl7tSDuZGw== binary-extensions@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.0.0.tgz#23c0df14f6a88077f5f986c0d167ec03c3d5537c" + resolved "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.0.0.tgz" integrity sha512-Phlt0plgpIIBOGTT/ehfFnbNlfsDEiqmzE2KRXoX1bLIlir4X/MR+zSyBEkL05ffWgnRSf/DXv+WrUAVr93/ow== -bl@^4.0.3, bl@^4.1.0: +bl@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/bl/-/bl-4.1.0.tgz#451535264182bec2fbbc83a62ab98cf11d9f7b3a" + resolved "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz" integrity sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w== dependencies: buffer "^5.5.0" inherits "^2.0.4" readable-stream "^3.4.0" -bluebird@^3.5.1, bluebird@^3.5.3, bluebird@^3.5.5: +bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bn.js@^4.0.0, bn.js@^4.1.0, bn.js@^4.1.1, bn.js@^4.4.0: version "4.11.9" - resolved "https://registry.yarnpkg.com/bn.js/-/bn.js-4.11.9.tgz#26d556829458f9d1e81fc48952493d0ba3507828" + resolved "https://registry.npmjs.org/bn.js/-/bn.js-4.11.9.tgz" integrity sha512-E6QoYqCKZfgatHTdHzs1RRKP7ip4vvm+EyRUeE2RF0NblwVvb0p6jSVeNTOFxPn26QXN2o6SMfNxKp6kU8zQaw== boolbase@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e" + resolved "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz" integrity sha1-aN/1++YMUes3cl6p4+0xDcwed24= boxen@^5.0.0: version "5.1.2" - resolved "https://registry.yarnpkg.com/boxen/-/boxen-5.1.2.tgz#788cb686fc83c1f486dfa8a40c68fc2b831d2b50" + resolved "https://registry.npmjs.org/boxen/-/boxen-5.1.2.tgz" integrity sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ== dependencies: ansi-align "^3.0.0" @@ -3114,7 +1359,7 @@ boxen@^5.0.0: brace-expansion@^1.1.7: version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" + resolved "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz" integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== dependencies: balanced-match "^1.0.0" @@ -3122,7 +1367,7 @@ brace-expansion@^1.1.7: braces@^2.3.1, braces@^2.3.2: version "2.3.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" + resolved "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz" integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== dependencies: arr-flatten "^1.1.0" @@ -3138,31 +1383,31 @@ braces@^2.3.1, braces@^2.3.2: braces@^3.0.1, braces@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" + resolved "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== dependencies: fill-range "^7.0.1" brorand@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f" + resolved "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz" integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8= brotli-size@4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/brotli-size/-/brotli-size-4.0.0.tgz#a05ee3faad3c0e700a2f2da826ba6b4d76e69e5e" + resolved "https://registry.npmjs.org/brotli-size/-/brotli-size-4.0.0.tgz" integrity sha512-uA9fOtlTRC0iqKfzff1W34DXUA3GyVqbUaeo3Rw3d4gd1eavKVCETXrn3NzO74W+UVkG3UHu8WxUi+XvKI/huA== dependencies: duplexer "0.1.1" browser-process-hrtime@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626" + resolved "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz" integrity sha512-9o5UecI3GhkpM6DrXr69PblIuWxPKk9Y0jHBRhdocZ2y7YECBFCsHm79Pr3OyR2AvjhDkabFJaDJMYRazHgsow== browserify-aes@^1.0.0, browserify-aes@^1.0.4: version "1.2.0" - resolved "https://registry.yarnpkg.com/browserify-aes/-/browserify-aes-1.2.0.tgz#326734642f403dabc3003209853bb70ad428ef48" + resolved "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz" integrity sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA== dependencies: buffer-xor "^1.0.3" @@ -3174,7 +1419,7 @@ browserify-aes@^1.0.0, browserify-aes@^1.0.4: browserify-cipher@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/browserify-cipher/-/browserify-cipher-1.0.1.tgz#8d6474c1b870bfdabcd3bcfcc1934a10e94f15f0" + resolved "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz" integrity sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w== dependencies: browserify-aes "^1.0.4" @@ -3183,7 +1428,7 @@ browserify-cipher@^1.0.0: browserify-des@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/browserify-des/-/browserify-des-1.0.2.tgz#3af4f1f59839403572f1c66204375f7a7f703e9c" + resolved "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz" integrity sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A== dependencies: cipher-base "^1.0.1" @@ -3193,7 +1438,7 @@ browserify-des@^1.0.0: browserify-rsa@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/browserify-rsa/-/browserify-rsa-4.0.1.tgz#21e0abfaf6f2029cf2fafb133567a701d4135524" + resolved "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz" integrity sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ= dependencies: bn.js "^4.1.0" @@ -3201,7 +1446,7 @@ browserify-rsa@^4.0.0: browserify-sign@^4.0.0: version "4.0.4" - resolved "https://registry.yarnpkg.com/browserify-sign/-/browserify-sign-4.0.4.tgz#aa4eb68e5d7b658baa6bf6a57e630cbd7a93d298" + resolved "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz" integrity sha1-qk62jl17ZYuqa/alfmMMvXqT0pg= dependencies: bn.js "^4.1.1" @@ -3214,14 +1459,14 @@ browserify-sign@^4.0.0: browserify-zlib@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.2.0.tgz#2869459d9aa3be245fe8fe2ca1f46e2e7f54d73f" + resolved "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz" integrity sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA== dependencies: pako "~1.0.5" browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6: version "4.17.0" - resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.17.0.tgz#1fcd81ec75b41d6d4994fb0831b92ac18c01649c" + resolved "https://registry.npmjs.org/browserslist/-/browserslist-4.17.0.tgz" integrity sha512-g2BJ2a0nEYvEFQC208q8mVAhfNwpZ5Mu8BwgtCdZKO3qx98HChmeg448fPdUzld8aFmfLgVh7yymqV+q1lJZ5g== dependencies: caniuse-lite "^1.0.30001254" @@ -3232,41 +1477,36 @@ browserslist@^4.0.0, browserslist@^4.16.0, browserslist@^4.16.6: bs-logger@0.x: version "0.2.6" - resolved "https://registry.yarnpkg.com/bs-logger/-/bs-logger-0.2.6.tgz#eb7d365307a72cf974cc6cda76b68354ad336bd8" + resolved "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz" integrity sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog== dependencies: fast-json-stable-stringify "2.x" bser@2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/bser/-/bser-2.1.1.tgz#e6787da20ece9d07998533cfd9de6f5c38f4bc05" + resolved "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz" integrity sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ== dependencies: node-int64 "^0.4.0" -btoa-lite@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" - integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= - buffer-crc32@~0.2.3: version "0.2.13" - resolved "https://registry.yarnpkg.com/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" + resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" + resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== buffer-xor@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" + resolved "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz" integrity sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk= buffer@^4.3.0: version "4.9.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-4.9.1.tgz#6d1bb601b07a4efced97094132093027c95bc298" + resolved "https://registry.npmjs.org/buffer/-/buffer-4.9.1.tgz" integrity sha1-bRu2AbB6TvztlwlBMgkwJ8lbwpg= dependencies: base64-js "^1.0.2" @@ -3275,7 +1515,7 @@ buffer@^4.3.0: buffer@^5.2.1, buffer@^5.5.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/buffer/-/buffer-5.7.1.tgz#ba62e7c13133053582197160851a8f648e99eed0" + resolved "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz" integrity sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ== dependencies: base64-js "^1.3.1" @@ -3283,45 +1523,30 @@ buffer@^5.2.1, buffer@^5.5.0: builtin-modules@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz" integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= builtin-modules@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-3.1.0.tgz#aad97c15131eb76b65b50ef208e7584cd76a7484" + resolved "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.1.0.tgz" integrity sha512-k0KL0aWZuBt2lrxrcASWDfwOLMnodeQjodT/1SxEQAXsHANgo6ZC/VEaSEHCXt7aSTZ4/4H5LKa+tBXmW7Vtvw== builtin-status-codes@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz#85982878e21b98e1c66425e03d0174788f569ee8" + resolved "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz" integrity sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug= builtins@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/builtins/-/builtins-1.0.3.tgz#cb94faeb61c8696451db36534e1422f94f0aee88" + resolved "https://registry.npmjs.org/builtins/-/builtins-1.0.3.tgz" integrity sha1-y5T662HIaWRR2zZTThQi+U8K7og= -byline@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/byline/-/byline-5.0.0.tgz#741c5216468eadc457b03410118ad77de8c1ddb1" - integrity sha1-dBxSFkaOrcRXsDQQEYrXfejB3bE= - -byte-size@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-5.0.1.tgz#4b651039a5ecd96767e71a3d7ed380e48bed4191" - integrity sha512-/XuKeqWocKsYa/cBY1YbSJSWWqTi4cFgr9S6OyM7PBaPbr9zvNGwWP33vt0uqGhwDdN+y3yhbXVILEUpnwEWGw== - -byte-size@^7.0.0: - version "7.0.1" - resolved "https://registry.yarnpkg.com/byte-size/-/byte-size-7.0.1.tgz#b1daf3386de7ab9d706b941a748dbfc71130dee3" - integrity sha512-crQdqyCwhokxwV1UyDzLZanhkugAgft7vt0qbbdt60C6Zf3CAiGmtUCylbtYwrU6loOUw3euGrNtW1J651ot1A== - bytes-iec@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/bytes-iec/-/bytes-iec-3.1.1.tgz#94cd36bf95c2c22a82002c247df8772d1d591083" + resolved "https://registry.npmjs.org/bytes-iec/-/bytes-iec-3.1.1.tgz" integrity sha512-fey6+4jDK7TFtFg/klGSvNKJctyU7n2aQdnM+CO0ruLPbqqMOM8Tio0Pc+deqUeVKX1tL5DQep1zQ7+37aTAsA== -cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: +cacache@^12.0.2: version "12.0.4" resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.4.tgz#668bcbd105aeb5f1d92fe25570ec9525c8faa40c" integrity sha512-a0tMB40oefvuInr4Cwb3GerbL9xTj1D5yg0T5xrjGCGyfvbxseIXX7BAO/u/hIXdafzOI5JC3wDwHyf24buOAQ== @@ -3342,9 +1567,9 @@ cacache@^12.0.0, cacache@^12.0.2, cacache@^12.0.3: unique-filename "^1.1.1" y18n "^4.0.0" -cacache@^15.0.0, cacache@^15.0.5, cacache@^15.2.0: +cacache@^15.0.5, cacache@^15.2.0: version "15.3.0" - resolved "https://registry.yarnpkg.com/cacache/-/cacache-15.3.0.tgz#dc85380fb2f556fe3dda4c719bfa0ec875a7f1eb" + resolved "https://registry.npmjs.org/cacache/-/cacache-15.3.0.tgz" integrity sha512-VVdYzXEn+cnbXpFgWs5hTT7OScegHVmLhJIR8Ufqk3iFD6A6j5iSX1KuBTfNEv4tdJWE2PzA6IVFtcLC7fN9wQ== dependencies: "@npmcli/fs" "^1.0.0" @@ -3368,7 +1593,7 @@ cacache@^15.0.0, cacache@^15.0.5, cacache@^15.2.0: cache-base@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" + resolved "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz" integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== dependencies: collection-visit "^1.0.0" @@ -3381,84 +1606,24 @@ cache-base@^1.0.1: union-value "^1.0.0" unset-value "^1.0.0" -call-me-maybe@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" - integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= - -caller-callsite@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134" - integrity sha1-hH4PzgoiN1CpoCfFSzNzGtMVQTQ= - dependencies: - callsites "^2.0.0" - -caller-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/caller-path/-/caller-path-2.0.0.tgz#468f83044e369ab2010fac5f06ceee15bb2cb1f4" - integrity sha1-Ro+DBE42mrIBD6xfBs7uFbsssfQ= - dependencies: - caller-callsite "^2.0.0" - -callsites@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-2.0.0.tgz#06eb84f00eea413da86affefacbffb36093b3c50" - integrity sha1-BuuE8A7qQT2oav/vrL/7Ngk7PFA= - callsites@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" + resolved "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz" integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ== -camelcase-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-2.1.0.tgz#308beeaffdf28119051efa1d932213c91b8f92e7" - integrity sha1-MIvur/3ygRkFHvodkyITyRuPkuc= - dependencies: - camelcase "^2.0.0" - map-obj "^1.0.0" - -camelcase-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77" - integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c= - dependencies: - camelcase "^4.1.0" - map-obj "^2.0.0" - quick-lru "^1.0.0" - -camelcase-keys@^6.2.2: - version "6.2.2" - resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.2.2.tgz#5e755d6ba51aa223ec7d3d52f25778210f9dc3c0" - integrity sha512-YrwaA0vEKazPBkn0ipTiMpSajYDSe+KjQfrjhcBMxJt/znbvlHd8Pw/Vamaz5EB4Wfhs3SUR3Z9mwRu/P3s3Yg== - dependencies: - camelcase "^5.3.1" - map-obj "^4.0.0" - quick-lru "^4.0.1" - -camelcase@^2.0.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-2.1.1.tgz#7c1d16d679a1bbe59ca02cacecfb011e201f5a1f" - integrity sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8= - -camelcase@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-4.1.0.tgz#d545635be1e33c542649c69173e5de6acfae34dd" - integrity sha1-1UVjW+HjPFQmScaRc+Xeas+uNN0= - camelcase@^5.0.0, camelcase@^5.3.1: version "5.3.1" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz" integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== camelcase@^6.0.0, camelcase@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-6.2.0.tgz#924af881c9d525ac9d87f40d964e5cea982a1809" + resolved "https://registry.npmjs.org/camelcase/-/camelcase-6.2.0.tgz" integrity sha512-c7wVvbw3f37nuobQNtgsgG9POC9qMbNuMQmTCqZv23b6MIz0fcYpBiOlv9gEN/hdLdnZTDQhg6e9Dq5M1vKvfg== caniuse-api@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/caniuse-api/-/caniuse-api-3.0.0.tgz#5e4d90e2274961d46291997df599e3ed008ee4c0" + resolved "https://registry.npmjs.org/caniuse-api/-/caniuse-api-3.0.0.tgz" integrity sha512-bsTwuIg/BZZK/vreVTYYbSWoe2F+71P7K5QGEX+pT250DZbfU1MQ5prOKpPR+LL6uWKK3KMwMCAS74QB3Um1uw== dependencies: browserslist "^4.0.0" @@ -3468,24 +1633,24 @@ caniuse-api@^3.0.0: caniuse-lite@^1.0.0, caniuse-lite@^1.0.30001254: version "1.0.30001258" - resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz#b604eed80cc54a578e4bf5a02ae3ed49f869d252" + resolved "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001258.tgz" integrity sha512-RBByOG6xWXUp0CR2/WU2amXz3stjKpSl5J1xU49F1n2OxD//uBZO4wCKUiG+QMGf7CHGfDDcqoKriomoGVxTeA== capture-exit@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/capture-exit/-/capture-exit-2.0.0.tgz#fb953bfaebeb781f62898239dabb426d08a509a4" + resolved "https://registry.npmjs.org/capture-exit/-/capture-exit-2.0.0.tgz" integrity sha512-PiT/hQmTonHhl/HFGN+Lx3JJUznrVYJ3+AQsnthneZbvW7x+f08Tk7yLJTLEOUvBTbduLeeBkxEaYXUOUrRq6g== dependencies: rsvp "^4.8.4" caseless@~0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" + resolved "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= -chalk@^2.0.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.2: +chalk@^2.0.0, chalk@^2.3.0: version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" + resolved "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz" integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== dependencies: ansi-styles "^3.2.1" @@ -3494,7 +1659,7 @@ chalk@^2.0.0, chalk@^2.3.0, chalk@^2.3.1, chalk@^2.4.2: chalk@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-3.0.0.tgz#3f73c2bf526591f574cc492c51e2456349f844e4" + resolved "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz" integrity sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg== dependencies: ansi-styles "^4.1.0" @@ -3502,7 +1667,7 @@ chalk@^3.0.0: chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: version "4.1.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-4.1.2.tgz#aac4e2b7734a740867aeb16bf02aad556a1e7a01" + resolved "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz" integrity sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA== dependencies: ansi-styles "^4.1.0" @@ -3510,17 +1675,12 @@ chalk@^4.0.0, chalk@^4.1.0, chalk@^4.1.1: char-regex@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/char-regex/-/char-regex-1.0.2.tgz#d744358226217f981ed58f479b1d6bcc29545dcf" + resolved "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz" integrity sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw== -chardet@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/chardet/-/chardet-0.7.0.tgz#90094849f0937f2eedc2425d0d28a9e5f0cbad9e" - integrity sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA== - chokidar@^2.1.8: version "2.1.8" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-2.1.8.tgz" integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg== dependencies: anymatch "^2.0.0" @@ -3537,9 +1697,9 @@ chokidar@^2.1.8: optionalDependencies: fsevents "^1.2.7" -chokidar@^3.4.1, chokidar@^3.5.1, chokidar@^3.5.2: +chokidar@^3.4.1, chokidar@^3.5.2: version "3.5.2" - resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.5.2.tgz#dba3976fcadb016f66fd365021d91600d01c1e75" + resolved "https://registry.npmjs.org/chokidar/-/chokidar-3.5.2.tgz" integrity sha512-ekGhOnNVPgT77r4K/U3GDhu+FQ2S8TnK/s2KbIGXi0SZWuwkZ2QNyfWdZW+TVfn84DpEP7rLeCt2UI6bJ8GwbQ== dependencies: anymatch "~3.1.2" @@ -3552,36 +1712,36 @@ chokidar@^3.4.1, chokidar@^3.5.1, chokidar@^3.5.2: optionalDependencies: fsevents "~2.3.2" -chownr@^1.1.1, chownr@^1.1.2, chownr@^1.1.4: +chownr@^1.1.1, chownr@^1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" + resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== chownr@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/chownr/-/chownr-2.0.0.tgz#15bfbe53d2eab4cf70f18a8cd68ebe5b3cb1dece" + resolved "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz" integrity sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ== chrome-trace-event@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz#234090ee97c7d4ad1a2c4beae27505deffc608a4" + resolved "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz" integrity sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ== dependencies: tslib "^1.9.0" ci-info@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" + resolved "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz" integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== ci-job-number@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/ci-job-number/-/ci-job-number-1.2.2.tgz#f4e5918fcaeeda95b604f214be7d7d4a961fe0c0" + resolved "https://registry.npmjs.org/ci-job-number/-/ci-job-number-1.2.2.tgz" integrity sha512-CLOGsVDrVamzv8sXJGaILUVI6dsuAkouJP/n6t+OxLPeeA4DDby7zn9SB6EUpa1H7oIKoE+rMmkW80zYsFfUjA== cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/cipher-base/-/cipher-base-1.0.4.tgz#8760e4ecc272f4c363532f926d874aae2c1397de" + resolved "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz" integrity sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q== dependencies: inherits "^2.0.1" @@ -3589,7 +1749,7 @@ cipher-base@^1.0.0, cipher-base@^1.0.1, cipher-base@^1.0.3: class-utils@^0.3.5: version "0.3.6" - resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" + resolved "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz" integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== dependencies: arr-union "^3.1.0" @@ -3599,63 +1759,32 @@ class-utils@^0.3.5: clean-stack@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/clean-stack/-/clean-stack-2.2.0.tgz#ee8472dbb129e727b31e8a10a427dee9dfe4008b" + resolved "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz" integrity sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A== cli-boxes@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-boxes/-/cli-boxes-2.2.1.tgz#ddd5035d25094fce220e9cab40a45840a440318f" + resolved "https://registry.npmjs.org/cli-boxes/-/cli-boxes-2.2.1.tgz" integrity sha512-y4coMcylgSCdVinjiDBuR8PCC2bLjyGTwEmPb9NHR/QaNU6EUOXcTY/s6VjGMD6ENSEaeQYHCY0GNGS5jfMwPw== -cli-cursor@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-2.1.0.tgz#b35dac376479facc3e94747d41d0d0f5238ffcb5" - integrity sha1-s12sN2R5+sw+lHR9QdDQ9SOP/LU= - dependencies: - restore-cursor "^2.0.0" - cli-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/cli-cursor/-/cli-cursor-3.1.0.tgz#264305a7ae490d1d03bf0c9ba7c925d1753af307" + resolved "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz" integrity sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw== dependencies: restore-cursor "^3.1.0" -cli-spinners@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.0.tgz#36c7dc98fb6a9a76bd6238ec3f77e2425627e939" - integrity sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q== - cli-truncate@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/cli-truncate/-/cli-truncate-2.1.0.tgz#c39e28bf05edcde5be3b98992a22deed5a2b93c7" + resolved "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz" integrity sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg== dependencies: slice-ansi "^3.0.0" string-width "^4.2.0" -cli-width@^2.0.0: - version "2.2.1" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-2.2.1.tgz#b0433d0b4e9c847ef18868a4ef16fd5fc8271c48" - integrity sha512-GRMWDxpOB6Dgk2E5Uo+3eEBvtOOlimMmpbFiKuLFnQzYDavtLFY3K5ona41jgN/WdRZtG7utuVSVTL4HbZHGkw== - -cli-width@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/cli-width/-/cli-width-3.0.0.tgz#a2f48437a2caa9a22436e794bf071ec9e61cedf6" - integrity sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw== - -cliui@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-5.0.0.tgz#deefcfdb2e800784aa34f46fa08e06851c7bbbc5" - integrity sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA== - dependencies: - string-width "^3.1.0" - strip-ansi "^5.2.0" - wrap-ansi "^5.1.0" - cliui@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" + resolved "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz" integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== dependencies: string-width "^4.2.0" @@ -3664,47 +1793,26 @@ cliui@^6.0.0: cliui@^7.0.2: version "7.0.4" - resolved "https://registry.yarnpkg.com/cliui/-/cliui-7.0.4.tgz#a0265ee655476fc807aea9df3df8df7783808b4f" + resolved "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz" integrity sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ== dependencies: string-width "^4.2.0" strip-ansi "^6.0.0" wrap-ansi "^7.0.0" -clone-deep@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/clone-deep/-/clone-deep-4.0.1.tgz#c19fd9bdbbf85942b4fd979c84dcf7d5f07c2387" - integrity sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ== - dependencies: - is-plain-object "^2.0.4" - kind-of "^6.0.2" - shallow-clone "^3.0.0" - -clone@^1.0.2: - version "1.0.4" - resolved "https://registry.yarnpkg.com/clone/-/clone-1.0.4.tgz#da309cc263df15994c688ca902179ca3c7cd7c7e" - integrity sha1-2jCcwmPfFZlMaIypAheco8fNfH4= - -cmd-shim@^4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/cmd-shim/-/cmd-shim-4.1.0.tgz#b3a904a6743e9fede4148c6f3800bf2a08135bdd" - integrity sha512-lb9L7EM4I/ZRVuljLPEtUJOP+xiQVknZ4ZMpMgEp4JzNldPb27HU03hi6K1/6CoIuit/Zm/LQXySErFeXxDprw== - dependencies: - mkdirp-infer-owner "^2.0.0" - co@^4.6.0: version "4.6.0" - resolved "https://registry.yarnpkg.com/co/-/co-4.6.0.tgz#6ea6bdf3d853ae54ccb8e47bfa0bf3f9031fb184" + resolved "https://registry.npmjs.org/co/-/co-4.6.0.tgz" integrity sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ= code-point-at@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77" + resolved "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz" integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c= codecov@^3.8.3: version "3.8.3" - resolved "https://registry.yarnpkg.com/codecov/-/codecov-3.8.3.tgz#9c3e364b8a700c597346ae98418d09880a3fdbe7" + resolved "https://registry.npmjs.org/codecov/-/codecov-3.8.3.tgz" integrity sha512-Y8Hw+V3HgR7V71xWH2vQ9lyS358CbGCldWlJFR0JirqoGtOoas3R3/OclRTvgUYFK29mmJICDPauVKmpqbwhOA== dependencies: argv "0.0.2" @@ -3715,12 +1823,12 @@ codecov@^3.8.3: collect-v8-coverage@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz#cc2c8e94fc18bbdffe64d6534570c8a673b27f59" + resolved "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz" integrity sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg== collection-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" + resolved "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz" integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= dependencies: map-visit "^1.0.0" @@ -3728,99 +1836,83 @@ collection-visit@^1.0.0: color-convert@^1.9.0: version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz" integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== dependencies: color-name "1.1.3" color-convert@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" + resolved "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz" integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== dependencies: color-name "~1.1.4" color-name@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz" integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= color-name@~1.1.4: version "1.1.4" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" + resolved "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz" integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== colord@^2.0.1, colord@^2.6: version "2.7.0" - resolved "https://registry.yarnpkg.com/colord/-/colord-2.7.0.tgz#706ea36fe0cd651b585eb142fe64b6480185270e" + resolved "https://registry.npmjs.org/colord/-/colord-2.7.0.tgz" integrity sha512-pZJBqsHz+pYyw3zpX6ZRXWoCHM1/cvFikY9TV8G3zcejCaKE0lhankoj8iScyrrePA8C7yJ5FStfA9zbcOnw7Q== colorette@^1.2.2, colorette@^1.3.0, colorette@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/colorette/-/colorette-1.4.0.tgz#5190fbb87276259a86ad700bff2c6d6faa3fca40" + resolved "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz" integrity sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g== colors@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/colors/-/colors-1.4.0.tgz#c50491479d4c1bdaed2c9ced32cf7c7dc2360f78" + resolved "https://registry.npmjs.org/colors/-/colors-1.4.0.tgz" integrity sha512-a+UqTh4kgZg/SlGvfbzDHpgRu7AAQOmmqRHJnxhRZICKFUT91brVhNNt58CMWU9PsBbv3PDCZUHbVxuDiH2mtA== -columnify@^1.5.4: - version "1.5.4" - resolved "https://registry.yarnpkg.com/columnify/-/columnify-1.5.4.tgz#4737ddf1c7b69a8a7c340570782e947eec8e78bb" - integrity sha1-Rzfd8ce2mop8NAVweC6UfuyOeLs= - dependencies: - strip-ansi "^3.0.0" - wcwidth "^1.0.0" - combined-stream@^1.0.6, combined-stream@~1.0.6: version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" + resolved "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz" integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== dependencies: delayed-stream "~1.0.0" commander@2.20.0, commander@^2.12.1, commander@^2.20.0, commander@^2.9.0: version "2.20.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.0.tgz#d58bb2b5c1ee8f87b0d340027e9e94e222c5a422" + resolved "https://registry.npmjs.org/commander/-/commander-2.20.0.tgz" integrity sha512-7j2y+40w61zy6YC2iRNpUe/NwhNyoXrYpHMrSunaMG64nRnaf96zO/KMQR4OyN/UnE5KLyEBnKHd4aG3rskjpQ== commander@^6.1.0, commander@^6.2.0: version "6.2.1" - resolved "https://registry.yarnpkg.com/commander/-/commander-6.2.1.tgz#0792eb682dfbc325999bb2b84fddddba110ac73c" + resolved "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz" integrity sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA== commander@^7.2.0: version "7.2.0" - resolved "https://registry.yarnpkg.com/commander/-/commander-7.2.0.tgz#a36cb57d0b501ce108e4d20559a150a391d97ab7" + resolved "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz" integrity sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw== commondir@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/commondir/-/commondir-1.0.1.tgz#ddd800da0c66127393cca5950ea968a3aaf1253b" + resolved "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz" integrity sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs= -compare-func@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/compare-func/-/compare-func-2.0.0.tgz#fb65e75edbddfd2e568554e8b5b05fff7a51fcb3" - integrity sha512-zHig5N+tPWARooBnb0Zx1MFcdfpyJrfTJ3Y5L+IFvUm8rM74hHz66z0gw0x4tijh5CorKkKUCnW82R2vmpeCRA== - dependencies: - array-ify "^1.0.0" - dot-prop "^5.1.0" - component-emitter@^1.2.1: version "1.3.0" - resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" + resolved "https://registry.npmjs.org/component-emitter/-/component-emitter-1.3.0.tgz" integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== concat-map@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" + resolved "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz" integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= concat-stream@^1.5.0: version "1.6.2" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34" + resolved "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz" integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw== dependencies: buffer-from "^1.0.0" @@ -3828,189 +1920,40 @@ concat-stream@^1.5.0: readable-stream "^2.2.2" typedarray "^0.0.6" -concat-stream@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-2.0.0.tgz#414cf5af790a48c60ab9be4527d56d5e41133cb1" - integrity sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A== - dependencies: - buffer-from "^1.0.0" - inherits "^2.0.3" - readable-stream "^3.0.2" - typedarray "^0.0.6" - concat@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/concat/-/concat-1.0.3.tgz#40f3353089d65467695cb1886b45edd637d8cca8" + resolved "https://registry.npmjs.org/concat/-/concat-1.0.3.tgz" integrity sha1-QPM1MInWVGdpXLGIa0Xt1jfYzKg= dependencies: commander "^2.9.0" -config-chain@^1.1.11, config-chain@^1.1.12: - version "1.1.13" - resolved "https://registry.yarnpkg.com/config-chain/-/config-chain-1.1.13.tgz#fad0795aa6a6cdaff9ed1b68e9dff94372c232f4" - integrity sha512-qj+f8APARXHrM0hraqXYb2/bOVSV4PvJQlNZ/DVj0QrmNM2q2euizkeuVckQ57J+W0mRH6Hvi+k50M4Jul2VRQ== - dependencies: - ini "^1.3.4" - proto-list "~1.2.1" - console-browserify@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-browserify/-/console-browserify-1.1.0.tgz#f0241c45730a9fc6323b206dbf38edc741d0bb10" + resolved "https://registry.npmjs.org/console-browserify/-/console-browserify-1.1.0.tgz" integrity sha1-8CQcRXMKn8YyOyBtvzjtx0HQuxA= dependencies: date-now "^0.1.4" console-control-strings@^1.0.0, console-control-strings@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/console-control-strings/-/console-control-strings-1.1.0.tgz#3d7cf4464db6446ea644bf4b39507f9851008e8e" + resolved "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz" integrity sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4= constants-browserify@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/constants-browserify/-/constants-browserify-1.0.0.tgz#c20b96d8c617748aaf1c16021760cd27fcb8cb75" + resolved "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz" integrity sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U= -conventional-changelog-angular@^5.0.12, conventional-changelog-angular@^5.0.3: - version "5.0.13" - resolved "https://registry.yarnpkg.com/conventional-changelog-angular/-/conventional-changelog-angular-5.0.13.tgz#896885d63b914a70d4934b59d2fe7bde1832b28c" - integrity sha512-i/gipMxs7s8L/QeuavPF2hLnJgH6pEZAttySB6aiQLWcX3puWDL3ACVmvBhJGxnAy52Qc15ua26BufY6KpmrVA== - dependencies: - compare-func "^2.0.0" - q "^1.5.1" - -conventional-changelog-core@^3.1.6: - version "3.2.3" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-3.2.3.tgz#b31410856f431c847086a7dcb4d2ca184a7d88fb" - integrity sha512-LMMX1JlxPIq/Ez5aYAYS5CpuwbOk6QFp8O4HLAcZxe3vxoCtABkhfjetk8IYdRB9CDQGwJFLR3Dr55Za6XKgUQ== - dependencies: - conventional-changelog-writer "^4.0.6" - conventional-commits-parser "^3.0.3" - dateformat "^3.0.0" - get-pkg-repo "^1.0.0" - git-raw-commits "2.0.0" - git-remote-origin-url "^2.0.0" - git-semver-tags "^2.0.3" - lodash "^4.2.1" - normalize-package-data "^2.3.5" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^3.0.0" - -conventional-changelog-core@^4.2.2: - version "4.2.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-core/-/conventional-changelog-core-4.2.4.tgz#e50d047e8ebacf63fac3dc67bf918177001e1e9f" - integrity sha512-gDVS+zVJHE2v4SLc6B0sLsPiloR0ygU7HaDW14aNJE1v4SlqJPILPl/aJC7YdtRE4CybBf8gDwObBvKha8Xlyg== - dependencies: - add-stream "^1.0.0" - conventional-changelog-writer "^5.0.0" - conventional-commits-parser "^3.2.0" - dateformat "^3.0.0" - get-pkg-repo "^4.0.0" - git-raw-commits "^2.0.8" - git-remote-origin-url "^2.0.0" - git-semver-tags "^4.1.1" - lodash "^4.17.15" - normalize-package-data "^3.0.0" - q "^1.5.1" - read-pkg "^3.0.0" - read-pkg-up "^3.0.0" - through2 "^4.0.0" - -conventional-changelog-preset-loader@^2.1.1, conventional-changelog-preset-loader@^2.3.4: - version "2.3.4" - resolved "https://registry.yarnpkg.com/conventional-changelog-preset-loader/-/conventional-changelog-preset-loader-2.3.4.tgz#14a855abbffd59027fd602581f1f34d9862ea44c" - integrity sha512-GEKRWkrSAZeTq5+YjUZOYxdHq+ci4dNwHvpaBC3+ENalzFWuCWa9EZXSuZBpkr72sMdKB+1fyDV4takK1Lf58g== - -conventional-changelog-writer@^4.0.6: - version "4.1.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-4.1.0.tgz#1ca7880b75aa28695ad33312a1f2366f4b12659f" - integrity sha512-WwKcUp7WyXYGQmkLsX4QmU42AZ1lqlvRW9mqoyiQzdD+rJWbTepdWoKJuwXTS+yq79XKnQNa93/roViPQrAQgw== - dependencies: - compare-func "^2.0.0" - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.6" - json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" - -conventional-changelog-writer@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/conventional-changelog-writer/-/conventional-changelog-writer-5.0.0.tgz#c4042f3f1542f2f41d7d2e0d6cad23aba8df8eec" - integrity sha512-HnDh9QHLNWfL6E1uHz6krZEQOgm8hN7z/m7tT16xwd802fwgMN0Wqd7AQYVkhpsjDUx/99oo+nGgvKF657XP5g== - dependencies: - conventional-commits-filter "^2.0.7" - dateformat "^3.0.0" - handlebars "^4.7.6" - json-stringify-safe "^5.0.1" - lodash "^4.17.15" - meow "^8.0.0" - semver "^6.0.0" - split "^1.0.0" - through2 "^4.0.0" - -conventional-commits-filter@^2.0.2, conventional-commits-filter@^2.0.7: - version "2.0.7" - resolved "https://registry.yarnpkg.com/conventional-commits-filter/-/conventional-commits-filter-2.0.7.tgz#f8d9b4f182fce00c9af7139da49365b136c8a0b3" - integrity sha512-ASS9SamOP4TbCClsRHxIHXRfcGCnIoQqkvAzCSbZzTFLfcTqJVugB0agRgsEELsqaeWgsXv513eS116wnlSSPA== - dependencies: - lodash.ismatch "^4.4.0" - modify-values "^1.0.0" - -conventional-commits-parser@^3.0.3, conventional-commits-parser@^3.2.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/conventional-commits-parser/-/conventional-commits-parser-3.2.2.tgz#190fb9900c6e02be0c0bca9b03d57e24982639fd" - integrity sha512-Jr9KAKgqAkwXMRHjxDwO/zOCDKod1XdAESHAGuJX38iZ7ZzVti/tvVoysO0suMsdAObp9NQ2rHSsSbnAqZ5f5g== - dependencies: - JSONStream "^1.0.4" - is-text-path "^1.0.1" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - -conventional-recommended-bump@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-5.0.1.tgz#5af63903947b6e089e77767601cb592cabb106ba" - integrity sha512-RVdt0elRcCxL90IrNP0fYCpq1uGt2MALko0eyeQ+zQuDVWtMGAy9ng6yYn3kax42lCj9+XBxQ8ZN6S9bdKxDhQ== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.1.1" - conventional-commits-filter "^2.0.2" - conventional-commits-parser "^3.0.3" - git-raw-commits "2.0.0" - git-semver-tags "^2.0.3" - meow "^4.0.0" - q "^1.5.1" - -conventional-recommended-bump@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/conventional-recommended-bump/-/conventional-recommended-bump-6.1.0.tgz#cfa623285d1de554012f2ffde70d9c8a22231f55" - integrity sha512-uiApbSiNGM/kkdL9GTOLAqC4hbptObFo4wW2QRyHsKciGAfQuLU1ShZ1BIVI/+K2BE/W1AWYQMCXAsv4dyKPaw== - dependencies: - concat-stream "^2.0.0" - conventional-changelog-preset-loader "^2.3.4" - conventional-commits-filter "^2.0.7" - conventional-commits-parser "^3.2.0" - git-raw-commits "^2.0.8" - git-semver-tags "^4.1.1" - meow "^8.0.0" - q "^1.5.1" - convert-source-map@^1.4.0, convert-source-map@^1.6.0, convert-source-map@^1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" + resolved "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.7.0.tgz" integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== dependencies: safe-buffer "~5.1.1" copy-concurrently@^1.0.0: version "1.0.5" - resolved "https://registry.yarnpkg.com/copy-concurrently/-/copy-concurrently-1.0.5.tgz#92297398cae34937fcafd6ec8139c18051f0b5e0" + resolved "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz" integrity sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A== dependencies: aproba "^1.1.1" @@ -4022,27 +1965,17 @@ copy-concurrently@^1.0.0: copy-descriptor@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" + resolved "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz" integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= core-util-is@1.0.2, core-util-is@~1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" + resolved "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz" integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= -cosmiconfig@^5.1.0: - version "5.2.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-5.2.1.tgz#040f726809c591e77a17c0a3626ca45b4f168b1a" - integrity sha512-H65gsXo1SKjf8zmrJ67eJk8aIRKV5ff2D4uKZIBZShbhGSpEmsQOPW/SKMKYhSTrqR7ufy6RP69rPogdaPh/kA== - dependencies: - import-fresh "^2.0.0" - is-directory "^0.3.1" - js-yaml "^3.13.1" - parse-json "^4.0.0" - cosmiconfig@^7.0.0: version "7.0.1" - resolved "https://registry.yarnpkg.com/cosmiconfig/-/cosmiconfig-7.0.1.tgz#714d756522cace867867ccb4474c5d01bbae5d6d" + resolved "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.1.tgz" integrity sha512-a1YWNUV2HwGimB7dU2s1wUMurNKjpx60HxBB6xUM8Re+2s1g1IIfJvFR0/iCF+XHdE0GMTKTuLR32UQff4TEyQ== dependencies: "@types/parse-json" "^4.0.0" @@ -4053,7 +1986,7 @@ cosmiconfig@^7.0.0: coveralls@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/coveralls/-/coveralls-3.1.1.tgz#f5d4431d8b5ae69c5079c8f8ca00d64ac77cf081" + resolved "https://registry.npmjs.org/coveralls/-/coveralls-3.1.1.tgz" integrity sha512-+dxnG2NHncSD1NrqbSM3dn/lE57O6Qf/koe9+I7c+wzkqRmEvcp0kgJdxKInzYzkICKkFMZsX3Vct3++tsF9ww== dependencies: js-yaml "^3.13.1" @@ -4064,7 +1997,7 @@ coveralls@^3.1.0: cpr@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/cpr/-/cpr-3.0.1.tgz#b9a55038b7cd81a35c17b9761895bd8496aef1e5" + resolved "https://registry.npmjs.org/cpr/-/cpr-3.0.1.tgz" integrity sha1-uaVQOLfNgaNcF7l2GJW9hJau8eU= dependencies: graceful-fs "^4.1.5" @@ -4074,7 +2007,7 @@ cpr@^3.0.1: create-ecdh@^4.0.0: version "4.0.3" - resolved "https://registry.yarnpkg.com/create-ecdh/-/create-ecdh-4.0.3.tgz#c9111b6f33045c4697f144787f9254cdc77c45ff" + resolved "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz" integrity sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw== dependencies: bn.js "^4.1.0" @@ -4082,7 +2015,7 @@ create-ecdh@^4.0.0: create-hash@^1.1.0, create-hash@^1.1.2: version "1.2.0" - resolved "https://registry.yarnpkg.com/create-hash/-/create-hash-1.2.0.tgz#889078af11a63756bcfb59bd221996be3a9ef196" + resolved "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz" integrity sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg== dependencies: cipher-base "^1.0.1" @@ -4093,7 +2026,7 @@ create-hash@^1.1.0, create-hash@^1.1.2: create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: version "1.1.7" - resolved "https://registry.yarnpkg.com/create-hmac/-/create-hmac-1.1.7.tgz#69170c78b3ab957147b2b8b04572e47ead2243ff" + resolved "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz" integrity sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg== dependencies: cipher-base "^1.0.3" @@ -4103,16 +2036,16 @@ create-hmac@^1.1.0, create-hmac@^1.1.2, create-hmac@^1.1.4: safe-buffer "^5.0.1" sha.js "^2.4.8" -cross-env@^7.0.2, cross-env@^7.0.3: +cross-env@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf" + resolved "https://registry.npmjs.org/cross-env/-/cross-env-7.0.3.tgz" integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw== dependencies: cross-spawn "^7.0.1" cross-spawn@^6.0.0: version "6.0.5" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz" integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== dependencies: nice-try "^1.0.4" @@ -4123,7 +2056,7 @@ cross-spawn@^6.0.0: cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" + resolved "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz" integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== dependencies: path-key "^3.1.0" @@ -4132,7 +2065,7 @@ cross-spawn@^7.0.0, cross-spawn@^7.0.1, cross-spawn@^7.0.3: crypto-browserify@^3.11.0: version "3.12.0" - resolved "https://registry.yarnpkg.com/crypto-browserify/-/crypto-browserify-3.12.0.tgz#396cf9f3137f03e4b8e532c58f698254e00f80ec" + resolved "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz" integrity sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg== dependencies: browserify-cipher "^1.0.0" @@ -4149,19 +2082,19 @@ crypto-browserify@^3.11.0: css-color-names@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/css-color-names/-/css-color-names-1.0.1.tgz#6ff7ee81a823ad46e020fa2fd6ab40a887e2ba67" + resolved "https://registry.npmjs.org/css-color-names/-/css-color-names-1.0.1.tgz" integrity sha512-/loXYOch1qU1biStIFsHH8SxTmOseh1IJqFvy8IujXOm1h+QjUdDhkzOrR5HG8K8mlxREj0yfi8ewCHx0eMxzA== css-declaration-sorter@^6.0.3: version "6.1.3" - resolved "https://registry.yarnpkg.com/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz#e9852e4cf940ba79f509d9425b137d1f94438dc2" + resolved "https://registry.npmjs.org/css-declaration-sorter/-/css-declaration-sorter-6.1.3.tgz" integrity sha512-SvjQjNRZgh4ULK1LDJ2AduPKUKxIqmtU7ZAyi47BTV+M90Qvxr9AB6lKlLbDUfXqI9IQeYA8LbAsCZPpJEV3aA== dependencies: timsort "^0.3.0" css-loader@^5.2.6: version "5.2.7" - resolved "https://registry.yarnpkg.com/css-loader/-/css-loader-5.2.7.tgz#9b9f111edf6fb2be5dc62525644cbc9c232064ae" + resolved "https://registry.npmjs.org/css-loader/-/css-loader-5.2.7.tgz" integrity sha512-Q7mOvpBNBG7YrVGMxRxcBJZFL75o+cH2abNASdibkj/fffYD8qWbInZrD0S9ccI6vZclF3DsHE7njGlLtaHbhg== dependencies: icss-utils "^5.1.0" @@ -4177,7 +2110,7 @@ css-loader@^5.2.6: css-select@^4.1.3: version "4.1.3" - resolved "https://registry.yarnpkg.com/css-select/-/css-select-4.1.3.tgz#a70440f70317f2669118ad74ff105e65849c7067" + resolved "https://registry.npmjs.org/css-select/-/css-select-4.1.3.tgz" integrity sha512-gT3wBNd9Nj49rAbmtFHj1cljIAOLYSX1nZ8CB7TBO3INYckygm5B7LISU/szY//YmdiSLbJvDLOx9VnMVpMBxA== dependencies: boolbase "^1.0.0" @@ -4188,7 +2121,7 @@ css-select@^4.1.3: css-tree@^1.1.2, css-tree@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/css-tree/-/css-tree-1.1.3.tgz#eb4870fb6fd7707327ec95c2ff2ab09b5e8db91d" + resolved "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz" integrity sha512-tRpdppF7TRazZrjJ6v3stzv93qxRcSsFmW6cX0Zm2NVKpxE1WV1HblnghVv9TreireHkqI/VDEsfolRF1p6y7Q== dependencies: mdn-data "2.0.14" @@ -4196,17 +2129,17 @@ css-tree@^1.1.2, css-tree@^1.1.3: css-what@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/css-what/-/css-what-5.0.1.tgz#3efa820131f4669a8ac2408f9c32e7c7de9f4cad" + resolved "https://registry.npmjs.org/css-what/-/css-what-5.0.1.tgz" integrity sha512-FYDTSHb/7KXsWICVsxdmiExPjCfRC4qRFBdVwv7Ax9hMnvMmEjP9RfxTEZ3qPZGmADDn2vAKSo9UcN1jKVYscg== cssesc@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/cssesc/-/cssesc-3.0.0.tgz#37741919903b868565e1c09ea747445cd18983ee" + resolved "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz" integrity sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg== cssnano-preset-default@^5.1.4: version "5.1.4" - resolved "https://registry.yarnpkg.com/cssnano-preset-default/-/cssnano-preset-default-5.1.4.tgz#359943bf00c5c8e05489f12dd25f3006f2c1cbd2" + resolved "https://registry.npmjs.org/cssnano-preset-default/-/cssnano-preset-default-5.1.4.tgz" integrity sha512-sPpQNDQBI3R/QsYxQvfB4mXeEcWuw0wGtKtmS5eg8wudyStYMgKOQT39G07EbW1LB56AOYrinRS9f0ig4Y3MhQ== dependencies: css-declaration-sorter "^6.0.3" @@ -4241,12 +2174,12 @@ cssnano-preset-default@^5.1.4: cssnano-utils@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/cssnano-utils/-/cssnano-utils-2.0.1.tgz#8660aa2b37ed869d2e2f22918196a9a8b6498ce2" + resolved "https://registry.npmjs.org/cssnano-utils/-/cssnano-utils-2.0.1.tgz" integrity sha512-i8vLRZTnEH9ubIyfdZCAdIdgnHAUeQeByEeQ2I7oTilvP9oHO6RScpeq3GsFUVqeB8uZgOQ9pw8utofNn32hhQ== cssnano@^5.0.2: version "5.0.8" - resolved "https://registry.yarnpkg.com/cssnano/-/cssnano-5.0.8.tgz#39ad166256980fcc64faa08c9bb18bb5789ecfa9" + resolved "https://registry.npmjs.org/cssnano/-/cssnano-5.0.8.tgz" integrity sha512-Lda7geZU0Yu+RZi2SGpjYuQz4HI4/1Y+BhdD0jL7NXAQ5larCzVn+PUGuZbDMYz904AXXCOgO5L1teSvgu7aFg== dependencies: cssnano-preset-default "^5.1.4" @@ -4256,62 +2189,43 @@ cssnano@^5.0.2: csso@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/csso/-/csso-4.2.0.tgz#ea3a561346e8dc9f546d6febedd50187cf389529" + resolved "https://registry.npmjs.org/csso/-/csso-4.2.0.tgz" integrity sha512-wvlcdIbf6pwKEk7vHj8/Bkc0B4ylXZruLvOgs9doS5eOsOpuodOV2zJChSpkp+pRpYQLQMeF04nr3Z68Sta9jA== dependencies: css-tree "^1.1.2" cssom@^0.4.4: version "0.4.4" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.4.4.tgz#5a66cf93d2d0b661d80bf6a44fb65f5c2e4e0a10" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.4.4.tgz" integrity sha512-p3pvU7r1MyyqbTk+WbNJIgJjG2VmTIaB10rI93LzVPrmDJKkzKYMtxxyAvQXR/NS6otuzveI7+7BBq3SjBS2mw== cssom@~0.3.6: version "0.3.8" - resolved "https://registry.yarnpkg.com/cssom/-/cssom-0.3.8.tgz#9f1276f5b2b463f2114d3f2c75250af8c1a36f4a" + resolved "https://registry.npmjs.org/cssom/-/cssom-0.3.8.tgz" integrity sha512-b0tGHbfegbhPJpxpiBPU2sCkigAqtM9O121le6bbOlgyV+NyGyCmVfJ6QW9eRjz8CpNfWEOYBIMIGRYkLwsIYg== cssstyle@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/cssstyle/-/cssstyle-2.3.0.tgz#ff665a0ddbdc31864b09647f34163443d90b0852" + resolved "https://registry.npmjs.org/cssstyle/-/cssstyle-2.3.0.tgz" integrity sha512-AZL67abkUzIuvcHqk7c09cezpGNcxUxU4Ioi/05xHk4DQeTkWmGYftIE6ctU6AEt+Gn4n1lDStOtj7FKycP71A== dependencies: cssom "~0.3.6" -currently-unhandled@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea" - integrity sha1-mI3zP+qxke95mmE2nddsF635V+o= - dependencies: - array-find-index "^1.0.1" - cyclist@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-1.0.1.tgz#596e9698fd0c80e12038c2b82d6eb1b35b6224d9" + resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz" integrity sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk= -dargs@^4.0.1: - version "4.1.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-4.1.0.tgz#03a9dbb4b5c2f139bf14ae53f0b8a2a6a86f4e17" - integrity sha1-A6nbtLXC8Tm/FK5T8LiipqhvThc= - dependencies: - number-is-nan "^1.0.0" - -dargs@^7.0.0: - version "7.0.0" - resolved "https://registry.yarnpkg.com/dargs/-/dargs-7.0.0.tgz#04015c41de0bcb69ec84050f3d9be0caf8d6d5cc" - integrity sha512-2iy1EkLdlBzQGvbweYRFxmFath8+K7+AKB0TlhHWkNuH+TmovaMH/Wp7V7R4u7f4SnX3OgLsU9t1NI9ioDnUpg== - dashdash@^1.12.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" + resolved "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz" integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= dependencies: assert-plus "^1.0.0" data-urls@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/data-urls/-/data-urls-2.0.0.tgz#156485a72963a970f5d5821aaf642bef2bf2db9b" + resolved "https://registry.npmjs.org/data-urls/-/data-urls-2.0.0.tgz" integrity sha512-X5eWTSXO/BJmpdIKCRuKUgSCgAN0OwliVK3yPKbwIWU1Tdw5BRajxlzMidvh+gwko9AfQ9zIj52pzF91Q3YAvQ== dependencies: abab "^2.0.3" @@ -4320,121 +2234,77 @@ data-urls@^2.0.0: date-now@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/date-now/-/date-now-0.1.4.tgz#eaf439fd4d4848ad74e5cc7dbef200672b9e345b" + resolved "https://registry.npmjs.org/date-now/-/date-now-0.1.4.tgz" integrity sha1-6vQ5/U1ISK105cx9vvIAZyueNFs= -dateformat@^3.0.0: - version "3.0.3" - resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae" - integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q== - -debug@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/debug/-/debug-3.1.0.tgz#5bb5a0672628b64149566ba16819e61518c67261" - integrity sha512-OX8XqP7/1a9cqkxYw2yXss15f26NKWBpDXQd0/uK/KPqdQhxbPa994hnzjcE2VqQpDslf55723cKPUOGSmMY3g== - dependencies: - ms "2.0.0" - debug@4, debug@4.3.1, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1: version "4.3.1" - resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.1.tgz#f0d229c505e0c6d8c49ac553d1b13dc183f6b2ee" + resolved "https://registry.npmjs.org/debug/-/debug-4.3.1.tgz" integrity sha512-doEwdvm4PCeK4K3RQN2ZC2BYUBaxwLARCqZmMjtF8a51J2Rb0xpVloFRnCODwqjpwnAoao4pelN8l3RJdv3gRQ== dependencies: ms "2.1.2" debug@^2.2.0, debug@^2.3.3: version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" + resolved "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz" integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== dependencies: ms "2.0.0" -debug@^3.1.0, debug@^3.2.6: +debug@^3.2.6: version "3.2.7" resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== dependencies: ms "^2.1.1" -debuglog@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492" - integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI= - -decamelize-keys@^1.0.0, decamelize-keys@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9" - integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk= - dependencies: - decamelize "^1.1.0" - map-obj "^1.0.0" - -decamelize@^1.1.0, decamelize@^1.1.2, decamelize@^1.2.0: +decamelize@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" + resolved "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz" integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= decimal.js@^10.2.0: version "10.2.0" - resolved "https://registry.yarnpkg.com/decimal.js/-/decimal.js-10.2.0.tgz#39466113a9e036111d02f82489b5fd6b0b5ed231" + resolved "https://registry.npmjs.org/decimal.js/-/decimal.js-10.2.0.tgz" integrity sha512-vDPw+rDgn3bZe1+F/pyEwb1oMG2XTlRVgAa6B4KccTEpYgF8w6eQllVbQcfIJnZyvzFtFpxnpGtx8dd7DJp/Rw== decode-uri-component@^0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" + resolved "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz" integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= -dedent@^0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/dedent/-/dedent-0.7.0.tgz#2495ddbaf6eb874abb0e1be9df22d2e5a544326c" - integrity sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw= - deep-extend@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/deep-extend/-/deep-extend-0.6.0.tgz#c4fa7c95404a17a9c3e8ca7e1537312b736330ac" + resolved "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz" integrity sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA== deep-is@~0.1.3: version "0.1.3" - resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.3.tgz#b369d6fb5dbc13eecf524f91b070feedc357cf34" + resolved "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz" integrity sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ= deepmerge@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/deepmerge/-/deepmerge-4.2.2.tgz#44d2ea3679b8f4d4ffba33f03d865fc1e7bf4955" + resolved "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz" integrity sha512-FJ3UgI4gIl+PHZm53knsuSFpE+nESMr7M4v9QcgB7S63Kj/6WqMiFQJpBBYz1Pt+66bZpP3Q7Lye0Oo9MPKEdg== -defaults@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/defaults/-/defaults-1.0.3.tgz#c656051e9817d9ff08ed881477f3fe4019f3ef7d" - integrity sha1-xlYFHpgX2f8I7YgUd/P+QBnz730= - dependencies: - clone "^1.0.2" - -define-properties@^1.1.2, define-properties@^1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1" - integrity sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ== - dependencies: - object-keys "^1.0.12" - define-property@^0.2.5: version "0.2.5" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" + resolved "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz" integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= dependencies: is-descriptor "^0.1.0" define-property@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" + resolved "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz" integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= dependencies: is-descriptor "^1.0.0" define-property@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" + resolved "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz" integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== dependencies: is-descriptor "^1.0.2" @@ -4442,106 +2312,76 @@ define-property@^2.0.2: delayed-stream@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" + resolved "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz" integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= delegates@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/delegates/-/delegates-1.0.0.tgz#84c6e159b81904fdca59a0ef44cd870d31250f9a" + resolved "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz" integrity sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o= depd@^1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" + resolved "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz" integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= -deprecation@^2.0.0, deprecation@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/deprecation/-/deprecation-2.3.1.tgz#6368cbdb40abf3373b525ac87e4a260c3a700919" - integrity sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ== - des.js@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/des.js/-/des.js-1.0.0.tgz#c074d2e2aa6a8a9a07dbd61f9a15c2cd83ec8ecc" + resolved "https://registry.npmjs.org/des.js/-/des.js-1.0.0.tgz" integrity sha1-wHTS4qpqipoH29YfmhXCzYPsjsw= dependencies: inherits "^2.0.1" minimalistic-assert "^1.0.0" -detect-indent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-5.0.0.tgz#3871cc0a6a002e8c3e5b3cf7f336264675f06b9d" - integrity sha1-OHHMCmoALow+Wzz38zYmRnXwa50= - -detect-indent@^6.0.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/detect-indent/-/detect-indent-6.1.0.tgz#592485ebbbf6b3b1ab2be175c8393d04ca0d57e6" - integrity sha512-reYkTUJAZb9gUuZ2RvVCNhVHdg62RHnJ7WJl8ftMi4diZ6NWlciOzQN88pUhSELEwflJht4oQDv0F0BMlwaYtA== - detect-libc@^1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-1.0.3.tgz#fa137c4bd698edf55cd5cd02ac559f91a4c4ba9b" + resolved "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz" integrity sha1-+hN8S9aY7fVc1c0CrFWfkaTEups= detect-newline@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-3.1.0.tgz#576f5dfc63ae1a192ff192d8ad3af6308991b651" + resolved "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz" integrity sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA== devtools-protocol@0.0.901419: version "0.0.901419" - resolved "https://registry.yarnpkg.com/devtools-protocol/-/devtools-protocol-0.0.901419.tgz#79b5459c48fe7e1c5563c02bd72f8fec3e0cebcd" + resolved "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.901419.tgz" integrity sha512-4INMPwNm9XRpBukhNbF7OB6fNTTCaI8pzy/fXg0xQzAy5h3zL1P8xT3QazgKqBrb/hAYwIBizqDBZ7GtJE74QQ== -dezalgo@^1.0.0: - version "1.0.3" - resolved "https://registry.yarnpkg.com/dezalgo/-/dezalgo-1.0.3.tgz#7f742de066fc748bc8db820569dddce49bf0d456" - integrity sha1-f3Qt4Gb8dIvI24IFad3c5Jvw1FY= - dependencies: - asap "^2.0.0" - wrappy "1" - diff-sequences@^25.2.6: version "25.2.6" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-25.2.6.tgz#5f467c00edd35352b7bca46d7927d60e687a76dd" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-25.2.6.tgz" integrity sha512-Hq8o7+6GaZeoFjtpgvRBUknSXNeJiCx7V9Fr94ZMljNiCr9n9L8H8aJqgWOQiDDGdyn29fRNcDdRVJ5fdyihfg== diff-sequences@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/diff-sequences/-/diff-sequences-26.0.0.tgz#0760059a5c287637b842bd7085311db7060e88a6" + resolved "https://registry.npmjs.org/diff-sequences/-/diff-sequences-26.0.0.tgz" integrity sha512-JC/eHYEC3aSS0vZGjuoc4vHA0yAQTzhQQldXMeMF+JlxLGJlCO38Gma82NV9gk1jGFz8mDzUMeaKXvjRRdJ2dg== diff@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d" + resolved "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz" integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A== diffie-hellman@^5.0.0: version "5.0.3" - resolved "https://registry.yarnpkg.com/diffie-hellman/-/diffie-hellman-5.0.3.tgz#40e8ee98f55a2149607146921c63e1ae5f3d2875" + resolved "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz" integrity sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg== dependencies: bn.js "^4.1.0" miller-rabin "^4.0.0" randombytes "^2.0.0" -dir-glob@^2.2.2: - version "2.2.2" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" - integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== - dependencies: - path-type "^3.0.0" - dir-glob@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" + resolved "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz" integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== dependencies: path-type "^4.0.0" dom-serializer@^1.0.1: version "1.3.2" - resolved "https://registry.yarnpkg.com/dom-serializer/-/dom-serializer-1.3.2.tgz#6206437d32ceefaec7161803230c7a20bc1b4d91" + resolved "https://registry.npmjs.org/dom-serializer/-/dom-serializer-1.3.2.tgz" integrity sha512-5c54Bk5Dw4qAxNOI1pFEizPSjVsx5+bpJKmL2kPn8JhBUq2q09tTCa3mjijun2NfK78NMouDYNMBkOrPZiS+ig== dependencies: domelementtype "^2.0.1" @@ -4550,71 +2390,50 @@ dom-serializer@^1.0.1: domain-browser@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/domain-browser/-/domain-browser-1.2.0.tgz#3d31f50191a6749dd1375a7f522e823d42e54eda" + resolved "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz" integrity sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA== domelementtype@^2.0.1, domelementtype@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/domelementtype/-/domelementtype-2.2.0.tgz#9a0b6c2782ed6a1c7323d42267183df9bd8b1d57" + resolved "https://registry.npmjs.org/domelementtype/-/domelementtype-2.2.0.tgz" integrity sha512-DtBMo82pv1dFtUmHyr48beiuq792Sxohr+8Hm9zoxklYPfa6n0Z3Byjj2IV7bmr2IyqClnqEQhfgHJJ5QF0R5A== domexception@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/domexception/-/domexception-2.0.1.tgz#fb44aefba793e1574b0af6aed2801d057529f304" + resolved "https://registry.npmjs.org/domexception/-/domexception-2.0.1.tgz" integrity sha512-yxJ2mFy/sibVQlu5qHjOkf9J3K6zgmCxgJ94u2EdvDOV09H+32LtRswEcUsmUWN72pVLOEnTSRaIVVzVQgS0dg== dependencies: webidl-conversions "^5.0.0" domhandler@^4.2.0: version "4.2.2" - resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-4.2.2.tgz#e825d721d19a86b8c201a35264e226c678ee755f" + resolved "https://registry.npmjs.org/domhandler/-/domhandler-4.2.2.tgz" integrity sha512-PzE9aBMsdZO8TK4BnuJwH0QT41wgMbRzuZrHUcpYncEjmQazq8QEaBWgLG7ZyC/DAZKEgglpIA6j4Qn/HmxS3w== dependencies: domelementtype "^2.2.0" domutils@^2.6.0: version "2.8.0" - resolved "https://registry.yarnpkg.com/domutils/-/domutils-2.8.0.tgz#4437def5db6e2d1f5d6ee859bd95ca7d02048135" + resolved "https://registry.npmjs.org/domutils/-/domutils-2.8.0.tgz" integrity sha512-w96Cjofp72M5IIhpjgobBimYEfoPjx1Vx0BSX9P30WBdZW2WIKU0T1Bd0kz2eNZ9ikjKgHbEyKx8BB6H1L3h3A== dependencies: dom-serializer "^1.0.1" domelementtype "^2.2.0" domhandler "^4.2.0" -dot-prop@^4.2.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-4.2.1.tgz#45884194a71fc2cda71cbb4bceb3a4dd2f433ba4" - integrity sha512-l0p4+mIuJIua0mhxGoh4a+iNL9bmeK5DvnSVQa6T0OhrVmaEa1XScX5Etc673FePCJOArq/4Pa2cLGODUWTPOQ== - dependencies: - is-obj "^1.0.0" - -dot-prop@^5.1.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-5.3.0.tgz#90ccce708cd9cd82cc4dc8c3ddd9abdd55b20e88" - integrity sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q== - dependencies: - is-obj "^2.0.0" - -dot-prop@^6.0.1: - version "6.0.1" - resolved "https://registry.yarnpkg.com/dot-prop/-/dot-prop-6.0.1.tgz#fc26b3cf142b9e59b74dbd39ed66ce620c681083" - integrity sha512-tE7ztYzXHIeyvc7N+hR3oi7FIbf/NIjVP9hmAt3yMXzrQ072/fpjGLx2GxNxGxUl5V73MEqYzioOMoVhGMJ5cA== - dependencies: - is-obj "^2.0.0" - duplexer@0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.1.tgz#ace6ff808c1ce66b57d1ebf97977acb02334cfc1" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.1.tgz" integrity sha1-rOb/gIwc5mtX0ev5eXessCM0z8E= -duplexer@^0.1.1, duplexer@^0.1.2: +duplexer@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" + resolved "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== duplexify@^3.4.2, duplexify@^3.6.0: version "3.7.1" - resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + resolved "https://registry.npmjs.org/duplexify/-/duplexify-3.7.1.tgz" integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== dependencies: end-of-stream "^1.0.0" @@ -4624,7 +2443,7 @@ duplexify@^3.4.2, duplexify@^3.6.0: ecc-jsbn@~0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" + resolved "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz" integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= dependencies: jsbn "~0.1.0" @@ -4632,12 +2451,12 @@ ecc-jsbn@~0.1.1: electron-to-chromium@^1.3.830: version "1.3.843" - resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz#671489bd2f59fd49b76adddc1aa02c88cd38a5c0" + resolved "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.843.tgz" integrity sha512-OWEwAbzaVd1Lk9MohVw8LxMXFlnYd9oYTYxfX8KS++kLLjDfbovLOcEEXwRhG612dqGQ6+44SZvim0GXuBRiKg== elliptic@^6.0.0: version "6.5.3" - resolved "https://registry.yarnpkg.com/elliptic/-/elliptic-6.5.3.tgz#cb59eb2efdaf73a0bd78ccd7015a62ad6e0f93d6" + resolved "https://registry.npmjs.org/elliptic/-/elliptic-6.5.3.tgz" integrity sha512-IMqzv5wNQf+E6aHeIqATs0tOLeOTwj1QKbRcS3jBbYkl5oLAserA8yJTT7/VyHUYG91PRmPyeQDObKLPpeS4dw== dependencies: bn.js "^4.4.0" @@ -4650,41 +2469,41 @@ elliptic@^6.0.0: emoji-regex@^7.0.1: version "7.0.3" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-7.0.3.tgz#933a04052860c85e83c122479c4748a8e4c72156" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz" integrity sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA== emoji-regex@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" + resolved "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz" integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== emojis-list@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-2.1.0.tgz#4daa4d9db00f9819880c79fa457ae5b09a1fd389" + resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz" integrity sha1-TapNnbAPmBmIDHn6RXrlsJof04k= emojis-list@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/emojis-list/-/emojis-list-3.0.0.tgz#5570662046ad29e2e916e71aae260abdff4f6a78" + resolved "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz" integrity sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q== -encoding@^0.1.11, encoding@^0.1.12: +encoding@^0.1.12: version "0.1.13" - resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.13.tgz#56574afdd791f54a8e9b2785c0582a2d26210fa9" + resolved "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz" integrity sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A== dependencies: iconv-lite "^0.6.2" end-of-stream@^1.0.0, end-of-stream@^1.1.0, end-of-stream@^1.4.1: version "1.4.4" - resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.4.tgz#5ae64a5f45057baf3626ec14da0ca5e4b2431eb0" + resolved "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz" integrity sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q== dependencies: once "^1.4.0" enhanced-resolve@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz#2f3cfd84dbe3b487f18f2db2ef1e064a571ca5ec" + resolved "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.5.0.tgz" integrity sha512-Nv9m36S/vxpsI+Hc4/ZGRs0n9mXqSWGGq49zxb/cJfPAQMbUtttJAlNPS4AQzaBdw/pKskw5bMbekT/Y7W/Wlg== dependencies: graceful-fs "^4.1.2" @@ -4693,115 +2512,63 @@ enhanced-resolve@^4.5.0: enquirer@^2.3.6: version "2.3.6" - resolved "https://registry.yarnpkg.com/enquirer/-/enquirer-2.3.6.tgz#2a7fe5dd634a1e4125a975ec994ff5456dc3734d" + resolved "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz" integrity sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg== dependencies: ansi-colors "^4.1.1" entities@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/entities/-/entities-2.0.0.tgz#68d6084cab1b079767540d80e56a39b423e4abf4" + resolved "https://registry.npmjs.org/entities/-/entities-2.0.0.tgz" integrity sha512-D9f7V0JSRwIxlRI2mjMqufDrRDnx8p+eEOz7aUM9SuvF8gsBzra0/6tbjl1m8eQHrZlYj6PxqE00hZ1SAIKPLw== -env-paths@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-1.0.0.tgz#4168133b42bb05c38a35b1ae4397c8298ab369e0" - integrity sha1-QWgTO0K7BcOKNbGuQ5fIKYqzaeA= - env-paths@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/env-paths/-/env-paths-2.2.0.tgz#cdca557dc009152917d6166e2febe1f039685e43" + resolved "https://registry.npmjs.org/env-paths/-/env-paths-2.2.0.tgz" integrity sha512-6u0VYSCo/OW6IoD5WCLLy9JUGARbamfSavcNXry/eu8aHVFei6CD3Sw+VGX5alea1i9pgPHW0mbu6Xj0uBh7gA== -envinfo@^7.3.1, envinfo@^7.7.4: - version "7.8.1" - resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.8.1.tgz#06377e3e5f4d379fea7ac592d5ad8927e0c4d475" - integrity sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw== - -err-code@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-1.1.2.tgz#06e0116d3028f6aef4806849eb0ea6a748ae6960" - integrity sha1-BuARbTAo9q70gGhJ6w6mp0iuaWA= - err-code@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/err-code/-/err-code-2.0.3.tgz#23c2f3b756ffdfc608d30e27c9a941024807e7f9" + resolved "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz" integrity sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA== errno@^0.1.3, errno@~0.1.7: version "0.1.7" - resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.7.tgz#4684d71779ad39af177e3f007996f7c67c852618" + resolved "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz" integrity sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg== dependencies: - prr "~1.0.1" - -error-ex@^1.2.0, error-ex@^1.3.1: - version "1.3.2" - resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" - integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== - dependencies: - is-arrayish "^0.2.1" - -es-abstract@^1.5.1: - version "1.15.0" - resolved "https://registry.yarnpkg.com/es-abstract/-/es-abstract-1.15.0.tgz#8884928ec7e40a79e3c9bc812d37d10c8b24cc57" - integrity sha512-bhkEqWJ2t2lMeaJDuk7okMkJWI/yqgH/EoGwpcvv0XW9RWQsRspI4wt6xuyuvMvvQE3gg/D9HXppgk21w78GyQ== - dependencies: - es-to-primitive "^1.2.0" - function-bind "^1.1.1" - has "^1.0.3" - has-symbols "^1.0.0" - is-callable "^1.1.4" - is-regex "^1.0.4" - object-inspect "^1.6.0" - object-keys "^1.1.1" - string.prototype.trimleft "^2.1.0" - string.prototype.trimright "^2.1.0" - -es-to-primitive@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/es-to-primitive/-/es-to-primitive-1.2.0.tgz#edf72478033456e8dda8ef09e00ad9650707f377" - integrity sha512-qZryBOJjV//LaxLTV6UC//WewneB3LcXOL9NP++ozKVXsIIIpm/2c13UDiD9Jp2eThsecw9m3jPqDwTyobcdbg== - dependencies: - is-callable "^1.1.4" - is-date-object "^1.0.1" - is-symbol "^1.0.2" - -es6-promise@^4.0.3: - version "4.2.8" - resolved "https://registry.yarnpkg.com/es6-promise/-/es6-promise-4.2.8.tgz#4eb21594c972bc40553d276e510539143db53e0a" - integrity sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w== + prr "~1.0.1" -es6-promisify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-5.0.0.tgz#5109d62f3e56ea967c4b63505aef08291c8a5203" - integrity sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM= +error-ex@^1.3.1: + version "1.3.2" + resolved "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz" + integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== dependencies: - es6-promise "^4.0.3" + is-arrayish "^0.2.1" escalade@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40" + resolved "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz" integrity sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw== escape-string-regexp@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz" integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= escape-string-regexp@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz#a30304e99daa32e23b2fd20f51babd07cffca344" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz" integrity sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w== escape-string-regexp@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" + resolved "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== escodegen@^1.14.1: version "1.14.3" - resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.14.3.tgz#4e7b81fba61581dc97582ed78cab7f0e8d63f503" + resolved "https://registry.npmjs.org/escodegen/-/escodegen-1.14.3.tgz" integrity sha512-qFcX0XJkdg+PB3xjZZG/wKSuT1PnQWx57+TVSjIMmILd2yC/6ByYElPwJnslDsuWuSAp4AwJGumarAAmJch5Kw== dependencies: esprima "^4.0.1" @@ -4813,7 +2580,7 @@ escodegen@^1.14.1: eslint-scope@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-4.0.3.tgz#ca03833310f6889a3264781aa82e63eb9cfe7848" + resolved "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz" integrity sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg== dependencies: esrecurse "^4.1.0" @@ -4821,19 +2588,19 @@ eslint-scope@^4.0.3: esprima@^4.0.0, esprima@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" + resolved "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz" integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== esrecurse@^4.1.0: version "4.2.1" - resolved "https://registry.yarnpkg.com/esrecurse/-/esrecurse-4.2.1.tgz#007a3b9fdbc2b3bb87e4879ea19c92fdbd3942cf" + resolved "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz" integrity sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ== dependencies: estraverse "^4.1.0" estimo@^2.2.8: version "2.2.8" - resolved "https://registry.yarnpkg.com/estimo/-/estimo-2.2.8.tgz#5eb3ab381cffe46086f68dfcca3550c7f656e5a2" + resolved "https://registry.npmjs.org/estimo/-/estimo-2.2.8.tgz" integrity sha512-7sQte1r5KtILz1BNl8b2Npf9K9HYE4vWfnj+9DDyUYsdKj9z+6bYXIahrqdTPBfhaUZ4Akd7EUqQxFnu5SCPkQ== dependencies: "@sitespeed.io/tracium" "^0.3.3" @@ -4843,37 +2610,27 @@ estimo@^2.2.8: estraverse@^4.1.0, estraverse@^4.1.1, estraverse@^4.2.0: version "4.3.0" - resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-4.3.0.tgz#398ad3f3c5a24948be7725e83d11a7de28cdbd1d" + resolved "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz" integrity sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw== estree-walker@^0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/estree-walker/-/estree-walker-0.6.1.tgz#53049143f40c6eb918b23671d1fe3219f3a1b362" + resolved "https://registry.npmjs.org/estree-walker/-/estree-walker-0.6.1.tgz" integrity sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w== esutils@^2.0.2: version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" + resolved "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz" integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== -eventemitter3@^3.1.0: - version "3.1.2" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7" - integrity sha512-tvtQIeLVHjDkJYnzf2dgVMxfuSGJeM/7UCG17TT4EumTfNtF+0nebF/4zWOIkCreAbtNqhGEboB6BWrwqNaw4Q== - -eventemitter3@^4.0.4: - version "4.0.7" - resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" - integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== - events@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/events/-/events-3.0.0.tgz#9a0a0dfaf62893d92b875b8f2698ca4114973e88" + resolved "https://registry.npmjs.org/events/-/events-3.0.0.tgz" integrity sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA== evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz#7fcbdb198dc71959432efe13842684e0525acb02" + resolved "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz" integrity sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA== dependencies: md5.js "^1.3.4" @@ -4881,12 +2638,12 @@ evp_bytestokey@^1.0.0, evp_bytestokey@^1.0.3: exec-sh@^0.3.2: version "0.3.4" - resolved "https://registry.yarnpkg.com/exec-sh/-/exec-sh-0.3.4.tgz#3a018ceb526cc6f6df2bb504b2bfe8e3a4934ec5" + resolved "https://registry.npmjs.org/exec-sh/-/exec-sh-0.3.4.tgz" integrity sha512-sEFIkc61v75sWeOe72qyrqg2Qg0OuLESziUDk/O/z2qgS15y2gWVFrI6f2Qn/qw/0/NCfCEsmNA4zOjkwEZT1A== execa@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/execa/-/execa-1.0.0.tgz#c6236a5bb4df6d6f15e88e7f017798216749ddd8" + resolved "https://registry.npmjs.org/execa/-/execa-1.0.0.tgz" integrity sha512-adbxcyWV46qiHyvSp50TKt05tB4tK3HcmF7/nxfAdhnox83seTDbwnaqKO4sXRy7roHAIFqJP/Rw/AuEbX61LA== dependencies: cross-spawn "^6.0.0" @@ -4899,7 +2656,7 @@ execa@^1.0.0: execa@^4.0.0: version "4.0.2" - resolved "https://registry.yarnpkg.com/execa/-/execa-4.0.2.tgz#ad87fb7b2d9d564f70d2b62d511bee41d5cbb240" + resolved "https://registry.npmjs.org/execa/-/execa-4.0.2.tgz" integrity sha512-QI2zLa6CjGWdiQsmSkZoGtDx2N+cQIGb3yNolGTdjSQzydzLgYYf8LRuagp7S7fPimjcrzUDSUFd/MgzELMi4Q== dependencies: cross-spawn "^7.0.0" @@ -4914,7 +2671,7 @@ execa@^4.0.0: execa@^5.0.0: version "5.1.1" - resolved "https://registry.yarnpkg.com/execa/-/execa-5.1.1.tgz#f80ad9cbf4298f7bd1d4c9555c21e93741c411dd" + resolved "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz" integrity sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg== dependencies: cross-spawn "^7.0.3" @@ -4929,12 +2686,12 @@ execa@^5.0.0: exit@^0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/exit/-/exit-0.1.2.tgz#0632638f8d877cc82107d30a0fff1a17cba1cd0c" + resolved "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz" integrity sha1-BjJjj42HfMghB9MKD/8aF8uhzQw= expand-brackets@^2.1.4: version "2.1.4" - resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" + resolved "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz" integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= dependencies: debug "^2.3.3" @@ -4947,7 +2704,7 @@ expand-brackets@^2.1.4: expect@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/expect/-/expect-26.1.0.tgz#8c62e31d0f8d5a8ebb186ee81473d15dd2fbf7c8" + resolved "https://registry.npmjs.org/expect/-/expect-26.1.0.tgz" integrity sha512-QbH4LZXDsno9AACrN9eM0zfnby9G+OsdNgZUohjg/P0mLy1O+/bzTAJGT6VSIjVCe8yKM6SzEl/ckEOFBT7Vnw== dependencies: "@jest/types" "^26.1.0" @@ -4959,14 +2716,14 @@ expect@^26.1.0: extend-shallow@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz" integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= dependencies: is-extendable "^0.1.0" extend-shallow@^3.0.0, extend-shallow@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" + resolved "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz" integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= dependencies: assign-symbols "^1.0.0" @@ -4974,21 +2731,12 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: extend@~3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" + resolved "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== -external-editor@^3.0.3: - version "3.1.0" - resolved "https://registry.yarnpkg.com/external-editor/-/external-editor-3.1.0.tgz#cb03f740befae03ea4d283caed2741a83f335495" - integrity sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew== - dependencies: - chardet "^0.7.0" - iconv-lite "^0.4.24" - tmp "^0.0.33" - extglob@^2.0.4: version "2.0.4" - resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" + resolved "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz" integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== dependencies: array-unique "^0.3.2" @@ -5002,7 +2750,7 @@ extglob@^2.0.4: extract-zip@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/extract-zip/-/extract-zip-2.0.1.tgz#663dca56fe46df890d5f131ef4a06d22bb8ba13a" + resolved "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz" integrity sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg== dependencies: debug "^4.1.1" @@ -5013,29 +2761,17 @@ extract-zip@2.0.1: extsprintf@1.3.0, extsprintf@^1.2.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" + resolved "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz" integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= fast-deep-equal@^3.1.1: version "3.1.3" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" + resolved "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^2.2.6: - version "2.2.7" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" - integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== - dependencies: - "@mrmlnc/readdir-enhanced" "^2.2.1" - "@nodelib/fs.stat" "^1.1.2" - glob-parent "^3.1.0" - is-glob "^4.0.0" - merge2 "^1.2.3" - micromatch "^3.1.10" - fast-glob@^3.1.1: version "3.2.4" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.4.tgz#d20aefbf99579383e7f3cc66529158c9b98554d3" + resolved "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.4.tgz" integrity sha512-kr/Oo6PX51265qeuCYsyGypiO5uJFgBS0jksyG7FUeCyQzNwYnzrNIMR1NXfkZXsMYXYLRAHgISHBz8gQcxKHQ== dependencies: "@nodelib/fs.stat" "^2.0.2" @@ -5047,64 +2783,50 @@ fast-glob@^3.1.1: fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz#874bf69c6f404c2b5d99c481341399fd55892633" + resolved "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz" integrity sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw== fast-levenshtein@~2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz#3d8a5c66883a16a30ca8643e851f19baa7797917" + resolved "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz" integrity sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc= fast-url-parser@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/fast-url-parser/-/fast-url-parser-1.1.3.tgz#f4af3ea9f34d8a271cf58ad2b3759f431f0b318d" + resolved "https://registry.npmjs.org/fast-url-parser/-/fast-url-parser-1.1.3.tgz" integrity sha1-9K8+qfNNiicc9YrSs3WfQx8LMY0= dependencies: punycode "^1.3.2" fastq@^1.6.0: version "1.8.0" - resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.8.0.tgz#550e1f9f59bbc65fe185cb6a9b4d95357107f481" + resolved "https://registry.npmjs.org/fastq/-/fastq-1.8.0.tgz" integrity sha512-SMIZoZdLh/fgofivvIkmknUXyPnvxRE3DhtZ5Me3Mrsk5gyPL42F0xr51TdRXskBxHfMp+07bcYzfsYEsSQA9Q== dependencies: reusify "^1.0.4" fb-watchman@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/fb-watchman/-/fb-watchman-2.0.1.tgz#fc84fb39d2709cf3ff6d743706157bb5708a8a85" + resolved "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.1.tgz" integrity sha512-DkPJKQeY6kKwmuMretBhr7G6Vodr7bFwDYTXIkfG1gjvNpaxBTQV3PbXg6bR1c1UP4jPOX0jHUbbHANL9vRjVg== dependencies: bser "2.1.1" fd-slicer@~1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/fd-slicer/-/fd-slicer-1.1.0.tgz#25c7c89cb1f9077f8891bbe61d8f390eae256f1e" + resolved "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz" integrity sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4= dependencies: pend "~1.2.0" -figgy-pudding@^3.4.1, figgy-pudding@^3.5.1: +figgy-pudding@^3.5.1: version "3.5.2" resolved "https://registry.yarnpkg.com/figgy-pudding/-/figgy-pudding-3.5.2.tgz#b4eee8148abb01dcf1d1ac34367d59e12fa61d6e" integrity sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw== -figures@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" - integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= - dependencies: - escape-string-regexp "^1.0.5" - -figures@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/figures/-/figures-3.2.0.tgz#625c18bd293c604dc4a8ddb2febf0c88341746af" - integrity sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg== - dependencies: - escape-string-regexp "^1.0.5" - file-loader@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/file-loader/-/file-loader-6.2.0.tgz#baef7cf8e1840df325e4390b4484879480eebe4d" + resolved "https://registry.npmjs.org/file-loader/-/file-loader-6.2.0.tgz" integrity sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw== dependencies: loader-utils "^2.0.0" @@ -5112,12 +2834,12 @@ file-loader@^6.2.0: filesize@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/filesize/-/filesize-6.1.0.tgz#e81bdaa780e2451d714d71c0d7a4f3238d37ad00" + resolved "https://registry.npmjs.org/filesize/-/filesize-6.1.0.tgz" integrity sha512-LpCHtPQ3sFx67z+uh2HnSyWSLLu5Jxo21795uRDuar/EOuYWXib5EmPaGIBuSnRqH2IODiKA2k5re/K9OnN/Yg== fill-range@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz" integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= dependencies: extend-shallow "^2.0.1" @@ -5127,45 +2849,30 @@ fill-range@^4.0.0: fill-range@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.0.1.tgz#1919a6a7c75fe38b2c7c77e5198535da9acdda40" + resolved "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz" integrity sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ== dependencies: to-regex-range "^5.0.1" find-cache-dir@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-2.1.0.tgz#8d0f94cd13fe43c6c7c261a0d86115ca918c05f7" + resolved "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz" integrity sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ== dependencies: commondir "^1.0.1" make-dir "^2.0.0" pkg-dir "^3.0.0" -find-up@^1.0.0: - version "1.1.2" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-1.1.2.tgz#6b2e9822b1a2ce0a60ab64d610eccad53cb24d0f" - integrity sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8= - dependencies: - path-exists "^2.0.0" - pinkie-promise "^2.0.0" - -find-up@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" - integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= - dependencies: - locate-path "^2.0.0" - find-up@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-3.0.0.tgz#49169f1d7993430646da61ecc5ae355c21c97b73" + resolved "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz" integrity sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg== dependencies: locate-path "^3.0.0" find-up@^4.0.0, find-up@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" + resolved "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz" integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== dependencies: locate-path "^5.0.0" @@ -5173,7 +2880,7 @@ find-up@^4.0.0, find-up@^4.1.0: flush-write-stream@^1.0.0: version "1.1.1" - resolved "https://registry.yarnpkg.com/flush-write-stream/-/flush-write-stream-1.1.1.tgz#8dd7d873a1babc207d94ead0c2e0e44276ebf2e8" + resolved "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.1.1.tgz" integrity sha512-3Z4XhFZ3992uIq0XOqb9AreonueSYphE6oYbpt5+3u06JWklbsPkNv3ZKkP9Bz/r+1MWCaMoSQ28P85+1Yc77w== dependencies: inherits "^2.0.3" @@ -5181,17 +2888,17 @@ flush-write-stream@^1.0.0: for-in@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" + resolved "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz" integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= forever-agent@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" + resolved "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz" integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= form-data@~2.3.2: version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" + resolved "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz" integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== dependencies: asynckit "^0.4.0" @@ -5200,14 +2907,14 @@ form-data@~2.3.2: fragment-cache@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" + resolved "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz" integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= dependencies: map-cache "^0.2.2" from2@^2.1.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/from2/-/from2-2.3.0.tgz#8bfb5502bde4a4d36cfdeea007fcca21d7e382af" + resolved "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz" integrity sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8= dependencies: inherits "^2.0.1" @@ -5215,45 +2922,35 @@ from2@^2.1.0: fs-constants@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad" + resolved "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz" integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow== fs-extra@^8.1.0: version "8.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz" integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g== dependencies: graceful-fs "^4.2.0" jsonfile "^4.0.0" universalify "^0.1.0" -fs-extra@^9.1.0: - version "9.1.0" - resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-9.1.0.tgz#5954460c764a8da2094ba3554bf839e6b9a7c86d" - integrity sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ== - dependencies: - at-least-node "^1.0.0" - graceful-fs "^4.2.0" - jsonfile "^6.0.1" - universalify "^2.0.0" - -fs-minipass@^1.2.5, fs-minipass@^1.2.7: +fs-minipass@^1.2.7: version "1.2.7" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.7.tgz#ccff8570841e7fe4265693da88936c55aed7f7c7" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz" integrity sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA== dependencies: minipass "^2.6.0" fs-minipass@^2.0.0, fs-minipass@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-2.1.0.tgz#7f5036fdbf12c63c169190cbe4199c852271f9fb" + resolved "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz" integrity sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg== dependencies: minipass "^3.0.0" fs-write-stream-atomic@^1.0.8: version "1.0.10" - resolved "https://registry.yarnpkg.com/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz#b47df53493ef911df75731e70a9ded0189db40c9" + resolved "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz" integrity sha1-tH31NJPvkR33VzHnCp3tAYnbQMk= dependencies: graceful-fs "^4.1.2" @@ -5263,12 +2960,12 @@ fs-write-stream-atomic@^1.0.8: fs.realpath@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" + resolved "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz" integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= fsevents@^1.2.7: version "1.2.9" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-1.2.9.tgz#3f5ed66583ccd6f400b5a00db6f7e861363e388f" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-1.2.9.tgz" integrity sha512-oeyj2H3EjjonWcFjD5NvZNE9Rqe4UW+nQBU2HNeKw0koVLEFIhtyETyAakeAM3de7Z/SW5kcA+fZUait9EApnw== dependencies: nan "^2.12.1" @@ -5276,17 +2973,12 @@ fsevents@^1.2.7: fsevents@^2.1.2, fsevents@~2.3.2: version "2.3.2" - resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.3.2.tgz#8a526f78b8fdf4623b709e0b975c52c24c02fd1a" + resolved "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz" integrity sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA== -function-bind@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d" - integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A== - gauge@~2.7.3: version "2.7.4" - resolved "https://registry.yarnpkg.com/gauge/-/gauge-2.7.4.tgz#2c03405c7538c39d7eb37b317022e325fb018bf7" + resolved "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz" integrity sha1-LANAXHU4w51+s3sxcCLjJfsBi/c= dependencies: aproba "^1.0.3" @@ -5298,189 +2990,75 @@ gauge@~2.7.3: strip-ansi "^3.0.1" wide-align "^1.1.0" -genfun@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/genfun/-/genfun-5.0.0.tgz#9dd9710a06900a5c4a5bf57aca5da4e52fe76537" - integrity sha512-KGDOARWVga7+rnB3z9Sd2Letx515owfk0hSxHGuqjANb1M+x2bGZGqHLiozPsYMdM2OubeMni/Hpwmjq6qIUhA== - gensync@^1.0.0-beta.1: version "1.0.0-beta.1" - resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.1.tgz#58f4361ff987e5ff6e1e7a210827aa371eaac269" + resolved "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.1.tgz" integrity sha512-r8EC6NO1sngH/zdD9fiRDLdcgnbayXah+mLgManTaIZJqEC1MZstmnox8KpnI2/fxQwrp5OpCOYWLp4rBl4Jcg== get-caller-file@^2.0.1, get-caller-file@^2.0.5: version "2.0.5" - resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" + resolved "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz" integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== get-own-enumerable-property-symbols@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz#6f7764f88ea11e0b514bd9bd860a132259992ca4" + resolved "https://registry.npmjs.org/get-own-enumerable-property-symbols/-/get-own-enumerable-property-symbols-3.0.1.tgz" integrity sha512-09/VS4iek66Dh2bctjRkowueRJbY1JDGR1L/zRxO1Qk8Uxs6PnqaNSqalpizPT+CDjre3hnEsuzvhgomz9qYrA== get-package-type@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/get-package-type/-/get-package-type-0.1.0.tgz#8de2d803cff44df3bc6c456e6668b36c3926e11a" + resolved "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz" integrity sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q== -get-pkg-repo@^1.0.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-1.4.0.tgz#c73b489c06d80cc5536c2c853f9e05232056972d" - integrity sha1-xztInAbYDMVTbCyFP54FIyBWly0= - dependencies: - hosted-git-info "^2.1.4" - meow "^3.3.0" - normalize-package-data "^2.3.0" - parse-github-repo-url "^1.3.0" - through2 "^2.0.0" - -get-pkg-repo@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/get-pkg-repo/-/get-pkg-repo-4.2.1.tgz#75973e1c8050c73f48190c52047c4cee3acbf385" - integrity sha512-2+QbHjFRfGB74v/pYWjd5OhU3TDIC2Gv/YKUTk/tCvAz0pkn/Mz6P3uByuBimLOcPvN2jYdScl3xGFSrx0jEcA== - dependencies: - "@hutson/parse-repository-url" "^3.0.0" - hosted-git-info "^4.0.0" - through2 "^2.0.0" - yargs "^16.2.0" - -get-port@^4.2.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-4.2.0.tgz#e37368b1e863b7629c43c5a323625f95cf24b119" - integrity sha512-/b3jarXkH8KJoOMQc3uVGHASwGLPq3gSFJ7tgJm2diza+bydJPTGOibin2steecKeOylE8oY2JERlVWkAJO6yw== - -get-port@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/get-port/-/get-port-5.1.1.tgz#0469ed07563479de6efb986baf053dcd7d4e3193" - integrity sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ== - -get-stdin@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/get-stdin/-/get-stdin-4.0.1.tgz#b968c6b0a04384324902e8bf1a5df32579a450fe" - integrity sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4= - -get-stream@^4.0.0, get-stream@^4.1.0: +get-stream@^4.0.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-4.1.0.tgz" integrity sha512-GMat4EJ5161kIy2HevLlr4luNjBgvmj413KaQA7jt4V8B4RDsfpHk7WQ9GVqfYyyx8OS/L66Kox+rJRNklLK7w== dependencies: pump "^3.0.0" get-stream@^5.0.0, get-stream@^5.1.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-5.2.0.tgz#4966a1795ee5ace65e706c4b7beb71257d6e22d3" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz" integrity sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA== dependencies: pump "^3.0.0" get-stream@^6.0.0: version "6.0.1" - resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-6.0.1.tgz#a262d8eef67aced57c2852ad6167526a43cbf7b7" + resolved "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz" integrity sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg== get-value@^2.0.3, get-value@^2.0.6: version "2.0.6" - resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" + resolved "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz" integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= getpass@^0.1.1: version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" + resolved "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz" integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= dependencies: assert-plus "^1.0.0" -git-raw-commits@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.0.tgz#d92addf74440c14bcc5c83ecce3fb7f8a79118b5" - integrity sha512-w4jFEJFgKXMQJ0H0ikBk2S+4KP2VEjhCvLCNqbNRQC8BgGWgLKNCO7a9K9LI+TVT7Gfoloje502sEnctibffgg== - dependencies: - dargs "^4.0.1" - lodash.template "^4.0.2" - meow "^4.0.0" - split2 "^2.0.0" - through2 "^2.0.0" - -git-raw-commits@^2.0.8: - version "2.0.10" - resolved "https://registry.yarnpkg.com/git-raw-commits/-/git-raw-commits-2.0.10.tgz#e2255ed9563b1c9c3ea6bd05806410290297bbc1" - integrity sha512-sHhX5lsbG9SOO6yXdlwgEMQ/ljIn7qMpAbJZCGfXX2fq5T8M5SrDnpYk9/4HswTildcIqatsWa91vty6VhWSaQ== - dependencies: - dargs "^7.0.0" - lodash "^4.17.15" - meow "^8.0.0" - split2 "^3.0.0" - through2 "^4.0.0" - -git-remote-origin-url@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/git-remote-origin-url/-/git-remote-origin-url-2.0.0.tgz#5282659dae2107145a11126112ad3216ec5fa65f" - integrity sha1-UoJlna4hBxRaERJhEq0yFuxfpl8= - dependencies: - gitconfiglocal "^1.0.0" - pify "^2.3.0" - -git-semver-tags@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-2.0.3.tgz#48988a718acf593800f99622a952a77c405bfa34" - integrity sha512-tj4FD4ww2RX2ae//jSrXZzrocla9db5h0V7ikPl1P/WwoZar9epdUhwR7XHXSgc+ZkNq72BEEerqQuicoEQfzA== - dependencies: - meow "^4.0.0" - semver "^6.0.0" - -git-semver-tags@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/git-semver-tags/-/git-semver-tags-4.1.1.tgz#63191bcd809b0ec3e151ba4751c16c444e5b5780" - integrity sha512-OWyMt5zBe7xFs8vglMmhM9lRQzCWL3WjHtxNNfJTMngGym7pC1kh8sP6jevfydJ6LP3ZvGxfb6ABYgPUM0mtsA== - dependencies: - meow "^8.0.0" - semver "^6.0.0" - -git-up@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/git-up/-/git-up-4.0.1.tgz#cb2ef086653640e721d2042fe3104857d89007c0" - integrity sha512-LFTZZrBlrCrGCG07/dm1aCjjpL1z9L3+5aEeI9SBhAqSc+kiA9Or1bgZhQFNppJX6h/f5McrvJt1mQXTFm6Qrw== - dependencies: - is-ssh "^1.3.0" - parse-url "^5.0.0" - -git-url-parse@^11.1.2, git-url-parse@^11.4.4: - version "11.6.0" - resolved "https://registry.yarnpkg.com/git-url-parse/-/git-url-parse-11.6.0.tgz#c634b8de7faa66498a2b88932df31702c67df605" - integrity sha512-WWUxvJs5HsyHL6L08wOusa/IXYtMuCAhrMmnTjQPpBU0TTHyDhnOATNH3xNQz7YOQUsqIIPTGr4xiVti1Hsk5g== - dependencies: - git-up "^4.0.0" - -gitconfiglocal@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/gitconfiglocal/-/gitconfiglocal-1.0.0.tgz#41d045f3851a5ea88f03f24ca1c6178114464b9b" - integrity sha1-QdBF84UaXqiPA/JMocYXgRRGS5s= - dependencies: - ini "^1.3.2" - glob-parent@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz" integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= dependencies: is-glob "^3.1.0" path-dirname "^1.0.0" -glob-parent@^5.0.0, glob-parent@^5.1.0, glob-parent@^5.1.1, glob-parent@~5.1.2: +glob-parent@^5.1.0, glob-parent@~5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" + resolved "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz" integrity sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow== dependencies: is-glob "^4.0.1" -glob-to-regexp@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" - integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= - -glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.0, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: version "7.1.7" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.7.tgz#3b193e9233f01d42d0b3f78294bbeeb418f94a90" + resolved "https://registry.npmjs.org/glob/-/glob-7.1.7.tgz" integrity sha512-OvD9ENzPLbegENnYP5UUfJIirTg4+XwMWGaQfQTY0JenxNvvIKP3U3/tAQSPIu/lHxXYSZmpXlUHeqAIdKzBLQ== dependencies: fs.realpath "^1.0.0" @@ -5492,12 +3070,12 @@ glob@^7.0.0, glob@^7.0.3, glob@^7.1.1, glob@^7.1.2, glob@^7.1.3, glob@^7.1.4, gl globals@^11.1.0: version "11.12.0" - resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e" + resolved "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz" integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA== -globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: +globby@^11.0.4: version "11.0.4" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.4.tgz#2cbaff77c2f2a62e71e9b2813a67b97a3a3001a5" + resolved "https://registry.npmjs.org/globby/-/globby-11.0.4.tgz" integrity sha512-9O4MVG9ioZJ08ffbcyVYyLOJLk5JQ688pJ4eMGLpdWLHq/Wr1D9BlriLQyL0E+jbkuePVZXYFj47QM/v093wHg== dependencies: array-union "^2.1.0" @@ -5507,40 +3085,26 @@ globby@^11.0.2, globby@^11.0.3, globby@^11.0.4: merge2 "^1.3.0" slash "^3.0.0" -globby@^9.2.0: - version "9.2.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" - integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== - dependencies: - "@types/glob" "^7.1.1" - array-union "^1.0.2" - dir-glob "^2.2.2" - fast-glob "^2.2.6" - glob "^7.1.3" - ignore "^4.0.3" - pify "^4.0.1" - slash "^2.0.0" - graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.5, graceful-fs@^4.1.6, graceful-fs@^4.2.0, graceful-fs@^4.2.3, graceful-fs@^4.2.4: version "4.2.8" - resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.8.tgz#e412b8d33f5e006593cbd3cee6df9f2cebbe802a" + resolved "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.8.tgz" integrity sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg== growly@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081" + resolved "https://registry.npmjs.org/growly/-/growly-1.3.0.tgz" integrity sha1-8QdIy+dq+WS3yWyTxrzCivEgwIE= gzip-size@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/gzip-size/-/gzip-size-6.0.0.tgz#065367fd50c239c0671cbcbad5be3e2eeb10e462" + resolved "https://registry.npmjs.org/gzip-size/-/gzip-size-6.0.0.tgz" integrity sha512-ax7ZYomf6jqPTQ4+XCpUGyXKHk5WweS+e05MBO4/y3WJ5RkmPXNKvX+bx1behVILVwr6JSQvZAku021CHPXG3Q== dependencies: duplexer "^0.1.2" -handlebars@^4.7.0, handlebars@^4.7.6: +handlebars@^4.7.0: version "4.7.7" - resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.7.tgz#9ce33416aad02dbd6c8fafa8240d5d98004945a1" + resolved "https://registry.npmjs.org/handlebars/-/handlebars-4.7.7.tgz" integrity sha512-aAcXm5OAfE/8IXkcZvCepKU3VzW1/39Fb5ZuqMtgI/hT8X2YgoMvBY5dLhq/cpOvw7Lk1nK/UF71aLG/ZnVYRA== dependencies: minimist "^1.2.5" @@ -5552,45 +3116,35 @@ handlebars@^4.7.0, handlebars@^4.7.6: har-schema@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" + resolved "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz" integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= har-validator@~5.1.3: version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" + resolved "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz" integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== dependencies: ajv "^6.5.5" har-schema "^2.0.0" -hard-rejection@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883" - integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA== - has-flag@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz" integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= has-flag@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" + resolved "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== -has-symbols@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.0.tgz#ba1a8f1af2a0fc39650f5c850367704122063b44" - integrity sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q= - -has-unicode@^2.0.0, has-unicode@^2.0.1: +has-unicode@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/has-unicode/-/has-unicode-2.0.1.tgz#e0e6fe6a28cf51138855e086d1691e771de2a8b9" + resolved "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz" integrity sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk= has-value@^0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" + resolved "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz" integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= dependencies: get-value "^2.0.3" @@ -5599,7 +3153,7 @@ has-value@^0.3.1: has-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" + resolved "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz" integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= dependencies: get-value "^2.0.6" @@ -5608,27 +3162,20 @@ has-value@^1.0.0: has-values@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" + resolved "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz" integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= has-values@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" + resolved "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz" integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= dependencies: is-number "^3.0.0" kind-of "^4.0.0" -has@^1.0.1, has@^1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/has/-/has-1.0.3.tgz#722d7cbfc1f6aa8241f16dd814e011e1f41e8796" - integrity sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw== - dependencies: - function-bind "^1.1.1" - hash-base@^3.0.0: version "3.0.4" - resolved "https://registry.yarnpkg.com/hash-base/-/hash-base-3.0.4.tgz#5fc8686847ecd73499403319a6b0a3f3f6ae4918" + resolved "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz" integrity sha1-X8hoaEfs1zSZQDMZprCj8/auSRg= dependencies: inherits "^2.0.1" @@ -5636,7 +3183,7 @@ hash-base@^3.0.0: hash.js@^1.0.0, hash.js@^1.0.3: version "1.1.7" - resolved "https://registry.yarnpkg.com/hash.js/-/hash.js-1.1.7.tgz#0babca538e8d4ee4a0f8988d68866537a003cf42" + resolved "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz" integrity sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA== dependencies: inherits "^2.0.3" @@ -5644,63 +3191,50 @@ hash.js@^1.0.0, hash.js@^1.0.3: highlight.js@^9.17.1: version "9.18.5" - resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-9.18.5.tgz#d18a359867f378c138d6819edfc2a8acd5f29825" + resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.18.5.tgz" integrity sha512-a5bFyofd/BHCX52/8i8uJkjr9DYwXIPnM/plwI6W7ezItLGqzt7X2G2nXuYSfsIJdkwwj/g9DG1LkcGJI/dDoA== hmac-drbg@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1" + resolved "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz" integrity sha1-0nRXAQJabHdabFRXk+1QL8DGSaE= dependencies: hash.js "^1.0.3" minimalistic-assert "^1.0.0" minimalistic-crypto-utils "^1.0.1" -hosted-git-info@^2.1.4, hosted-git-info@^2.7.1: +hosted-git-info@^2.1.4: version "2.8.9" resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-2.8.9.tgz#dffc0bf9a21c02209090f2aa69429e1414daf3f9" integrity sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw== -hosted-git-info@^4.0.0, hosted-git-info@^4.0.1: +hosted-git-info@^4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/hosted-git-info/-/hosted-git-info-4.0.2.tgz#5e425507eede4fea846b7262f0838456c4209961" + resolved "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-4.0.2.tgz" integrity sha512-c9OGXbZ3guC/xOlCg1Ci/VgWlwsqDv1yMQL1CWqXDL0hDjXuNcq0zuR4xqPSuasI3kqFDhqSyTjREz5gzq0fXg== dependencies: lru-cache "^6.0.0" html-encoding-sniffer@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz#42a6dc4fd33f00281176e8b23759ca4e4fa185f3" + resolved "https://registry.npmjs.org/html-encoding-sniffer/-/html-encoding-sniffer-2.0.1.tgz" integrity sha512-D5JbOMBIR/TVZkubHT+OyT2705QvogUW4IBn6nHd756OwieSF9aDYFj4dv6HHEVGYbHaLETa3WggZYWWMyy3ZQ== dependencies: whatwg-encoding "^1.0.5" html-escaper@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" + resolved "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== -http-cache-semantics@^3.8.1: - version "3.8.1" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-3.8.1.tgz#39b0e16add9b605bf0a9ef3d9daaf4843b4cacd2" - integrity sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w== - -http-cache-semantics@^4.0.4, http-cache-semantics@^4.1.0: +http-cache-semantics@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz#49e91c5cbf36c9b94bcfcd71c23d5249ec74e390" + resolved "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.0.tgz" integrity sha512-carPklcUh7ROWRK7Cv27RPtdhYhUsela/ue5/jKzjegVvXDqM2ILE9Q2BGn9JZJh1g87cp56su/FgQSzcWS8cQ== -http-proxy-agent@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-2.1.0.tgz#e4821beef5b2142a2026bd73926fe537631c5405" - integrity sha512-qwHbBLV7WviBl0rQsOzH6o5lwyOIvwp/BdFnvVxXORldu5TmjFfjzBcWUWS5kWAZhmv+JtiDhSuQCp4sBfbIgg== - dependencies: - agent-base "4" - debug "3.1.0" - http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz#8a8c8ef7f5932ccf953c296ca8291b95aa74aa3a" + resolved "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-4.0.1.tgz" integrity sha512-k0zdNgqWTGA6aeIRVpvfVob4fL52dTfaehylg0Y4UvSySvOq/Y+BOyPrgpUrA7HylqvU8vIZGsRuXmspskV0Tg== dependencies: "@tootallnate/once" "1" @@ -5709,7 +3243,7 @@ http-proxy-agent@^4.0.0, http-proxy-agent@^4.0.1: http-signature@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" + resolved "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz" integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= dependencies: assert-plus "^1.0.0" @@ -5718,74 +3252,66 @@ http-signature@~1.2.0: https-browserify@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/https-browserify/-/https-browserify-1.0.0.tgz#ec06c10e0a34c0f2faf199f7fd7fc78fffd03c73" + resolved "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz" integrity sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM= https-proxy-agent@5.0.0, https-proxy-agent@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz#e2a90542abb68a762e0a0850f6c9edadfd8506b2" + resolved "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.0.tgz" integrity sha512-EkYm5BcKUGiduxzSt3Eppko+PiNWNEpa4ySk9vTC6wDsQJW9rHSa+UhGNJoRYp7bz6Ht1eaRIa6QaJqO5rCFbA== dependencies: agent-base "6" debug "4" -https-proxy-agent@^2.2.3: - version "2.2.4" - resolved "https://registry.yarnpkg.com/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz#4ee7a737abd92678a293d9b34a1af4d0d08c787b" - integrity sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg== - dependencies: - agent-base "^4.3.0" - debug "^3.1.0" - human-signals@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-1.1.1.tgz#c5b1cd14f50aeae09ab6c59fe63ba3395fe4dfa3" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz" integrity sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw== human-signals@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" + resolved "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== humanize-ms@^1.2.1: version "1.2.1" - resolved "https://registry.yarnpkg.com/humanize-ms/-/humanize-ms-1.2.1.tgz#c46e3159a293f6b896da29316d8b6fe8bb79bbed" + resolved "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz" integrity sha1-xG4xWaKT9riW2ikxbYtv6Lt5u+0= dependencies: ms "^2.0.0" husky@^7.0.0: version "7.0.2" - resolved "https://registry.yarnpkg.com/husky/-/husky-7.0.2.tgz#21900da0f30199acca43a46c043c4ad84ae88dff" + resolved "https://registry.npmjs.org/husky/-/husky-7.0.2.tgz" integrity sha512-8yKEWNX4z2YsofXAMT7KvA1g8p+GxtB1ffV8XtpAEGuXNAbCV5wdNKH+qTpw8SM9fh4aMPDR+yQuKfgnreyZlg== -iconv-lite@0.4.24, iconv-lite@^0.4.24, iconv-lite@^0.4.4: +iconv-lite@0.4.24, iconv-lite@^0.4.4: version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== dependencies: safer-buffer ">= 2.1.2 < 3" iconv-lite@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.6.2.tgz#ce13d1875b0c3a674bd6a04b7f76b01b1b6ded01" + resolved "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.2.tgz" integrity sha512-2y91h5OpQlolefMPmUlivelittSWy0rP+oYVpn6A7GwVHNE8AWzoYOBNmlwks3LobaJxgHCYZAnyNo2GgpNRNQ== dependencies: safer-buffer ">= 2.1.2 < 3.0.0" icss-utils@^5.0.0, icss-utils@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/icss-utils/-/icss-utils-5.1.0.tgz#c6be6858abd013d768e98366ae47e25d5887b1ae" + resolved "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz" integrity sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA== ieee754@^1.1.13, ieee754@^1.1.4: version "1.2.1" - resolved "https://registry.yarnpkg.com/ieee754/-/ieee754-1.2.1.tgz#8eb7a10a63fff25d15a57b001586d177d1b0d352" + resolved "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz" integrity sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA== iferr@^0.1.5: version "0.1.5" - resolved "https://registry.yarnpkg.com/iferr/-/iferr-0.1.5.tgz#c60eed69e6d8fdb6b3104a1fcbca1c192dc5b501" + resolved "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz" integrity sha1-xg7taebY/bazEEofy8ocGS3FtQE= ignore-walk@3.0.4, ignore-walk@^3.0.1, ignore-walk@^3.0.3: @@ -5795,43 +3321,22 @@ ignore-walk@3.0.4, ignore-walk@^3.0.1, ignore-walk@^3.0.3: dependencies: minimatch "^3.0.4" -ignore@^4.0.3: - version "4.0.6" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" - integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== - ignore@^5.1.4: version "5.1.8" - resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.8.tgz#f150a8b50a34289b33e22f5889abd4d8016f0e57" + resolved "https://registry.npmjs.org/ignore/-/ignore-5.1.8.tgz" integrity sha512-BMpfD7PpiETpBl/A6S498BaIJ6Y/ABT93ETbby2fP00v4EbvPBXWEoaR1UBPKs3iR53pJY7EtZk5KACI57i1Uw== -import-fresh@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-2.0.0.tgz#d81355c15612d386c61f9ddd3922d4304822a546" - integrity sha1-2BNVwVYS04bGH53dOSLUMEgipUY= - dependencies: - caller-path "^2.0.0" - resolve-from "^3.0.0" - import-fresh@^3.2.1: version "3.3.0" - resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" + resolved "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz" integrity sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw== dependencies: parent-module "^1.0.0" resolve-from "^4.0.0" -import-local@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-2.0.0.tgz#55070be38a5993cf18ef6db7e961f5bee5c5a09d" - integrity sha512-b6s04m3O+s3CGSbqDIyP4R6aAwAeYlVq9+WUWep6iHa8ETRf9yei1U48C5MmfJmV9AiLYYBKPMq/W+/WRpQmCQ== - dependencies: - pkg-dir "^3.0.0" - resolve-cwd "^2.0.0" - import-local@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/import-local/-/import-local-3.0.2.tgz#a8cfd0431d1de4a2199703d003e3e62364fa6db6" + resolved "https://registry.npmjs.org/import-local/-/import-local-3.0.2.tgz" integrity sha512-vjL3+w0oulAVZ0hBHnxa/Nm5TAurf9YLQJDhqRZyqb+VKGOB6LU8t9H1Nr5CIo16vh9XfJTOoHwU0B71S557gA== dependencies: pkg-dir "^4.2.0" @@ -5839,34 +3344,22 @@ import-local@^3.0.2: imurmurhash@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea" + resolved "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz" integrity sha1-khi5srkoojixPcT7a21XbyMUU+o= -indent-string@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-2.1.0.tgz#8e2d48348742121b4a8218b7a137e9a52049dc80" - integrity sha1-ji1INIdCEhtKghi3oTfppSBJ3IA= - dependencies: - repeating "^2.0.0" - -indent-string@^3.0.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289" - integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok= - indent-string@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251" + resolved "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz" integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg== infer-owner@^1.0.3, infer-owner@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/infer-owner/-/infer-owner-1.0.4.tgz#c4cefcaa8e51051c2a40ba2ce8a3d27295af9467" + resolved "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz" integrity sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A== inflight@^1.0.4: version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" + resolved "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz" integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= dependencies: once "^1.3.0" @@ -5874,188 +3367,106 @@ inflight@^1.0.4: inherits@2, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.1, inherits@~2.0.3: version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== inherits@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.1.tgz#b17d08d326b4423e568eff719f91b0b1cbdf69f1" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz" integrity sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE= inherits@2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" + resolved "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz" integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= -ini@^1.3.2, ini@^1.3.4, ini@~1.3.0: +ini@~1.3.0: version "1.3.8" resolved "https://registry.yarnpkg.com/ini/-/ini-1.3.8.tgz#a29da425b48806f34767a4efce397269af28432c" integrity sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew== -init-package-json@^1.10.3: - version "1.10.3" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-1.10.3.tgz#45ffe2f610a8ca134f2bd1db5637b235070f6cbe" - integrity sha512-zKSiXKhQveNteyhcj1CoOP8tqp1QuxPIPBl8Bid99DGLFqA1p87M6lNgfjJHSBoWJJlidGOv5rWjyYKEB3g2Jw== - dependencies: - glob "^7.1.1" - npm-package-arg "^4.0.0 || ^5.0.0 || ^6.0.0" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "1 || 2" - semver "2.x || 3.x || 4 || 5" - validate-npm-package-license "^3.0.1" - validate-npm-package-name "^3.0.0" - -init-package-json@^2.0.2: - version "2.0.5" - resolved "https://registry.yarnpkg.com/init-package-json/-/init-package-json-2.0.5.tgz#78b85f3c36014db42d8f32117252504f68022646" - integrity sha512-u1uGAtEFu3VA6HNl/yUWw57jmKEMx8SKOxHhxjGnOFUiIlFnohKDFg4ZrPpv9wWqk44nDxGJAtqjdQFm+9XXQA== - dependencies: - npm-package-arg "^8.1.5" - promzard "^0.3.0" - read "~1.0.1" - read-package-json "^4.1.1" - semver "^7.3.5" - validate-npm-package-license "^3.0.4" - validate-npm-package-name "^3.0.0" - -inquirer@^6.2.0: - version "6.5.2" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-6.5.2.tgz#ad50942375d036d327ff528c08bd5fab089928ca" - integrity sha512-cntlB5ghuB0iuO65Ovoi8ogLHiWGs/5yNrtUcKjFhSSiVeAIVpD7koaSU9RM8mpXw5YDi9RdYXGQMaOURB7ycQ== - dependencies: - ansi-escapes "^3.2.0" - chalk "^2.4.2" - cli-cursor "^2.1.0" - cli-width "^2.0.0" - external-editor "^3.0.3" - figures "^2.0.0" - lodash "^4.17.12" - mute-stream "0.0.7" - run-async "^2.2.0" - rxjs "^6.4.0" - string-width "^2.1.0" - strip-ansi "^5.1.0" - through "^2.3.6" - -inquirer@^7.3.3: - version "7.3.3" - resolved "https://registry.yarnpkg.com/inquirer/-/inquirer-7.3.3.tgz#04d176b2af04afc157a83fd7c100e98ee0aad003" - integrity sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA== - dependencies: - ansi-escapes "^4.2.1" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-width "^3.0.0" - external-editor "^3.0.3" - figures "^3.0.0" - lodash "^4.17.19" - mute-stream "0.0.8" - run-async "^2.4.0" - rxjs "^6.6.0" - string-width "^4.1.0" - strip-ansi "^6.0.0" - through "^2.3.6" - interpret@^1.0.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" + resolved "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz" integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== ip-regex@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" + resolved "https://registry.npmjs.org/ip-regex/-/ip-regex-2.1.0.tgz" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= -ip@1.1.5, ip@^1.1.5: +ip@^1.1.5: version "1.1.5" - resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + resolved "https://registry.npmjs.org/ip/-/ip-1.1.5.tgz" integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= is-absolute-url@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/is-absolute-url/-/is-absolute-url-3.0.3.tgz#96c6a22b6a23929b11ea0afb1836c36ad4a5d698" + resolved "https://registry.npmjs.org/is-absolute-url/-/is-absolute-url-3.0.3.tgz" integrity sha512-opmNIX7uFnS96NtPmhWQgQx6/NYFgsUXYMllcfzwWKUMwfo8kku1TvE6hkNcH+Q1ts5cMVrsY7j0bxXQDciu9Q== is-accessor-descriptor@^0.1.6: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz" integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= dependencies: kind-of "^3.0.2" is-accessor-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" + resolved "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz" integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== dependencies: kind-of "^6.0.0" is-arrayish@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" + resolved "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz" integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= is-binary-path@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-1.0.1.tgz#75f16642b480f187a711c814161fd3a4a7655898" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz" integrity sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg= dependencies: binary-extensions "^1.0.0" is-binary-path@~2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09" + resolved "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz" integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw== dependencies: binary-extensions "^2.0.0" is-buffer@^1.1.5: version "1.1.6" - resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" + resolved "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz" integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== -is-callable@^1.1.4: - version "1.1.4" - resolved "https://registry.yarnpkg.com/is-callable/-/is-callable-1.1.4.tgz#1e1adf219e1eeb684d691f9d6a05ff0d30a24d75" - integrity sha512-r5p9sxJjYnArLjObpjA4xu5EKI3CuKHkJXMhT7kwbpUyIFD1n5PMAsoPvWnvtZiNz7LjkYDRZhd7FlI0eMijEA== - is-ci@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" + resolved "https://registry.npmjs.org/is-ci/-/is-ci-2.0.0.tgz" integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== dependencies: ci-info "^2.0.0" -is-core-module@^2.5.0: - version "2.6.0" - resolved "https://registry.yarnpkg.com/is-core-module/-/is-core-module-2.6.0.tgz#d7553b2526fe59b92ba3e40c8df757ec8a709e19" - integrity sha512-wShG8vs60jKfPWpF2KZRaAtvt3a20OAn7+IJ6hLPECpSABLcKtFKTTI4ZtH5QcBruBHlq+WsdHWyz0BCZW7svQ== - dependencies: - has "^1.0.3" - is-data-descriptor@^0.1.4: version "0.1.4" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz" integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= dependencies: kind-of "^3.0.2" is-data-descriptor@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" + resolved "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz" integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== dependencies: kind-of "^6.0.0" -is-date-object@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-date-object/-/is-date-object-1.0.1.tgz#9aa20eb6aeebbff77fbd33e74ca01b33581d3a16" - integrity sha1-mqIOtq7rv/d/vTPnTKAbM1gdOhY= - is-descriptor@^0.1.0: version "0.1.6" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz" integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== dependencies: is-accessor-descriptor "^0.1.6" @@ -6064,267 +3475,199 @@ is-descriptor@^0.1.0: is-descriptor@^1.0.0, is-descriptor@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" + resolved "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz" integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== dependencies: is-accessor-descriptor "^1.0.0" is-data-descriptor "^1.0.0" kind-of "^6.0.2" -is-directory@^0.3.1: - version "0.3.1" - resolved "https://registry.yarnpkg.com/is-directory/-/is-directory-0.3.1.tgz#61339b6f2475fc772fd9c9d83f5c8575dc154ae1" - integrity sha1-YTObbyR1/Hcv2cnYP1yFddwVSuE= - is-docker@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.0.0.tgz#2cb0df0e75e2d064fe1864c37cdeacb7b2dcf25b" + resolved "https://registry.npmjs.org/is-docker/-/is-docker-2.0.0.tgz" integrity sha512-pJEdRugimx4fBMra5z2/5iRdZ63OhYV0vr0Dwm5+xtW4D1FvRkB8hamMIhnWfyJeDdyr/aa7BDyNbtG38VxgoQ== is-extendable@^0.1.0, is-extendable@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz" integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= is-extendable@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" + resolved "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz" integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== dependencies: is-plain-object "^2.0.4" is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" + resolved "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz" integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= -is-finite@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-finite/-/is-finite-1.1.0.tgz#904135c77fb42c0641d6aa1bcdbc4daa8da082f3" - integrity sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w== - is-fullwidth-code-point@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz#ef9e31386f031a7f0d643af82fde50c457ef00cb" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz" integrity sha1-754xOG8DGn8NZDr4L95QxFfvAMs= dependencies: number-is-nan "^1.0.0" is-fullwidth-code-point@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz#a3b30a5c4f199183167aaab93beefae3ddfb654f" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz" integrity sha1-o7MKXE8ZkYMWeqq5O+764937ZU8= is-fullwidth-code-point@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" + resolved "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== is-generator-fn@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/is-generator-fn/-/is-generator-fn-2.1.0.tgz#7d140adc389aaf3011a8f2a2a4cfa6faadffb118" + resolved "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz" integrity sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ== is-glob@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz" integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= dependencies: is-extglob "^2.1.0" is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" + resolved "https://registry.npmjs.org/is-glob/-/is-glob-4.0.1.tgz" integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== dependencies: is-extglob "^2.1.1" -is-interactive@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" - integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== - is-lambda@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" + resolved "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz" integrity sha1-PZh3iZ5qU+/AFgUEzeFfgubwYdU= is-module@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-module/-/is-module-1.0.0.tgz#3258fb69f78c14d5b815d664336b4cffb6441591" + resolved "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz" integrity sha1-Mlj7afeMFNW4FdZkM2tM/7ZEFZE= is-number@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" + resolved "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz" integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= dependencies: kind-of "^3.0.2" is-number@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/is-number/-/is-number-7.0.0.tgz#7535345b896734d5f80c4d06c50955527a14f12b" + resolved "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz" integrity sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng== -is-obj@^1.0.0, is-obj@^1.0.1: +is-obj@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-1.0.1.tgz#3e4729ac1f5fde025cd7d83a896dab9f4f67db0f" + resolved "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz" integrity sha1-PkcprB9f3gJc19g6iW2rn09n2w8= -is-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/is-obj/-/is-obj-2.0.0.tgz#473fb05d973705e3fd9620545018ca8e22ef4982" - integrity sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w== - -is-plain-obj@^1.0.0, is-plain-obj@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e" - integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4= - -is-plain-obj@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-2.1.0.tgz#45e42e37fccf1f40da8e5f76ee21515840c09287" - integrity sha512-YWnfyRwxL/+SsrWYfOpUtz5b3YD+nyfkHvjbcanzk8zgyO4ASD67uVMRt8k5bM4lLMDnXfriRhOpemw+NfT1eA== - 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" + resolved "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz" integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== dependencies: isobject "^3.0.1" -is-plain-object@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-5.0.0.tgz#4427f50ab3429e9025ea7d52e9043a9ef4159344" - integrity sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q== - is-potential-custom-element-name@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz#0c52e54bcca391bb2c494b21e8626d7336c6e397" + resolved "https://registry.npmjs.org/is-potential-custom-element-name/-/is-potential-custom-element-name-1.0.0.tgz" integrity sha1-DFLlS8yjkbssSUsh6GJtczbG45c= is-reference@^1.1.2: version "1.1.4" - resolved "https://registry.yarnpkg.com/is-reference/-/is-reference-1.1.4.tgz#3f95849886ddb70256a3e6d062b1a68c13c51427" + resolved "https://registry.npmjs.org/is-reference/-/is-reference-1.1.4.tgz" integrity sha512-uJA/CDPO3Tao3GTrxYn6AwkM4nUPJiGGYu5+cB8qbC7WGFlrKZbiRo7SFKxUAEpFUfiHofWCXBUNhvYJMh+6zw== dependencies: "@types/estree" "0.0.39" -is-regex@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/is-regex/-/is-regex-1.0.4.tgz#5517489b547091b0930e095654ced25ee97e9491" - integrity sha1-VRdIm1RwkbCTDglWVM7SXul+lJE= - dependencies: - has "^1.0.1" - is-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-regexp/-/is-regexp-1.0.0.tgz#fd2d883545c46bac5a633e7b9a09e87fa2cb5069" + resolved "https://registry.npmjs.org/is-regexp/-/is-regexp-1.0.0.tgz" integrity sha1-/S2INUXEa6xaYz57mgnof6LLUGk= is-resolvable@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-resolvable/-/is-resolvable-1.1.0.tgz#fb18f87ce1feb925169c9a407c19318a3206ed88" + resolved "https://registry.npmjs.org/is-resolvable/-/is-resolvable-1.1.0.tgz" integrity sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg== -is-ssh@^1.3.0: - version "1.3.1" - resolved "https://registry.yarnpkg.com/is-ssh/-/is-ssh-1.3.1.tgz#f349a8cadd24e65298037a522cf7520f2e81a0f3" - integrity sha512-0eRIASHZt1E68/ixClI8bp2YK2wmBPVWEismTs6M+M099jKgrzl/3E976zIbImSIob48N2/XGe9y7ZiYdImSlg== - dependencies: - protocols "^1.1.0" - is-stream@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz" integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ= is-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3" + resolved "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz" integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw== -is-symbol@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38" - integrity sha512-HS8bZ9ox60yCJLH9snBpIwv9pYUAkcuLhSA1oero1UB5y9aiQpRA8y2ex945AOtCZL1lJDeIk3G5LthswI46Lw== - dependencies: - has-symbols "^1.0.0" - -is-text-path@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/is-text-path/-/is-text-path-1.0.1.tgz#4e1aa0fb51bfbcb3e92688001397202c1775b66e" - integrity sha1-Thqg+1G/vLPpJogAE5cgLBd1tm4= - dependencies: - text-extensions "^1.0.0" - is-typedarray@^1.0.0, is-typedarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" + resolved "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz" integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= is-unicode-supported@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz#3f26c76a809593b52bfa2ecb5710ed2779b522a7" + resolved "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz" integrity sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw== -is-utf8@^0.2.0: - version "0.2.1" - resolved "https://registry.yarnpkg.com/is-utf8/-/is-utf8-0.2.1.tgz#4b0da1442104d1b336340e80797e865cf39f7d72" - integrity sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI= - -is-windows@^1.0.0, is-windows@^1.0.2: +is-windows@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" + resolved "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz" integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== is-wsl@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz" integrity sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0= is-wsl@^2.1.1: version "2.2.0" - resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-2.2.0.tgz#74a4c76e77ca9fd3f932f290c17ea326cd157271" + resolved "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz" integrity sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww== dependencies: is-docker "^2.0.0" isarray@1.0.0, isarray@^1.0.0, isarray@~1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" + resolved "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz" integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= isexe@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" + resolved "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz" integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= isobject@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" + resolved "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz" integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= dependencies: isarray "1.0.0" isobject@^3.0.0, isobject@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" + resolved "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz" integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= isstream@~0.1.2: version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" + resolved "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz" integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= istanbul-lib-coverage@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" + resolved "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz" integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: version "4.0.3" - resolved "https://registry.yarnpkg.com/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz#873c6fff897450118222774696a3f28902d77c1d" + resolved "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-4.0.3.tgz" integrity sha512-BXgQl9kf4WTCPCCpmFGoJkz/+uhvm7h7PFKUYxh7qarQd3ER33vHG//qaE8eN25l07YqZPpHXU9I09l/RD5aGQ== dependencies: "@babel/core" "^7.7.5" @@ -6334,7 +3677,7 @@ istanbul-lib-instrument@^4.0.0, istanbul-lib-instrument@^4.0.3: istanbul-lib-report@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" + resolved "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz" integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== dependencies: istanbul-lib-coverage "^3.0.0" @@ -6343,7 +3686,7 @@ istanbul-lib-report@^3.0.0: istanbul-lib-source-maps@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz#75743ce6d96bb86dc7ee4352cf6366a23f0b1ad9" + resolved "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.0.tgz" integrity sha512-c16LpFRkR8vQXyHZ5nLpY35JZtzj1PQY1iZmesUbf1FZHbIupcWfjgOXBY9YHkLEQ6puz1u4Dgj6qmU/DisrZg== dependencies: debug "^4.1.1" @@ -6352,7 +3695,7 @@ istanbul-lib-source-maps@^4.0.0: istanbul-reports@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" + resolved "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.0.2.tgz" integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== dependencies: html-escaper "^2.0.0" @@ -6360,7 +3703,7 @@ istanbul-reports@^3.0.2: jest-changed-files@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-changed-files/-/jest-changed-files-26.1.0.tgz#de66b0f30453bca2aff98e9400f75905da495305" + resolved "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-26.1.0.tgz" integrity sha512-HS5MIJp3B8t0NRKGMCZkcDUZo36mVRvrDETl81aqljT1S9tqiHRSpyoOvWg9ZilzZG9TDisDNaN1IXm54fLRZw== dependencies: "@jest/types" "^26.1.0" @@ -6369,7 +3712,7 @@ jest-changed-files@^26.1.0: jest-cli@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.1.0.tgz#eb9ec8a18cf3b6aa556d9deaa9e24be12b43ad87" + resolved "https://registry.npmjs.org/jest-cli/-/jest-cli-26.1.0.tgz" integrity sha512-Imumvjgi3rU7stq6SJ1JUEMaV5aAgJYXIs0jPqdUnF47N/Tk83EXfmtvNKQ+SnFVI6t6mDOvfM3aA9Sg6kQPSw== dependencies: "@jest/core" "^26.1.0" @@ -6388,7 +3731,7 @@ jest-cli@^26.1.0: jest-config@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.1.0.tgz#9074f7539acc185e0113ad6d22ed589c16a37a73" + resolved "https://registry.npmjs.org/jest-config/-/jest-config-26.1.0.tgz" integrity sha512-ONTGeoMbAwGCdq4WuKkMcdMoyfs5CLzHEkzFOlVvcDXufZSaIWh/OXMLa2fwKXiOaFcqEw8qFr4VOKJQfn4CVw== dependencies: "@babel/core" "^7.1.0" @@ -6412,7 +3755,7 @@ jest-config@^26.1.0: jest-diff@^25.2.1: version "25.5.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-25.5.0.tgz#1dd26ed64f96667c068cef026b677dfa01afcfa9" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-25.5.0.tgz" integrity sha512-z1kygetuPiREYdNIumRpAHY6RXiGmp70YHptjdaxTWGmA085W3iCnXNx0DhflK3vwrKmrRWyY1wUpkPMVxMK7A== dependencies: chalk "^3.0.0" @@ -6422,7 +3765,7 @@ jest-diff@^25.2.1: jest-diff@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-diff/-/jest-diff-26.1.0.tgz#00a549bdc936c9691eb4dc25d1fbd78bf456abb2" + resolved "https://registry.npmjs.org/jest-diff/-/jest-diff-26.1.0.tgz" integrity sha512-GZpIcom339y0OXznsEKjtkfKxNdg7bVbEofK8Q6MnevTIiR1jNhDWKhRX6X0SDXJlwn3dy59nZ1z55fLkAqPWg== dependencies: chalk "^4.0.0" @@ -6432,14 +3775,14 @@ jest-diff@^26.1.0: jest-docblock@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-docblock/-/jest-docblock-26.0.0.tgz#3e2fa20899fc928cb13bd0ff68bd3711a36889b5" + resolved "https://registry.npmjs.org/jest-docblock/-/jest-docblock-26.0.0.tgz" integrity sha512-RDZ4Iz3QbtRWycd8bUEPxQsTlYazfYn/h5R65Fc6gOfwozFhoImx+affzky/FFBuqISPTqjXomoIGJVKBWoo0w== dependencies: detect-newline "^3.0.0" jest-each@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-each/-/jest-each-26.1.0.tgz#e35449875009a22d74d1bda183b306db20f286f7" + resolved "https://registry.npmjs.org/jest-each/-/jest-each-26.1.0.tgz" integrity sha512-lYiSo4Igr81q6QRsVQq9LIkJW0hZcKxkIkHzNeTMPENYYDw/W/Raq28iJ0sLlNFYz2qxxeLnc5K2gQoFYlu2bA== dependencies: "@jest/types" "^26.1.0" @@ -6450,7 +3793,7 @@ jest-each@^26.1.0: jest-environment-jsdom@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-jsdom/-/jest-environment-jsdom-26.1.0.tgz#9dc7313ffe1b59761dad1fedb76e2503e5d37c5b" + resolved "https://registry.npmjs.org/jest-environment-jsdom/-/jest-environment-jsdom-26.1.0.tgz" integrity sha512-dWfiJ+spunVAwzXbdVqPH1LbuJW/kDL+FyqgA5YzquisHqTi0g9hquKif9xKm7c1bKBj6wbmJuDkeMCnxZEpUw== dependencies: "@jest/environment" "^26.1.0" @@ -6462,7 +3805,7 @@ jest-environment-jsdom@^26.1.0: jest-environment-node@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-environment-node/-/jest-environment-node-26.1.0.tgz#8bb387b3eefb132eab7826f9a808e4e05618960b" + resolved "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-26.1.0.tgz" integrity sha512-DNm5x1aQH0iRAe9UYAkZenuzuJ69VKzDCAYISFHQ5i9e+2Tbeu2ONGY7YStubCLH8a1wdKBgqScYw85+ySxqxg== dependencies: "@jest/environment" "^26.1.0" @@ -6473,17 +3816,17 @@ jest-environment-node@^26.1.0: jest-get-type@^25.2.6: version "25.2.6" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-25.2.6.tgz#0b0a32fab8908b44d508be81681487dbabb8d877" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-25.2.6.tgz" integrity sha512-DxjtyzOHjObRM+sM1knti6or+eOgcGU4xVSb2HNP1TqO4ahsT+rqZg+nyqHWJSvWgKC5cG3QjGFBqxLghiF/Ig== jest-get-type@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-get-type/-/jest-get-type-26.0.0.tgz#381e986a718998dbfafcd5ec05934be538db4039" + resolved "https://registry.npmjs.org/jest-get-type/-/jest-get-type-26.0.0.tgz" integrity sha512-zRc1OAPnnws1EVfykXOj19zo2EMw5Hi6HLbFCSjpuJiXtOWAYIjNsHVSbpQ8bDX7L5BGYGI8m+HmKdjHYFF0kg== jest-haste-map@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-haste-map/-/jest-haste-map-26.1.0.tgz#ef31209be73f09b0d9445e7d213e1b53d0d1476a" + resolved "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-26.1.0.tgz" integrity sha512-WeBS54xCIz9twzkEdm6+vJBXgRBQfdbbXD0dk8lJh7gLihopABlJmIQFdWSDDtuDe4PRiObsjZSUjbJ1uhWEpA== dependencies: "@jest/types" "^26.1.0" @@ -6503,7 +3846,7 @@ jest-haste-map@^26.1.0: jest-jasmine2@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.1.0.tgz#4dfe349b2b2d3c6b3a27c024fd4cb57ac0ed4b6f" + resolved "https://registry.npmjs.org/jest-jasmine2/-/jest-jasmine2-26.1.0.tgz" integrity sha512-1IPtoDKOAG+MeBrKvvuxxGPJb35MTTRSDglNdWWCndCB3TIVzbLThRBkwH9P081vXLgiJHZY8Bz3yzFS803xqQ== dependencies: "@babel/traverse" "^7.1.0" @@ -6526,7 +3869,7 @@ jest-jasmine2@^26.1.0: jest-junit@^11.0.1: version "11.0.1" - resolved "https://registry.yarnpkg.com/jest-junit/-/jest-junit-11.0.1.tgz#944b997b7318efd1f021b4f0fce4937f8d66f392" + resolved "https://registry.npmjs.org/jest-junit/-/jest-junit-11.0.1.tgz" integrity sha512-stgc0mBoiSg/F9qWd4KkmR3K7Nk2u+M/dc1oup7gxz9mrzGcEaU2YL9/0QscVqqg3IOaA1P5ZXtozG/XR6j6nw== dependencies: mkdirp "^1.0.4" @@ -6536,7 +3879,7 @@ jest-junit@^11.0.1: jest-leak-detector@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-leak-detector/-/jest-leak-detector-26.1.0.tgz#039c3a07ebcd8adfa984b6ac015752c35792e0a6" + resolved "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-26.1.0.tgz" integrity sha512-dsMnKF+4BVOZwvQDlgn3MG+Ns4JuLv8jNvXH56bgqrrboyCbI1rQg6EI5rs+8IYagVcfVP2yZFKfWNZy0rK0Hw== dependencies: jest-get-type "^26.0.0" @@ -6544,7 +3887,7 @@ jest-leak-detector@^26.1.0: jest-matcher-utils@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-matcher-utils/-/jest-matcher-utils-26.1.0.tgz#cf75a41bd413dda784f022de5a65a2a5c73a5c92" + resolved "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-26.1.0.tgz" integrity sha512-PW9JtItbYvES/xLn5mYxjMd+Rk+/kIt88EfH3N7w9KeOrHWaHrdYPnVHndGbsFGRJ2d5gKtwggCvkqbFDoouQA== dependencies: chalk "^4.0.0" @@ -6554,7 +3897,7 @@ jest-matcher-utils@^26.1.0: jest-message-util@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-message-util/-/jest-message-util-26.1.0.tgz#52573fbb8f5cea443c4d1747804d7a238a3e233c" + resolved "https://registry.npmjs.org/jest-message-util/-/jest-message-util-26.1.0.tgz" integrity sha512-dY0+UlldiAJwNDJ08SF0HdF32g9PkbF2NRK/+2iMPU40O6q+iSn1lgog/u0UH8ksWoPv0+gNq8cjhYO2MFtT0g== dependencies: "@babel/code-frame" "^7.0.0" @@ -6568,24 +3911,24 @@ jest-message-util@^26.1.0: jest-mock@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-mock/-/jest-mock-26.1.0.tgz#80d8286da1f05a345fbad1bfd6fa49a899465d3d" + resolved "https://registry.npmjs.org/jest-mock/-/jest-mock-26.1.0.tgz" integrity sha512-1Rm8EIJ3ZFA8yCIie92UbxZWj9SuVmUGcyhLHyAhY6WI3NIct38nVcfOPWhJteqSn8V8e3xOMha9Ojfazfpovw== dependencies: "@jest/types" "^26.1.0" jest-pnp-resolver@^1.2.1: version "1.2.2" - resolved "https://registry.yarnpkg.com/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz#b704ac0ae028a89108a4d040b3f919dfddc8e33c" + resolved "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.2.tgz" integrity sha512-olV41bKSMm8BdnuMsewT4jqlZ8+3TCARAXjZGT9jcoSnrfUnRCqnMoF9XEeoWjbzObpqF9dRhHQj0Xb9QdF6/w== jest-regex-util@^26.0.0: version "26.0.0" - resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28" + resolved "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-26.0.0.tgz" integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A== jest-resolve-dependencies@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.1.0.tgz#1ce36472f864a5dadf7dc82fa158e1c77955691b" + resolved "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-26.1.0.tgz" integrity sha512-fQVEPHHQ1JjHRDxzlLU/buuQ9om+hqW6Vo928aa4b4yvq4ZHBtRSDsLdKQLuCqn5CkTVpYZ7ARh2fbA8WkRE6g== dependencies: "@jest/types" "^26.1.0" @@ -6594,7 +3937,7 @@ jest-resolve-dependencies@^26.1.0: jest-resolve@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-resolve/-/jest-resolve-26.1.0.tgz#a530eaa302b1f6fa0479079d1561dd69abc00e68" + resolved "https://registry.npmjs.org/jest-resolve/-/jest-resolve-26.1.0.tgz" integrity sha512-KsY1JV9FeVgEmwIISbZZN83RNGJ1CC+XUCikf/ZWJBX/tO4a4NvA21YixokhdR9UnmPKKAC4LafVixJBrwlmfg== dependencies: "@jest/types" "^26.1.0" @@ -6608,7 +3951,7 @@ jest-resolve@^26.1.0: jest-runner@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.1.0.tgz#457f7fc522afe46ca6db1dccf19f87f500b3288d" + resolved "https://registry.npmjs.org/jest-runner/-/jest-runner-26.1.0.tgz" integrity sha512-elvP7y0fVDREnfqit0zAxiXkDRSw6dgCkzPCf1XvIMnSDZ8yogmSKJf192dpOgnUVykmQXwYYJnCx641uLTgcw== dependencies: "@jest/console" "^26.1.0" @@ -6633,7 +3976,7 @@ jest-runner@^26.1.0: jest-runtime@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.1.0.tgz#45a37af42115f123ed5c51f126c05502da2469cb" + resolved "https://registry.npmjs.org/jest-runtime/-/jest-runtime-26.1.0.tgz" integrity sha512-1qiYN+EZLmG1QV2wdEBRf+Ci8i3VSfIYLF02U18PiUDrMbhfpN/EAMMkJtT02jgJUoaEOpHAIXG6zS3QRMzRmA== dependencies: "@jest/console" "^26.1.0" @@ -6665,14 +4008,14 @@ jest-runtime@^26.1.0: jest-serializer@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-serializer/-/jest-serializer-26.1.0.tgz#72a394531fc9b08e173dc7d297440ac610d95022" + resolved "https://registry.npmjs.org/jest-serializer/-/jest-serializer-26.1.0.tgz" integrity sha512-eqZOQG/0+MHmr25b2Z86g7+Kzd5dG9dhCiUoyUNJPgiqi38DqbDEOlHcNijyfZoj74soGBohKBZuJFS18YTJ5w== dependencies: graceful-fs "^4.2.4" jest-snapshot@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.1.0.tgz#c36ed1e0334bd7bd2fe5ad07e93a364ead7e1349" + resolved "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-26.1.0.tgz" integrity sha512-YhSbU7eMTVQO/iRbNs8j0mKRxGp4plo7sJ3GzOQ0IYjvsBiwg0T1o0zGQAYepza7lYHuPTrG5J2yDd0CE2YxSw== dependencies: "@babel/types" "^7.0.0" @@ -6693,7 +4036,7 @@ jest-snapshot@^26.1.0: jest-util@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-util/-/jest-util-26.1.0.tgz#80e85d4ba820decacf41a691c2042d5276e5d8d8" + resolved "https://registry.npmjs.org/jest-util/-/jest-util-26.1.0.tgz" integrity sha512-rNMOwFQevljfNGvbzNQAxdmXQ+NawW/J72dmddsK0E8vgxXCMtwQ/EH0BiWEIxh0hhMcTsxwAxINt7Lh46Uzbg== dependencies: "@jest/types" "^26.1.0" @@ -6704,7 +4047,7 @@ jest-util@^26.1.0: jest-validate@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.1.0.tgz#942c85ad3d60f78250c488a7f85d8f11a29788e7" + resolved "https://registry.npmjs.org/jest-validate/-/jest-validate-26.1.0.tgz" integrity sha512-WPApOOnXsiwhZtmkDsxnpye+XLb/tUISP+H6cHjfUIXvlG+eKwP+isnivsxlHCPaO9Q5wvbhloIBkdF3qUn+Nw== dependencies: "@jest/types" "^26.1.0" @@ -6716,7 +4059,7 @@ jest-validate@^26.1.0: jest-watcher@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest-watcher/-/jest-watcher-26.1.0.tgz#99812a0cd931f0cb3d153180426135ab83e4d8f2" + resolved "https://registry.npmjs.org/jest-watcher/-/jest-watcher-26.1.0.tgz" integrity sha512-ffEOhJl2EvAIki613oPsSG11usqnGUzIiK7MMX6hE4422aXOcVEG3ySCTDFLn1+LZNXGPE8tuJxhp8OBJ1pgzQ== dependencies: "@jest/test-result" "^26.1.0" @@ -6726,9 +4069,9 @@ jest-watcher@^26.1.0: jest-util "^26.1.0" string-length "^4.0.1" -jest-worker@^26.0.0, jest-worker@^26.1.0, jest-worker@^26.2.1: +jest-worker@^26.0.0, jest-worker@^26.1.0: version "26.6.2" - resolved "https://registry.yarnpkg.com/jest-worker/-/jest-worker-26.6.2.tgz#7f72cbc4d643c365e27b9fd775f9d0eaa9c7a8ed" + resolved "https://registry.npmjs.org/jest-worker/-/jest-worker-26.6.2.tgz" integrity sha512-KWYVV1c4i+jbMpaBC+U++4Va0cp8OisU185o73T1vo99hqi7w8tSJfUXYswwqqrjzwxa6KpRK54WhPvwf5w6PQ== dependencies: "@types/node" "*" @@ -6737,7 +4080,7 @@ jest-worker@^26.0.0, jest-worker@^26.1.0, jest-worker@^26.2.1: jest@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/jest/-/jest-26.1.0.tgz#2f3aa7bcffb9bfd025473f83bbbf46a3af026263" + resolved "https://registry.npmjs.org/jest/-/jest-26.1.0.tgz" integrity sha512-LIti8jppw5BcQvmNJe4w2g1N/3V68HUfAv9zDVm7v+VAtQulGhH0LnmmiVkbNE4M4I43Bj2fXPiBGKt26k9tHw== dependencies: "@jest/core" "^26.1.0" @@ -6746,17 +4089,17 @@ jest@^26.1.0: jquery@^3.4.1: version "3.6.0" - resolved "https://registry.yarnpkg.com/jquery/-/jquery-3.6.0.tgz#c72a09f15c1bdce142f49dbf1170bdf8adac2470" + resolved "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz" integrity sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw== "js-tokens@^3.0.0 || ^4.0.0", js-tokens@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" + resolved "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz" integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== js-yaml@3.14.1, js-yaml@^3.13.1: version "3.14.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.14.1.tgz#dae812fdb3825fa306609a8717383c50c36a0537" + resolved "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz" integrity sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g== dependencies: argparse "^1.0.7" @@ -6764,12 +4107,12 @@ js-yaml@3.14.1, js-yaml@^3.13.1: jsbn@~0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" + resolved "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz" integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= jsdom@^16.2.2: version "16.2.2" - resolved "https://registry.yarnpkg.com/jsdom/-/jsdom-16.2.2.tgz#76f2f7541646beb46a938f5dc476b88705bedf2b" + resolved "https://registry.npmjs.org/jsdom/-/jsdom-16.2.2.tgz" integrity sha512-pDFQbcYtKBHxRaP55zGXCJWgFHkDAYbKcsXEK/3Icu9nKYZkutUXfLBwbD+09XDutkYSHcgfQLZ0qvpAAm9mvg== dependencies: abab "^2.0.3" @@ -6801,72 +4144,63 @@ jsdom@^16.2.2: jsesc@^2.5.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/jsesc/-/jsesc-2.5.2.tgz#80564d2e483dacf6e8ef209650a67df3f0c283a4" + resolved "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz" integrity sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA== -json-parse-better-errors@^1.0.0, json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: +json-parse-better-errors@^1.0.1, json-parse-better-errors@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" + resolved "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz" integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== json-parse-even-better-errors@^2.3.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz#7c47805a94319928e05777405dc12e1f7a4ee02d" + resolved "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz" integrity sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w== json-schema-traverse@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" + resolved "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz" integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== json-schema@0.2.3: version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" + resolved "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz" integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= -json-stringify-safe@^5.0.1, json-stringify-safe@~5.0.1: +json-stringify-safe@~5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" + resolved "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz" integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= json5@2.x, json5@^2.1.2: version "2.1.3" - resolved "https://registry.yarnpkg.com/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz" integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== dependencies: minimist "^1.2.5" json5@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" + resolved "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz" integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== dependencies: minimist "^1.2.0" jsonfile@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" + resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz" integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= optionalDependencies: graceful-fs "^4.1.6" -jsonfile@^6.0.1: - version "6.1.0" - resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-6.1.0.tgz#bc55b2634793c679ec6403094eb13698a6ec0aae" - integrity sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ== - dependencies: - universalify "^2.0.0" - optionalDependencies: - graceful-fs "^4.1.6" - -jsonparse@^1.2.0, jsonparse@^1.3.1: +jsonparse@^1.3.1: version "1.3.1" - resolved "https://registry.yarnpkg.com/jsonparse/-/jsonparse-1.3.1.tgz#3f4dae4a91fac315f71062f8521cc239f1366280" + resolved "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz" integrity sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA= jsprim@^1.2.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" + resolved "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz" integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= dependencies: assert-plus "1.0.0" @@ -6876,36 +4210,36 @@ jsprim@^1.2.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" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz" integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= dependencies: is-buffer "^1.1.5" kind-of@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz" integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= dependencies: is-buffer "^1.1.5" kind-of@^5.0.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz" integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== -kind-of@^6.0.0, kind-of@^6.0.2, kind-of@^6.0.3: +kind-of@^6.0.0, kind-of@^6.0.2: version "6.0.3" - resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" + resolved "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== kleur@^3.0.3: version "3.0.3" - resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + resolved "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz" integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== last-call-webpack-plugin@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz#9742df0e10e3cf46e5c0381c2de90d3a7a2d7555" + resolved "https://registry.npmjs.org/last-call-webpack-plugin/-/last-call-webpack-plugin-3.0.0.tgz" integrity sha512-7KI2l2GIZa9p2spzPIVZBYyNKkN+e/SQPpnjlTiPhdbDW3F86tdKKELxKpzJ5sgU19wQWsACULZmpTPYHeWO5w== dependencies: lodash "^4.17.5" @@ -6913,104 +4247,35 @@ last-call-webpack-plugin@^3.0.0: lcov-parse@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/lcov-parse/-/lcov-parse-1.0.0.tgz#eb0d46b54111ebc561acb4c408ef9363bdc8f7e0" + resolved "https://registry.npmjs.org/lcov-parse/-/lcov-parse-1.0.0.tgz" integrity sha1-6w1GtUER68VhrLTECO+TY73I9+A= -lerna@^3.13.1: - version "3.22.1" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-3.22.1.tgz#82027ac3da9c627fd8bf02ccfeff806a98e65b62" - integrity sha512-vk1lfVRFm+UuEFA7wkLKeSF7Iz13W+N/vFd48aW2yuS7Kv0RbNm2/qcDPV863056LMfkRlsEe+QYOw3palj5Lg== - dependencies: - "@lerna/add" "3.21.0" - "@lerna/bootstrap" "3.21.0" - "@lerna/changed" "3.21.0" - "@lerna/clean" "3.21.0" - "@lerna/cli" "3.18.5" - "@lerna/create" "3.22.0" - "@lerna/diff" "3.21.0" - "@lerna/exec" "3.21.0" - "@lerna/import" "3.22.0" - "@lerna/info" "3.21.0" - "@lerna/init" "3.21.0" - "@lerna/link" "3.21.0" - "@lerna/list" "3.21.0" - "@lerna/publish" "3.22.1" - "@lerna/run" "3.21.0" - "@lerna/version" "3.22.1" - import-local "^2.0.0" - npmlog "^4.1.2" - -lerna@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/lerna/-/lerna-4.0.0.tgz#b139d685d50ea0ca1be87713a7c2f44a5b678e9e" - integrity sha512-DD/i1znurfOmNJb0OBw66NmNqiM8kF6uIrzrJ0wGE3VNdzeOhz9ziWLYiRaZDGGwgbcjOo6eIfcx9O5Qynz+kg== - dependencies: - "@lerna/add" "4.0.0" - "@lerna/bootstrap" "4.0.0" - "@lerna/changed" "4.0.0" - "@lerna/clean" "4.0.0" - "@lerna/cli" "4.0.0" - "@lerna/create" "4.0.0" - "@lerna/diff" "4.0.0" - "@lerna/exec" "4.0.0" - "@lerna/import" "4.0.0" - "@lerna/info" "4.0.0" - "@lerna/init" "4.0.0" - "@lerna/link" "4.0.0" - "@lerna/list" "4.0.0" - "@lerna/publish" "4.0.0" - "@lerna/run" "4.0.0" - "@lerna/version" "4.0.0" - import-local "^3.0.2" - npmlog "^4.1.2" - leven@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/leven/-/leven-3.1.0.tgz#77891de834064cccba82ae7842bb6b14a13ed7f2" + resolved "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz" integrity sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A== levn@~0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/levn/-/levn-0.3.0.tgz#3b09924edf9f083c0490fdd4c0bc4421e04764ee" + resolved "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz" integrity sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4= dependencies: prelude-ls "~1.1.2" type-check "~0.3.2" -libnpmaccess@^4.0.1: - version "4.0.3" - resolved "https://registry.yarnpkg.com/libnpmaccess/-/libnpmaccess-4.0.3.tgz#dfb0e5b0a53c315a2610d300e46b4ddeb66e7eec" - integrity sha512-sPeTSNImksm8O2b6/pf3ikv4N567ERYEpeKRPSmqlNt1dTZbvgpJIzg5vAhXHpw2ISBsELFRelk0jEahj1c6nQ== - dependencies: - aproba "^2.0.0" - minipass "^3.1.1" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - -libnpmpublish@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/libnpmpublish/-/libnpmpublish-4.0.2.tgz#be77e8bf5956131bcb45e3caa6b96a842dec0794" - integrity sha512-+AD7A2zbVeGRCFI2aO//oUmapCwy7GHqPXFJh3qpToSRNU+tXKJ2YFUgjt04LPPAf2dlEH95s6EhIHM1J7bmOw== - dependencies: - normalize-package-data "^3.0.2" - npm-package-arg "^8.1.2" - npm-registry-fetch "^11.0.0" - semver "^7.1.3" - ssri "^8.0.1" - lilconfig@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/lilconfig/-/lilconfig-2.0.3.tgz#68f3005e921dafbd2a2afb48379986aa6d2579fd" + resolved "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.3.tgz" integrity sha512-EHKqr/+ZvdKCifpNrJCKxBTgk5XupZA3y/aCPY9mxfgBzmgh93Mt/WqjjQ38oMxXuvDokaKiM3lAgvSH2sjtHg== lines-and-columns@^1.1.6: version "1.1.6" - resolved "https://registry.yarnpkg.com/lines-and-columns/-/lines-and-columns-1.1.6.tgz#1c00c743b433cd0a4e80758f7b64a57440d9ff00" + resolved "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz" integrity sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA= lint-staged@^11.1.2: version "11.1.2" - resolved "https://registry.yarnpkg.com/lint-staged/-/lint-staged-11.1.2.tgz#4dd78782ae43ee6ebf2969cad9af67a46b33cd90" + resolved "https://registry.npmjs.org/lint-staged/-/lint-staged-11.1.2.tgz" integrity sha512-6lYpNoA9wGqkL6Hew/4n1H6lRqF3qCsujVT0Oq5Z4hiSAM7S6NksPJ3gnr7A7R52xCtiZMcEUNNQ6d6X5Bvh9w== dependencies: chalk "^4.1.1" @@ -7030,7 +4295,7 @@ lint-staged@^11.1.2: listr2@^3.8.2: version "3.12.1" - resolved "https://registry.yarnpkg.com/listr2/-/listr2-3.12.1.tgz#75e515b86c66b60baf253542cc0dced6b60fedaf" + resolved "https://registry.npmjs.org/listr2/-/listr2-3.12.1.tgz" integrity sha512-oB1DlXlCzGPbvWhqYBZUQEPJKqsmebQWofXG6Mpbe3uIvoNl8mctBEojyF13ZyqwQ91clCWXpwsWp+t98K4FOQ== dependencies: cli-truncate "^2.1.0" @@ -7041,56 +4306,14 @@ listr2@^3.8.2: through "^2.3.8" wrap-ansi "^7.0.0" -load-json-file@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-1.1.0.tgz#956905708d58b4bab4c2261b04f59f31c99374c0" - integrity sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA= - dependencies: - graceful-fs "^4.1.2" - parse-json "^2.2.0" - pify "^2.0.0" - pinkie-promise "^2.0.0" - strip-bom "^2.0.0" - -load-json-file@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" - integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= - dependencies: - graceful-fs "^4.1.2" - parse-json "^4.0.0" - pify "^3.0.0" - strip-bom "^3.0.0" - -load-json-file@^5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-5.3.0.tgz#4d3c1e01fa1c03ea78a60ac7af932c9ce53403f3" - integrity sha512-cJGP40Jc/VXUsp8/OrnyKyTZ1y6v/dphm3bioS+RrKXjK2BB6wHUd6JptZEFDGgGahMT+InnZO5i1Ei9mpC8Bw== - dependencies: - graceful-fs "^4.1.15" - parse-json "^4.0.0" - pify "^4.0.1" - strip-bom "^3.0.0" - type-fest "^0.3.0" - -load-json-file@^6.2.0: - version "6.2.0" - resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-6.2.0.tgz#5c7770b42cafa97074ca2848707c61662f4251a1" - integrity sha512-gUD/epcRms75Cw8RT1pUdHugZYM5ce64ucs2GEISABwkRsOQr0q2wm/MV2TKThycIe5e0ytRweW2RZxclogCdQ== - dependencies: - graceful-fs "^4.1.15" - parse-json "^5.0.0" - strip-bom "^4.0.0" - type-fest "^0.6.0" - loader-runner@^2.4.0: version "2.4.0" - resolved "https://registry.yarnpkg.com/loader-runner/-/loader-runner-2.4.0.tgz#ed47066bfe534d7e84c4c7b9998c2a75607d9357" + resolved "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz" integrity sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw== loader-utils@^1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-1.2.3.tgz#1ff5dc6911c9f0a062531a4c04b609406108c2c7" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz" integrity sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA== dependencies: big.js "^5.2.2" @@ -7099,24 +4322,16 @@ loader-utils@^1.2.3: loader-utils@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/loader-utils/-/loader-utils-2.0.0.tgz#e4cace5b816d425a166b5f097e10cd12b36064b0" + resolved "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz" integrity sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ== dependencies: big.js "^5.2.2" emojis-list "^3.0.0" json5 "^2.1.2" -locate-path@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" - integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= - dependencies: - p-locate "^2.0.0" - path-exists "^3.0.0" - locate-path@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-3.0.0.tgz#dbec3b3ab759758071b58fe59fc41871af21400e" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz" integrity sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A== dependencies: p-locate "^3.0.0" @@ -7124,79 +4339,34 @@ locate-path@^3.0.0: locate-path@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" + resolved "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz" integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== dependencies: p-locate "^4.1.0" -lodash._reinterpolate@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz#0ccf2d89166af03b3663c796538b75ac6e114d9d" - integrity sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0= - -lodash.clonedeep@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" - integrity sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8= - -lodash.get@^4.4.2: - version "4.4.2" - resolved "https://registry.yarnpkg.com/lodash.get/-/lodash.get-4.4.2.tgz#2d177f652fa31e939b4438d5341499dfa3825e99" - integrity sha1-LRd/ZS+jHpObRDjVNBSZ36OCXpk= - -lodash.ismatch@^4.4.0: - version "4.4.0" - resolved "https://registry.yarnpkg.com/lodash.ismatch/-/lodash.ismatch-4.4.0.tgz#756cb5150ca3ba6f11085a78849645f188f85f37" - integrity sha1-dWy1FQyjum8RCFp4hJZF8Yj4Xzc= - lodash.memoize@4.x, lodash.memoize@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/lodash.memoize/-/lodash.memoize-4.1.2.tgz#bcc6c49a42a2840ed997f323eada5ecd182e0bfe" + resolved "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz" integrity sha1-vMbEmkKihA7Zl/Mj6tpezRguC/4= -lodash.set@^4.3.2: - version "4.3.2" - resolved "https://registry.yarnpkg.com/lodash.set/-/lodash.set-4.3.2.tgz#d8757b1da807dde24816b0d6a84bea1a76230b23" - integrity sha1-2HV7HagH3eJIFrDWqEvqGnYjCyM= - -lodash.sortby@^4.7.0: - version "4.7.0" - resolved "https://registry.yarnpkg.com/lodash.sortby/-/lodash.sortby-4.7.0.tgz#edd14c824e2cc9c1e0b0a1b42bb5210516a42438" - integrity sha1-7dFMgk4sycHgsKG0K7UhBRakJDg= - -lodash.template@^4.0.2, lodash.template@^4.5.0: - version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.template/-/lodash.template-4.5.0.tgz#f976195cf3f347d0d5f52483569fe8031ccce8ab" - integrity sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.templatesettings "^4.0.0" - -lodash.templatesettings@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz#e481310f049d3cf6d47e912ad09313b154f0fb33" - integrity sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ== - dependencies: - lodash._reinterpolate "^3.0.0" - lodash.uniq@^4.5.0: version "4.5.0" - resolved "https://registry.yarnpkg.com/lodash.uniq/-/lodash.uniq-4.5.0.tgz#d0225373aeb652adc1bc82e4945339a842754773" + resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -lodash@^4.17.12, lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.2.1, lodash@^4.7.0: +lodash@^4.17.13, lodash@^4.17.15, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.7.0: version "4.17.21" - resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== log-driver@^1.2.7: version "1.2.7" - resolved "https://registry.yarnpkg.com/log-driver/-/log-driver-1.2.7.tgz#63b95021f0702fedfa2c9bb0a24e7797d71871d8" + resolved "https://registry.npmjs.org/log-driver/-/log-driver-1.2.7.tgz" integrity sha512-U7KCmLdqsGHBLeWqYlFA0V0Sl6P08EE1ZrmA9cxjUE0WVqT9qnyVDPz1kzpFEP0jdJuFnasWIfSd7fsaNXkpbg== log-symbols@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/log-symbols/-/log-symbols-4.1.0.tgz#3fbdbb95b4683ac9fc785111e792e558d4abd503" + resolved "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz" integrity sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg== dependencies: chalk "^4.1.0" @@ -7204,7 +4374,7 @@ log-symbols@^4.1.0: log-update@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/log-update/-/log-update-4.0.0.tgz#589ecd352471f2a1c0c570287543a64dfd20e0a1" + resolved "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz" integrity sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg== dependencies: ansi-escapes "^4.3.0" @@ -7214,118 +4384,60 @@ log-update@^4.0.0: loose-envify@^1.1.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" + resolved "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz" integrity sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q== dependencies: js-tokens "^3.0.0 || ^4.0.0" -loud-rejection@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f" - integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8= - dependencies: - currently-unhandled "^0.4.1" - signal-exit "^3.0.0" - lru-cache@^5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz" integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== dependencies: yallist "^3.0.2" lru-cache@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" + resolved "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz" integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== dependencies: yallist "^4.0.0" lunr@^2.3.8: version "2.3.9" - resolved "https://registry.yarnpkg.com/lunr/-/lunr-2.3.9.tgz#18b123142832337dd6e964df1a5a7707b25d35e1" + resolved "https://registry.npmjs.org/lunr/-/lunr-2.3.9.tgz" integrity sha512-zTU3DaZaF3Rt9rhN3uBMGQD3dD2/vFQqnvZCDv4dl5iOzq2IZQqTxu90r4E5J+nP70J3ilqVCrbho2eWaeW8Ow== -macos-release@^2.2.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/macos-release/-/macos-release-2.5.0.tgz#067c2c88b5f3fb3c56a375b2ec93826220fa1ff2" - integrity sha512-EIgv+QZ9r+814gjJj0Bt5vSLJLzswGmSUbUpbi9AIr/fsN2IWFBl2NucV9PAiek+U1STK468tEkxmVYUtuAN3g== - magic-string@^0.25.2: version "0.25.4" - resolved "https://registry.yarnpkg.com/magic-string/-/magic-string-0.25.4.tgz#325b8a0a79fc423db109b77fd5a19183b7ba5143" + resolved "https://registry.npmjs.org/magic-string/-/magic-string-0.25.4.tgz" integrity sha512-oycWO9nEVAP2RVPbIoDoA4Y7LFIJ3xRYov93gAyJhZkET1tNuB0u7uWkZS2LpBWTJUWnmau/To8ECWRC+jKNfw== dependencies: sourcemap-codec "^1.4.4" -make-dir@^1.0.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-1.3.0.tgz#79c1033b80515bd6d24ec9933e860ca75ee27f0c" - integrity sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ== - dependencies: - pify "^3.0.0" - -make-dir@^2.0.0, make-dir@^2.1.0: +make-dir@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-2.1.0.tgz#5f0310e18b8be898cc07009295a30ae41e91e6f5" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz" integrity sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA== dependencies: pify "^4.0.1" semver "^5.6.0" make-dir@^3.0.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" - integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== - dependencies: - semver "^6.0.0" - -make-error@1.x, make-error@^1.1.1: - version "1.3.6" - resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2" - integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== - -make-fetch-happen@^5.0.0: - version "5.0.2" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-5.0.2.tgz#aa8387104f2687edca01c8687ee45013d02d19bd" - integrity sha512-07JHC0r1ykIoruKO8ifMXu+xEU8qOXDFETylktdug6vJDACnP+HKevOu3PXyNPzFyTSlz8vrBYlBO1JZRe8Cag== - dependencies: - agentkeepalive "^3.4.1" - cacache "^12.0.0" - http-cache-semantics "^3.8.1" - http-proxy-agent "^2.1.0" - https-proxy-agent "^2.2.3" - lru-cache "^5.1.1" - mississippi "^3.0.0" - node-fetch-npm "^2.0.2" - promise-retry "^1.1.1" - socks-proxy-agent "^4.0.0" - ssri "^6.0.0" - -make-fetch-happen@^8.0.9: - version "8.0.10" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-8.0.10.tgz#f37c5d93d14290488ca6a2ae917a380bd7d24f16" - integrity sha512-jPLPKQjBmDLK5r1BdyDyNKBytmkv2AsDWm2CxHJh+fqhSmC9Pmb7RQxwOq8xQig9+AWIS49+51k4f6vDQ3VnrQ== - dependencies: - agentkeepalive "^4.1.0" - cacache "^15.0.0" - http-cache-semantics "^4.0.4" - http-proxy-agent "^4.0.1" - https-proxy-agent "^5.0.0" - is-lambda "^1.0.1" - lru-cache "^6.0.0" - minipass "^3.1.3" - minipass-collect "^1.0.2" - minipass-fetch "^1.3.0" - minipass-flush "^1.0.5" - minipass-pipeline "^1.2.2" - promise-retry "^1.1.1" - socks-proxy-agent "^5.0.0" - ssri "^8.0.0" + version "3.1.0" + resolved "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz" + integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== + dependencies: + semver "^6.0.0" + +make-error@1.x, make-error@^1.1.1: + version "1.3.6" + resolved "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz" + integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw== make-fetch-happen@^9.0.1: version "9.1.0" - resolved "https://registry.yarnpkg.com/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz#53085a09e7971433e6765f7971bf63f4e05cb968" + resolved "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-9.1.0.tgz" integrity sha512-+zopwDy7DNknmwPQplem5lAZX/eCOzSvSNNcSKm5eVwTkOBzoktEfXsa9L23J/GIRhxRsaxzkPEhrJEpE2F4Gg== dependencies: agentkeepalive "^4.1.3" @@ -7347,46 +4459,31 @@ make-fetch-happen@^9.0.1: makeerror@1.0.x: version "1.0.11" - resolved "https://registry.yarnpkg.com/makeerror/-/makeerror-1.0.11.tgz#e01a5c9109f2af79660e4e8b9587790184f5a96c" + resolved "https://registry.npmjs.org/makeerror/-/makeerror-1.0.11.tgz" integrity sha1-4BpckQnyr3lmDk6LlYd5AYT1qWw= dependencies: tmpl "1.0.x" map-cache@^0.2.2: version "0.2.2" - resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" + resolved "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz" integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= -map-obj@^1.0.0, map-obj@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" - integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= - -map-obj@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9" - integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk= - -map-obj@^4.0.0: - version "4.2.1" - resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.2.1.tgz#e4ea399dbc979ae735c83c863dd31bdf364277b7" - integrity sha512-+WA2/1sPmDj1dlvvJmB5G6JKfY9dpn7EVBUL06+y6PoljPkh+6V1QihwxNkbcGxCRjt2b0F9K0taiCuo7MbdFQ== - map-visit@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" + resolved "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz" integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= dependencies: object-visit "^1.0.0" marked@^0.8.0: version "0.8.2" - resolved "https://registry.yarnpkg.com/marked/-/marked-0.8.2.tgz#4faad28d26ede351a7a1aaa5fec67915c869e355" + resolved "https://registry.npmjs.org/marked/-/marked-0.8.2.tgz" integrity sha512-EGwzEeCcLniFX51DhTpmTom+dSA/MG/OBUDjnWtHbEnjAH180VzUeAw+oE4+Zv+CoYBWyRlYOTR0N8SO9R1PVw== md5.js@^1.3.4: version "1.3.5" - resolved "https://registry.yarnpkg.com/md5.js/-/md5.js-1.3.5.tgz#b5d07b8e3216e3e27cd728d72f70d1e6a342005f" + resolved "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz" integrity sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg== dependencies: hash-base "^3.0.0" @@ -7395,12 +4492,12 @@ md5.js@^1.3.4: mdn-data@2.0.14: version "2.0.14" - resolved "https://registry.yarnpkg.com/mdn-data/-/mdn-data-2.0.14.tgz#7113fc4281917d63ce29b43446f701e68c25ba50" + resolved "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.14.tgz" integrity sha512-dn6wd0uw5GsdswPFfsgMp5NSB0/aDe6fK94YJV/AJDYXL6HVLWBsxeq7js7Ad+mU2K9LAlwpk6kN2D5mwCPVow== memory-fs@^0.4.1: version "0.4.1" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.4.1.tgz#3a9a20b8462523e447cfbc7e8bb80ed667bfc552" + resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz" integrity sha1-OpoguEYlI+RHz7x+i7gO1me/xVI= dependencies: errno "^0.1.3" @@ -7408,80 +4505,32 @@ memory-fs@^0.4.1: memory-fs@^0.5.0: version "0.5.0" - resolved "https://registry.yarnpkg.com/memory-fs/-/memory-fs-0.5.0.tgz#324c01288b88652966d161db77838720845a8e3c" + resolved "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz" integrity sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA== dependencies: errno "^0.1.3" readable-stream "^2.0.1" -meow@^3.3.0: - version "3.7.0" - resolved "https://registry.yarnpkg.com/meow/-/meow-3.7.0.tgz#72cb668b425228290abbfa856892587308a801fb" - integrity sha1-cstmi0JSKCkKu/qFaJJYcwioAfs= - dependencies: - camelcase-keys "^2.0.0" - decamelize "^1.1.2" - loud-rejection "^1.0.0" - map-obj "^1.0.1" - minimist "^1.1.3" - normalize-package-data "^2.3.4" - object-assign "^4.0.1" - read-pkg-up "^1.0.1" - redent "^1.0.0" - trim-newlines "^1.0.0" - -meow@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/meow/-/meow-4.0.1.tgz#d48598f6f4b1472f35bf6317a95945ace347f975" - integrity sha512-xcSBHD5Z86zaOc+781KrupuHAzeGXSLtiAOmBsiLDiPSaYSB6hdew2ng9EBAnZ62jagG9MHAOdxpDi/lWBFJ/A== - dependencies: - camelcase-keys "^4.0.0" - decamelize-keys "^1.0.0" - loud-rejection "^1.0.0" - minimist "^1.1.3" - minimist-options "^3.0.1" - normalize-package-data "^2.3.4" - read-pkg-up "^3.0.0" - redent "^2.0.0" - trim-newlines "^2.0.0" - -meow@^8.0.0: - version "8.1.2" - resolved "https://registry.yarnpkg.com/meow/-/meow-8.1.2.tgz#bcbe45bda0ee1729d350c03cffc8395a36c4e897" - integrity sha512-r85E3NdZ+mpYk1C6RjPFEMSE+s1iZMuHtsHAqY0DT3jZczl0diWUZ8g6oU7h0M9cD2EL+PzaYghhCLzR0ZNn5Q== - dependencies: - "@types/minimist" "^1.2.0" - camelcase-keys "^6.2.2" - decamelize-keys "^1.1.0" - hard-rejection "^2.1.0" - minimist-options "4.1.0" - normalize-package-data "^3.0.0" - read-pkg-up "^7.0.1" - redent "^3.0.0" - trim-newlines "^3.0.0" - type-fest "^0.18.0" - yargs-parser "^20.2.3" - merge-stream@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" + resolved "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.2.3, merge2@^1.3.0: +merge2@^1.3.0: version "1.4.1" - resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" + resolved "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== mico-spinner@^1.2.2: version "1.2.2" - resolved "https://registry.yarnpkg.com/mico-spinner/-/mico-spinner-1.2.2.tgz#0f00cbf45c81b58fbd7d0a7bb2dea8546867d413" + resolved "https://registry.npmjs.org/mico-spinner/-/mico-spinner-1.2.2.tgz" integrity sha512-jIsOIIk5xa+TmZJU2mPVTEk1AC7aKnrj8UJR58cTiK8msNWYvPuQxPx0ojNbtVOut/TjTgGkVLrEt1jsrceYfA== dependencies: colorette "^1.2.2" micromatch@4.x, micromatch@^4.0.2, micromatch@^4.0.4: version "4.0.4" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.4.tgz#896d519dfe9db25fce94ceb7a500919bf881ebf9" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz" integrity sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg== dependencies: braces "^3.0.1" @@ -7489,7 +4538,7 @@ micromatch@4.x, micromatch@^4.0.2, micromatch@^4.0.4: micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" + resolved "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== dependencies: arr-diff "^4.0.0" @@ -7508,7 +4557,7 @@ micromatch@^3.1.10, micromatch@^3.1.4: miller-rabin@^4.0.0: version "4.0.1" - resolved "https://registry.yarnpkg.com/miller-rabin/-/miller-rabin-4.0.1.tgz#f080351c865b0dc562a8462966daa53543c78a4d" + resolved "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz" integrity sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA== dependencies: bn.js "^4.0.0" @@ -7516,85 +4565,58 @@ miller-rabin@^4.0.0: mime-db@1.44.0: version "1.44.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.44.0.tgz#fa11c5eb0aca1334b4233cb4d52f10c5a6272f92" + resolved "https://registry.npmjs.org/mime-db/-/mime-db-1.44.0.tgz" integrity sha512-/NOTfLrsPBVeH7YtFPgsVWveuL+4SjjYxaQ1xtM1KMFj7HdxlBlxeyNLzhyJVx7r4rZGJAZ/6lkKCitSc/Nmpg== mime-types@^2.1.12, mime-types@~2.1.19: version "2.1.27" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.27.tgz#47949f98e279ea53119f5722e0f34e529bec009f" + resolved "https://registry.npmjs.org/mime-types/-/mime-types-2.1.27.tgz" integrity sha512-JIhqnCasI9yD+SsmkquHBxTSEuZdQX5BuQnS2Vc7puQQQ+8yiP5AY5uWhpdv4YL4VM5c6iliiYWPgJ/nJQLp7w== dependencies: mime-db "1.44.0" mime@^2.3.1: version "2.5.2" - resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" + resolved "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz" integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== -mimic-fn@^1.0.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-1.2.0.tgz#820c86a39334640e99516928bd03fca88057d022" - integrity sha512-jf84uxzwiuiIVKiOLpfYk7N46TSy8ubTonmneY9vrpHNAnp0QBt2BxWV9dO3/j+BoVAb+a5G6YDPW3M5HOdMWQ== - mimic-fn@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b" + resolved "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz" integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg== -min-indent@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.1.tgz#a63f681673b30571fbe8bc25686ae746eefa9869" - integrity sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg== - minimalistic-assert@^1.0.0, minimalistic-assert@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz#2e194de044626d4a10e7f7fbc00ce73e83e4d5c7" + resolved "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz" integrity sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A== minimalistic-crypto-utils@^1.0.0, minimalistic-crypto-utils@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz#f6c00c1c0b082246e5c4d99dfb8c7c083b2b582a" + resolved "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz" integrity sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo= minimatch@^3.0.0, minimatch@^3.0.4: version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" + resolved "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz" integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== dependencies: brace-expansion "^1.1.7" -minimist-options@4.1.0: - version "4.1.0" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.1.0.tgz#c0655713c53a8a2ebd77ffa247d342c40f010619" - integrity sha512-Q4r8ghd80yhO/0j1O3B2BjweX3fiHg9cdOwjJd2J76Q135c+NDxGCqdYKQ1SKBuFfgWbAUzBfvYjPUEeNgqN1A== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - kind-of "^6.0.3" - -minimist-options@^3.0.1: - version "3.0.2" - resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954" - integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ== - dependencies: - arrify "^1.0.1" - is-plain-obj "^1.1.0" - -minimist@^1.1.1, minimist@^1.1.3, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: +minimist@^1.1.1, minimist@^1.2.0, minimist@^1.2.3, minimist@^1.2.5: version "1.2.5" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" + resolved "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz" integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== minipass-collect@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/minipass-collect/-/minipass-collect-1.0.2.tgz#22b813bf745dc6edba2576b940022ad6edc8c617" + resolved "https://registry.npmjs.org/minipass-collect/-/minipass-collect-1.0.2.tgz" integrity sha512-6T6lH0H8OG9kITm/Jm6tdooIbogG9e0tLgpY6mphXSm/A9u8Nq1ryBG+Qspiub9LjWlBPsPS3tWQ/Botq4FdxA== dependencies: minipass "^3.0.0" minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: version "1.4.1" - resolved "https://registry.yarnpkg.com/minipass-fetch/-/minipass-fetch-1.4.1.tgz#d75e0091daac1b0ffd7e9d41629faff7d0c1f1b6" + resolved "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-1.4.1.tgz" integrity sha512-CGH1eblLq26Y15+Azk7ey4xh0J/XfJfrCox5LDJiKqI2Q2iwOLOKrlmIaODiSQS8d18jalF6y2K2ePUm0CmShw== dependencies: minipass "^3.1.0" @@ -7605,14 +4627,14 @@ minipass-fetch@^1.3.0, minipass-fetch@^1.3.2: minipass-flush@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/minipass-flush/-/minipass-flush-1.0.5.tgz#82e7135d7e89a50ffe64610a787953c4c4cbb373" + resolved "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz" integrity sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw== dependencies: minipass "^3.0.0" minipass-json-stream@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz#7edbb92588fbfc2ff1db2fc10397acb7b6b44aa7" + resolved "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz" integrity sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg== dependencies: jsonparse "^1.3.1" @@ -7620,21 +4642,21 @@ minipass-json-stream@^1.0.1: minipass-pipeline@^1.2.2, minipass-pipeline@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz#68472f79711c084657c067c5c6ad93cddea8214c" + resolved "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz" integrity sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A== dependencies: minipass "^3.0.0" minipass-sized@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/minipass-sized/-/minipass-sized-1.0.3.tgz#70ee5a7c5052070afacfbc22977ea79def353b70" + resolved "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz" integrity sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g== dependencies: minipass "^3.0.0" -minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: +minipass@^2.6.0, minipass@^2.9.0: version "2.9.0" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-2.9.0.tgz#e713762e7d3e32fed803115cf93e04bca9fcc9a6" + resolved "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz" integrity sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg== dependencies: safe-buffer "^5.1.2" @@ -7642,21 +4664,21 @@ minipass@^2.3.5, minipass@^2.6.0, minipass@^2.8.6, minipass@^2.9.0: minipass@^3.0.0, minipass@^3.1.0, minipass@^3.1.1, minipass@^3.1.3: version "3.1.3" - resolved "https://registry.yarnpkg.com/minipass/-/minipass-3.1.3.tgz#7d42ff1f39635482e15f9cdb53184deebd5815fd" + resolved "https://registry.npmjs.org/minipass/-/minipass-3.1.3.tgz" integrity sha512-Mgd2GdMVzY+x3IJ+oHnVM+KG3lA5c8tnabyJKmHSaG2kAGpudxuOf8ToDkhumF7UzME7DecbQE9uOZhNm7PuJg== dependencies: yallist "^4.0.0" -minizlib@^1.2.1, minizlib@^1.3.3: +minizlib@^1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-1.3.3.tgz#2290de96818a34c29551c8a8d301216bd65a861d" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz" integrity sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q== dependencies: minipass "^2.9.0" minizlib@^2.0.0, minizlib@^2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/minizlib/-/minizlib-2.1.2.tgz#e90d3466ba209b932451508a11ce3d3632145931" + resolved "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz" integrity sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg== dependencies: minipass "^3.0.0" @@ -7664,7 +4686,7 @@ minizlib@^2.0.0, minizlib@^2.1.1: mississippi@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/mississippi/-/mississippi-3.0.0.tgz#ea0a3291f97e0b5e8776b363d5f0a12d94c67022" + resolved "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz" integrity sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA== dependencies: concat-stream "^1.5.0" @@ -7680,53 +4702,32 @@ mississippi@^3.0.0: mixin-deep@^1.2.0: version "1.3.2" - resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" + resolved "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz" integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== dependencies: for-in "^1.0.2" is-extendable "^1.0.1" -mkdirp-infer-owner@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/mkdirp-infer-owner/-/mkdirp-infer-owner-2.0.0.tgz#55d3b368e7d89065c38f32fd38e638f0ab61d316" - integrity sha512-sdqtiFt3lkOaYvTXSRIUjkIdPTcxgv5+fgqYE/5qgwdw12cOrAuzzgzvVExIkH/ul1oeHN3bCLOWSG3XOqbKKw== - dependencies: - chownr "^2.0.0" - infer-owner "^1.0.4" - mkdirp "^1.0.3" - -mkdirp-promise@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/mkdirp-promise/-/mkdirp-promise-5.0.1.tgz#e9b8f68e552c68a9c1713b84883f7a1dd039b8a1" - integrity sha1-6bj2jlUsaKnBcTuEiD96HdA5uKE= - dependencies: - mkdirp "*" +mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: + version "1.0.4" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz" + integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== -mkdirp@*, mkdirp@^0.5.0, mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: +mkdirp@^0.5.1, mkdirp@^0.5.3, mkdirp@^0.5.5, mkdirp@~0.5.1: version "0.5.5" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" + resolved "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz" integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== dependencies: minimist "^1.2.5" -mkdirp@1.x, mkdirp@^1.0.3, mkdirp@^1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e" - integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw== - -mobx@^6.3.0, mobx@^6.3.3: +mobx@^6.3.0: version "6.3.3" - resolved "https://registry.yarnpkg.com/mobx/-/mobx-6.3.3.tgz#a3006c56243b1c7ea4ee671a66f963b9f43cf1af" + resolved "https://registry.npmjs.org/mobx/-/mobx-6.3.3.tgz" integrity sha512-JoNU50rO6d1wHwKPJqKq4rmUMbYnI9CsJmBo+Cu4exBYenFvIN77LWrZENpzW6reZPADtXMmB1DicbDSfy8Clw== -modify-values@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/modify-values/-/modify-values-1.0.1.tgz#b3939fa605546474e3e3e3c63d64bd43b4ee6022" - integrity sha512-xV2bxeN6F7oYjZWTe/YPAy6MN2M+sL4u/Rlm2AHCIVGfo2p1yGmBHQ6vHehl4bRTZBdHu3TSkWdYgkwpYzAGSw== - move-concurrently@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/move-concurrently/-/move-concurrently-1.0.1.tgz#be2c005fda32e0b29af1f05d7c4b33214c701f92" + resolved "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz" integrity sha1-viwAX9oy4LKa8fBdfEszIUxwH5I= dependencies: aproba "^1.1.1" @@ -7738,67 +4739,27 @@ move-concurrently@^1.0.1: ms@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" + resolved "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz" integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= ms@2.1.2, ms@^2.0.0, ms@^2.1.1: version "2.1.2" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" + resolved "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== -multimatch@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-3.0.0.tgz#0e2534cc6bc238d9ab67e1b9cd5fcd85a6dbf70b" - integrity sha512-22foS/gqQfANZ3o+W7ST2x25ueHDVNWl/b9OlGcLpy/iKxjCpvcNCM51YCenUi7Mt/jAjjqv8JwZRs8YP5sRjA== - dependencies: - array-differ "^2.0.3" - array-union "^1.0.2" - arrify "^1.0.1" - minimatch "^3.0.4" - -multimatch@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/multimatch/-/multimatch-5.0.0.tgz#932b800963cea7a31a033328fa1e0c3a1874dbe6" - integrity sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA== - dependencies: - "@types/minimatch" "^3.0.3" - array-differ "^3.0.0" - array-union "^2.1.0" - arrify "^2.0.1" - minimatch "^3.0.4" - -mute-stream@0.0.7: - version "0.0.7" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.7.tgz#3075ce93bc21b8fab43e1bc4da7e8115ed1e7bab" - integrity sha1-MHXOk7whuPq0PhvE2n6BFe0ee6s= - -mute-stream@0.0.8, mute-stream@~0.0.4: - version "0.0.8" - resolved "https://registry.yarnpkg.com/mute-stream/-/mute-stream-0.0.8.tgz#1630c42b2251ff81e2a283de96a5497ea92e5e0d" - integrity sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA== - -mz@^2.5.0: - version "2.7.0" - resolved "https://registry.yarnpkg.com/mz/-/mz-2.7.0.tgz#95008057a56cafadc2bc63dde7f9ff6955948e32" - integrity sha512-z81GNO7nnYMEhrGh9LeymoE4+Yr0Wn5McHIZMK5cfQCl+NDX08sCZgUc9/6MHni9IWuFLm1Z3HTCXu2z9fN62Q== - dependencies: - any-promise "^1.0.0" - object-assign "^4.0.1" - thenify-all "^1.0.0" - nan@^2.12.1: version "2.14.0" - resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== nanoid@^3.1.23, nanoid@^3.1.25: version "3.1.25" - resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-3.1.25.tgz#09ca32747c0e543f0e1814b7d3793477f9c8e152" + resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.25.tgz" integrity sha512-rdwtIXaXCLFAQbnfqDRnI6jaRHp9fTcYBjtFKE8eezcZ7LuLjhUaQGNeMXf1HmRoCH32CLz6XwX0TtxEOS/A3Q== nanomatch@^1.2.9: version "1.2.13" - resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" + resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz" integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== dependencies: arr-diff "^4.0.0" @@ -7815,13 +4776,13 @@ nanomatch@^1.2.9: natural-compare@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" + resolved "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= needle@^2.2.1: - version "2.4.0" - resolved "https://registry.yarnpkg.com/needle/-/needle-2.4.0.tgz#6833e74975c444642590e15a750288c5f939b57c" - integrity sha512-4Hnwzr3mi5L97hMYeNl8wRW/Onhy4nUKR/lVemJ8gJedxxUyBLm9kkrDColJvoSfwi0jCNhD+xCdOtiGDQiRZg== + version "2.9.1" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.9.1.tgz#22d1dffbe3490c2b83e301f7709b6736cd8f2684" + integrity sha512-6R9fqJ5Zcmf+uYaFgdIHmLwNldn5HbK8L5ybn7Uz+ylX/rnOsSp1AHcvQSrCaFN+qNM1wpymHqD7mVasEOlHGQ== dependencies: debug "^3.2.6" iconv-lite "^0.4.4" @@ -7829,53 +4790,27 @@ needle@^2.2.1: negotiator@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" + resolved "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz" integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== neo-async@^2.5.0, neo-async@^2.6.0, neo-async@^2.6.1: version "2.6.1" - resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.1.tgz#ac27ada66167fa8849a6addd837f6b189ad2081c" + resolved "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz" integrity sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw== nice-try@^1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" + resolved "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz" integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== -node-fetch-npm@^2.0.2: - version "2.0.4" - resolved "https://registry.yarnpkg.com/node-fetch-npm/-/node-fetch-npm-2.0.4.tgz#6507d0e17a9ec0be3bec516958a497cec54bf5a4" - integrity sha512-iOuIQDWDyjhv9qSDrj9aq/klt6F9z1p2otB3AV7v3zBDcL/x+OfGsvGQZZCcMZbUf4Ujw1xGNQkjvGnVT22cKg== - dependencies: - encoding "^0.1.11" - json-parse-better-errors "^1.0.0" - safe-buffer "^5.1.1" - -node-fetch@2.6.1, node-fetch@^2.5.0, node-fetch@^2.6.1: +node-fetch@2.6.1, node-fetch@^2.6.1: version "2.6.1" - resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.1.tgz#045bd323631f76ed2e2b55573394416b639a0052" + resolved "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz" integrity sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw== -node-gyp@^5.0.2: - version "5.0.5" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-5.0.5.tgz#f6cf1da246eb8c42b097d7cd4d6c3ce23a4163af" - integrity sha512-WABl9s4/mqQdZneZHVWVG4TVr6QQJZUC6PAx47ITSk9lreZ1n+7Z9mMAIbA3vnO4J9W20P7LhCxtzfWsAD/KDw== - dependencies: - env-paths "^1.0.0" - glob "^7.0.3" - graceful-fs "^4.1.2" - mkdirp "^0.5.0" - nopt "2 || 3" - npmlog "0 || 1 || 2 || 3 || 4" - request "^2.87.0" - rimraf "2" - semver "~5.3.0" - tar "^4.4.12" - which "1" - node-gyp@^7.1.0: version "7.1.2" - resolved "https://registry.yarnpkg.com/node-gyp/-/node-gyp-7.1.2.tgz#21a810aebb187120251c3bcec979af1587b188ae" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-7.1.2.tgz" integrity sha512-CbpcIo7C3eMu3dL1c3d0xw449fHIGALIJsRP4DDPHpyiW8vcriNY7ubh9TE4zEKfSxscY7PjeFnshE7h75ynjQ== dependencies: env-paths "^2.2.0" @@ -7891,12 +4826,12 @@ node-gyp@^7.1.0: node-int64@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b" + resolved "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz" integrity sha1-h6kGXNs1XTGC2PlM4RGIuCXGijs= node-libs-browser@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/node-libs-browser/-/node-libs-browser-2.2.1.tgz#b64f513d18338625f90346d27b0d235e631f6425" + resolved "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz" integrity sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q== dependencies: assert "^1.1.1" @@ -7925,12 +4860,12 @@ node-libs-browser@^2.2.1: node-modules-regexp@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz#8d9dbe28964a4ac5712e9131642107c71e90ec40" + resolved "https://registry.npmjs.org/node-modules-regexp/-/node-modules-regexp-1.0.0.tgz" integrity sha1-jZ2+KJZKSsVxLpExZCEHxx6Q7EA= node-notifier@^7.0.0: version "7.0.1" - resolved "https://registry.yarnpkg.com/node-notifier/-/node-notifier-7.0.1.tgz#a355e33e6bebacef9bf8562689aed0f4230ca6f9" + resolved "https://registry.npmjs.org/node-notifier/-/node-notifier-7.0.1.tgz" integrity sha512-VkzhierE7DBmQEElhTGJIoiZa1oqRijOtgOlsXg32KrJRXsPy0NXFBqWGW/wTswnJlDCs5viRYaqWguqzsKcmg== dependencies: growly "^1.3.0" @@ -7942,7 +4877,7 @@ node-notifier@^7.0.0: node-pre-gyp@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz#39ba4bb1439da030295f899e3b520b7785766149" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.12.0.tgz" integrity sha512-4KghwV8vH5k+g2ylT+sLTjy5wmUOb9vPhnM8NHvRf9dHmnW/CndrFXy2aRPaPST6dugXSdHXfeaHQm77PIz/1A== dependencies: detect-libc "^1.0.2" @@ -7958,16 +4893,9 @@ node-pre-gyp@^0.12.0: node-releases@^1.1.75: version "1.1.75" - resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.75.tgz#6dd8c876b9897a1b8e5a02de26afa79bb54ebbfe" + resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.75.tgz" integrity sha512-Qe5OUajvqrqDSy6wrWFmMwfJ0jVgwiw4T3KqmbTcZ62qW0gQkheXYhcFM1+lOVcGUoRxcEcfyvFMAnDgaF1VWw== -"nopt@2 || 3": - version "3.0.6" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" - integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= - dependencies: - abbrev "1" - nopt@^4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" @@ -7978,14 +4906,14 @@ nopt@^4.0.1: nopt@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/nopt/-/nopt-5.0.0.tgz#530942bb58a512fccafe53fe210f13a25355dc88" + resolved "https://registry.npmjs.org/nopt/-/nopt-5.0.0.tgz" integrity sha512-Tbj67rffqceeLpcRXrT7vKAN8CwfPeIBgM7E6iBkmKLV7bEMwpGgYLGv0jACUsECaa/vuxP0IjEont6umdMgtQ== dependencies: abbrev "1" -normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.3.5, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0: +normalize-package-data@^2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" + resolved "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz" integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA== dependencies: hosted-git-info "^2.1.4" @@ -7993,91 +4921,52 @@ normalize-package-data@^2.0.0, normalize-package-data@^2.3.0, normalize-package- semver "2 || 3 || 4 || 5" validate-npm-package-license "^3.0.1" -normalize-package-data@^3.0.0, normalize-package-data@^3.0.2: - version "3.0.3" - resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-3.0.3.tgz#dbcc3e2da59509a0983422884cd172eefdfa525e" - integrity sha512-p2W1sgqij3zMMyRC067Dg16bfzVH+w7hyegmpIvZ4JNjqtGOVAIvLmjBx3yP7YTe9vKJgkoNOPjwQGogDoMXFA== - dependencies: - hosted-git-info "^4.0.1" - is-core-module "^2.5.0" - semver "^7.3.4" - validate-npm-package-license "^3.0.1" - normalize-path@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-2.1.1.tgz#1ab28b556e198363a8c1a6f7e6fa20137fe6aed9" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz" integrity sha1-GrKLVW4Zg2Oowab35vogE3/mrtk= dependencies: remove-trailing-separator "^1.0.1" normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" + resolved "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz" integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA== -normalize-url@^3.3.0: - version "3.3.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-3.3.0.tgz#b2e1c4dc4f7c6d57743df733a4f5978d18650559" - integrity sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg== - normalize-url@^6.0.1: version "6.1.0" - resolved "https://registry.yarnpkg.com/normalize-url/-/normalize-url-6.1.0.tgz#40d0885b535deffe3f3147bec877d05fe4c5668a" + resolved "https://registry.npmjs.org/normalize-url/-/normalize-url-6.1.0.tgz" integrity sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A== npm-bundled@^1.0.1, npm-bundled@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/npm-bundled/-/npm-bundled-1.1.1.tgz#1edd570865a94cdb1bc8220775e29466c9fb234b" + resolved "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz" integrity sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA== dependencies: npm-normalize-package-bin "^1.0.1" npm-install-checks@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/npm-install-checks/-/npm-install-checks-4.0.0.tgz#a37facc763a2fde0497ef2c6d0ac7c3fbe00d7b4" + resolved "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-4.0.0.tgz" integrity sha512-09OmyDkNLYwqKPOnbI8exiOZU2GVVmQp7tgez2BPi5OZC8M82elDAps7sxC4l//uSUtotWqoEIDwjRvWH4qz8w== dependencies: semver "^7.1.1" -npm-lifecycle@^3.1.2, npm-lifecycle@^3.1.5: - version "3.1.5" - resolved "https://registry.yarnpkg.com/npm-lifecycle/-/npm-lifecycle-3.1.5.tgz#9882d3642b8c82c815782a12e6a1bfeed0026309" - integrity sha512-lDLVkjfZmvmfvpvBzA4vzee9cn+Me4orq0QF8glbswJVEbIcSNWib7qGOffolysc3teCqbbPZZkzbr3GQZTL1g== - dependencies: - byline "^5.0.0" - graceful-fs "^4.1.15" - node-gyp "^5.0.2" - resolve-from "^4.0.0" - slide "^1.1.6" - uid-number "0.0.6" - umask "^1.1.0" - which "^1.3.1" - -npm-normalize-package-bin@^1.0.0, npm-normalize-package-bin@^1.0.1: +npm-normalize-package-bin@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz#6e79a41f23fd235c0623218228da7d9c23b8f6e2" + resolved "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz" integrity sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA== -"npm-package-arg@^4.0.0 || ^5.0.0 || ^6.0.0", npm-package-arg@^6.0.0, npm-package-arg@^6.1.0: - version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-6.1.1.tgz#02168cb0a49a2b75bf988a28698de7b529df5cb7" - integrity sha512-qBpssaL3IOZWi5vEKUKW0cO7kzLeT+EQO9W8RsLOZf76KF9E/K9+wH0C7t06HXPpaH8WH5xF1MExLuCwbTqRUg== - dependencies: - hosted-git-info "^2.7.1" - osenv "^0.1.5" - semver "^5.6.0" - validate-npm-package-name "^3.0.0" - -npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.0, npm-package-arg@^8.1.2, npm-package-arg@^8.1.5: +npm-package-arg@^8.0.0, npm-package-arg@^8.0.1, npm-package-arg@^8.1.2: version "8.1.5" - resolved "https://registry.yarnpkg.com/npm-package-arg/-/npm-package-arg-8.1.5.tgz#3369b2d5fe8fdc674baa7f1786514ddc15466e44" + resolved "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-8.1.5.tgz" integrity sha512-LhgZrg0n0VgvzVdSm1oiZworPbTxYHUJCgtsJW8mGvlDpxTM1vSJc3m5QZeUkhAHIzbz3VCHd/R4osi1L1Tg/Q== dependencies: hosted-git-info "^4.0.1" semver "^7.3.4" validate-npm-package-name "^3.0.0" -npm-packlist@^1.1.6, npm-packlist@^1.4.4: +npm-packlist@^1.1.6: version "1.4.8" resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-1.4.8.tgz#56ee6cc135b9f98ad3d51c1c95da22bbb9b2ef3e" integrity sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A== @@ -8088,7 +4977,7 @@ npm-packlist@^1.1.6, npm-packlist@^1.4.4: npm-packlist@^2.1.4: version "2.2.2" - resolved "https://registry.yarnpkg.com/npm-packlist/-/npm-packlist-2.2.2.tgz#076b97293fa620f632833186a7a8f65aaa6148c8" + resolved "https://registry.npmjs.org/npm-packlist/-/npm-packlist-2.2.2.tgz" integrity sha512-Jt01acDvJRhJGthnUJVF/w6gumWOZxO7IkpY/lsX9//zqQgnF7OJaxgQXcerd4uQOLu7W5bkb4mChL9mdfm+Zg== dependencies: glob "^7.1.6" @@ -8096,18 +4985,9 @@ npm-packlist@^2.1.4: npm-bundled "^1.1.1" npm-normalize-package-bin "^1.0.1" -npm-pick-manifest@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-3.0.2.tgz#f4d9e5fd4be2153e5f4e5f9b7be8dc419a99abb7" - integrity sha512-wNprTNg+X5nf+tDi+hbjdHhM4bX+mKqv6XmPh7B5eG+QY9VARfQPfCEH013H5GqfNj6ee8Ij2fg8yk0mzps1Vw== - dependencies: - figgy-pudding "^3.5.1" - npm-package-arg "^6.0.0" - semver "^5.4.1" - npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: version "6.1.1" - resolved "https://registry.yarnpkg.com/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz#7b5484ca2c908565f43b7f27644f36bb816f5148" + resolved "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-6.1.1.tgz" integrity sha512-dBsdBtORT84S8V8UTad1WlUyKIY9iMsAmqxHbLdeEeBNMLQDlDWWra3wYUx9EBEIiG/YwAy0XyNHDd2goAsfuA== dependencies: npm-install-checks "^4.0.0" @@ -8117,7 +4997,7 @@ npm-pick-manifest@^6.0.0, npm-pick-manifest@^6.1.1: npm-registry-fetch@^11.0.0: version "11.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz#68c1bb810c46542760d62a6a965f85a702d43a76" + resolved "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-11.0.0.tgz" integrity sha512-jmlgSxoDNuhAtxUIG6pVwwtz840i994dL14FoNVZisrmZW5kWd63IUTNv1m/hyRSGSqWjCUp/YZlS1BJyNp9XA== dependencies: make-fetch-happen "^9.0.1" @@ -8127,37 +5007,23 @@ npm-registry-fetch@^11.0.0: minizlib "^2.0.0" npm-package-arg "^8.0.0" -npm-registry-fetch@^9.0.0: - version "9.0.0" - resolved "https://registry.yarnpkg.com/npm-registry-fetch/-/npm-registry-fetch-9.0.0.tgz#86f3feb4ce00313bc0b8f1f8f69daae6face1661" - integrity sha512-PuFYYtnQ8IyVl6ib9d3PepeehcUeHN9IO5N/iCRhyg9tStQcqGQBRVHmfmMWPDERU3KwZoHFvbJ4FPXPspvzbA== - dependencies: - "@npmcli/ci-detect" "^1.0.0" - lru-cache "^6.0.0" - make-fetch-happen "^8.0.9" - minipass "^3.1.3" - minipass-fetch "^1.3.0" - minipass-json-stream "^1.0.1" - minizlib "^2.0.0" - npm-package-arg "^8.0.0" - npm-run-path@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-2.0.2.tgz#35a9232dfa35d7067b4cb2ddf2357b1871536c5f" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-2.0.2.tgz" integrity sha1-NakjLfo11wZ7TLLd8jV7GHFTbF8= dependencies: path-key "^2.0.0" npm-run-path@^4.0.0, npm-run-path@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/npm-run-path/-/npm-run-path-4.0.1.tgz#b7ecd1e5ed53da8e37a55e1c2269e0b97ed748ea" + resolved "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz" integrity sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw== dependencies: path-key "^3.0.0" -"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2, npmlog@^4.1.2: +npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" - resolved "https://registry.yarnpkg.com/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" + resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== dependencies: are-we-there-yet "~1.1.2" @@ -8167,106 +5033,76 @@ npm-run-path@^4.0.0, npm-run-path@^4.0.1: nth-check@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/nth-check/-/nth-check-2.0.1.tgz#2efe162f5c3da06a28959fbd3db75dbeea9f0fc2" + resolved "https://registry.npmjs.org/nth-check/-/nth-check-2.0.1.tgz" integrity sha512-it1vE95zF6dTT9lBsYbxvqh0Soy4SPowchj0UBGj/V6cTPnXXtQOPUbhZ6CmGzAD/rW22LQK6E96pcdJXk4A4w== dependencies: boolbase "^1.0.0" number-is-nan@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/number-is-nan/-/number-is-nan-1.0.1.tgz#097b602b53422a522c1afb8790318336941a011d" + resolved "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz" integrity sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0= nwsapi@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/nwsapi/-/nwsapi-2.2.0.tgz#204879a9e3d068ff2a55139c2c772780681a38b7" + resolved "https://registry.npmjs.org/nwsapi/-/nwsapi-2.2.0.tgz" integrity sha512-h2AatdwYH+JHiZpv7pt/gSX1XoRGb7L/qSIeuqA6GwYoF9w1vP1cw42TO0aI2pNyshRK5893hNSl+1//vHK7hQ== oauth-sign@~0.9.0: version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" + resolved "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz" integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== -object-assign@^4.0.1, object-assign@^4.1.0, object-assign@^4.1.1: +object-assign@^4.1.0, object-assign@^4.1.1: version "4.1.1" - resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863" + resolved "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz" integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM= object-copy@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" + resolved "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz" integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= dependencies: copy-descriptor "^0.1.0" define-property "^0.2.5" kind-of "^3.0.3" -object-inspect@^1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.6.0.tgz#c70b6cbf72f274aab4c34c0c82f5167bf82cf15b" - integrity sha512-GJzfBZ6DgDAmnuaM3104jR4s1Myxr3Y3zfIyN4z3UdqN69oSRacNK8UhnobDdC+7J2AHCjGwxQubNJfE70SXXQ== - -object-keys@^1.0.12, object-keys@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/object-keys/-/object-keys-1.1.1.tgz#1c47f272df277f3b1daf061677d9c82e2322c60e" - integrity sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA== - object-visit@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" + resolved "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz" integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= dependencies: isobject "^3.0.0" -object.getownpropertydescriptors@^2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/object.getownpropertydescriptors/-/object.getownpropertydescriptors-2.0.3.tgz#8758c846f5b407adab0f236e0986f14b051caa16" - integrity sha1-h1jIRvW0B62rDyNuCYbxSwUcqhY= - dependencies: - define-properties "^1.1.2" - es-abstract "^1.5.1" - object.pick@^1.3.0: version "1.3.0" - resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" + resolved "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz" integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= dependencies: isobject "^3.0.1" -octokit-pagination-methods@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/octokit-pagination-methods/-/octokit-pagination-methods-1.1.0.tgz#cf472edc9d551055f9ef73f6e42b4dbb4c80bea4" - integrity sha512-fZ4qZdQ2nxJvtcasX7Ghl+WlWS/d9IgnBIwFZXVNNZUmzpno91SX5bc5vuxiuKoCtK78XxGGNuSCrDC7xYB3OQ== - once@^1.3.0, once@^1.3.1, once@^1.4.0: version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" + resolved "https://registry.npmjs.org/once/-/once-1.4.0.tgz" integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= dependencies: wrappy "1" -onetime@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-2.0.1.tgz#067428230fd67443b2794b22bba528b6867962d4" - integrity sha1-BnQoIw/WdEOyeUsiu6UotoZ5YtQ= - dependencies: - mimic-fn "^1.0.0" - onetime@^5.1.0, onetime@^5.1.2: version "5.1.2" - resolved "https://registry.yarnpkg.com/onetime/-/onetime-5.1.2.tgz#d0e96ebb56b07476df1dd9c4806e5237985ca45e" + resolved "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz" integrity sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg== dependencies: mimic-fn "^2.1.0" opener@^1.5.2: version "1.5.2" - resolved "https://registry.yarnpkg.com/opener/-/opener-1.5.2.tgz#5d37e1f35077b9dcac4301372271afdeb2a13598" + resolved "https://registry.npmjs.org/opener/-/opener-1.5.2.tgz" integrity sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A== optimize-css-assets-webpack-plugin@^6.0.1: version "6.0.1" - resolved "https://registry.yarnpkg.com/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-6.0.1.tgz#7719bceabba1f3891ec3ae04efb81a1cc99cd793" + resolved "https://registry.npmjs.org/optimize-css-assets-webpack-plugin/-/optimize-css-assets-webpack-plugin-6.0.1.tgz" integrity sha512-BshV2UZPfggZLdUfN3zFBbG4sl/DynUI+YCB6fRRDWaqO2OiWN8GPcp4Y0/fEV6B3k9Hzyk3czve3V/8B/SzKQ== dependencies: cssnano "^5.0.2" @@ -8275,7 +5111,7 @@ optimize-css-assets-webpack-plugin@^6.0.1: optionator@^0.8.1: version "0.8.3" - resolved "https://registry.yarnpkg.com/optionator/-/optionator-0.8.3.tgz#84fa1d036fe9d3c7e21d99884b601167ec8fb495" + resolved "https://registry.npmjs.org/optionator/-/optionator-0.8.3.tgz" integrity sha512-+IW9pACdk3XWmmTXG8m3upGUJst5XRGzxMRjXzAuJ1XnIFNvfhjjIuYkDvysnPQ7qzqVzLt78BCruntqRhWQbA== dependencies: deep-is "~0.1.3" @@ -8285,47 +5121,24 @@ optionator@^0.8.1: type-check "~0.3.2" word-wrap "~1.2.3" -ora@^5.4.1: - version "5.4.1" - resolved "https://registry.yarnpkg.com/ora/-/ora-5.4.1.tgz#1b2678426af4ac4a509008e5e4ac9e9959db9e18" - integrity sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ== - dependencies: - bl "^4.1.0" - chalk "^4.1.0" - cli-cursor "^3.1.0" - cli-spinners "^2.5.0" - is-interactive "^1.0.0" - is-unicode-supported "^0.1.0" - log-symbols "^4.1.0" - strip-ansi "^6.0.0" - wcwidth "^1.0.1" - os-browserify@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/os-browserify/-/os-browserify-0.3.0.tgz#854373c7f5c2315914fc9bfc6bd8238fdda1ec27" + resolved "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz" integrity sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc= os-homedir@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3" + resolved "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz" integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M= -os-name@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/os-name/-/os-name-3.1.0.tgz#dec19d966296e1cd62d701a5a66ee1ddeae70801" - integrity sha512-h8L+8aNjNcMpo/mAIBPn5PXCM16iyPGjHNWo6U1YO8sJTMHtEtyczI6QJnLoplswm6goopQkqc7OAnjhWcugVg== - dependencies: - macos-release "^2.2.0" - windows-release "^3.1.0" - -os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: +os-tmpdir@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" + resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4, osenv@^0.1.5: +osenv@^0.1.4: version "0.1.5" - resolved "https://registry.yarnpkg.com/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" + resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== dependencies: os-homedir "^1.0.0" @@ -8333,142 +5146,50 @@ osenv@^0.1.4, osenv@^0.1.5: p-each-series@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/p-each-series/-/p-each-series-2.1.0.tgz#961c8dd3f195ea96c747e636b262b800a6b1af48" + resolved "https://registry.npmjs.org/p-each-series/-/p-each-series-2.1.0.tgz" integrity sha512-ZuRs1miPT4HrjFa+9fRfOFXxGJfORgelKV9f9nNOWw2gl6gVsRaVDOQP0+MI0G0wGKns1Yacsu0GjOFbTK0JFQ== p-finally@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" + resolved "https://registry.npmjs.org/p-finally/-/p-finally-1.0.0.tgz" integrity sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4= -p-limit@^1.1.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" - integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== - dependencies: - p-try "^1.0.0" - p-limit@^2.0.0, p-limit@^2.2.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" + resolved "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz" integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== dependencies: p-try "^2.0.0" -p-locate@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" - integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= - dependencies: - p-limit "^1.1.0" - p-locate@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-3.0.0.tgz#322d69a05c0264b25997d9f40cd8a891ab0064a4" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz" integrity sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ== dependencies: p-limit "^2.0.0" p-locate@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" + resolved "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz" integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== dependencies: p-limit "^2.2.0" -p-map-series@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-1.0.0.tgz#bf98fe575705658a9e1351befb85ae4c1f07bdca" - integrity sha1-v5j+V1cFZYqeE1G++4WuTB8Hvco= - dependencies: - p-reduce "^1.0.0" - -p-map-series@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" - integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== - -p-map@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" - integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== - p-map@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/p-map/-/p-map-4.0.0.tgz#bb2f95a5eda2ec168ec9274e06a747c3e2904d2b" + resolved "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz" integrity sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ== dependencies: aggregate-error "^3.0.0" -p-pipe@^1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-1.2.0.tgz#4b1a11399a11520a67790ee5a0c1d5881d6befe9" - integrity sha1-SxoROZoRUgpneQ7loMHViB1r7+k= - -p-pipe@^3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/p-pipe/-/p-pipe-3.1.0.tgz#48b57c922aa2e1af6a6404cb7c6bf0eb9cc8e60e" - integrity sha512-08pj8ATpzMR0Y80x50yJHn37NF6vjrqHutASaX5LiH5npS9XPvrUmscd9MF5R4fuYRHOxQR1FfMIlF7AzwoPqw== - -p-queue@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-4.0.0.tgz#ed0eee8798927ed6f2c2f5f5b77fdb2061a5d346" - integrity sha512-3cRXXn3/O0o3+eVmUroJPSj/esxoEFIm0ZOno/T+NzG/VZgPOqQ8WKmlNqubSEpZmCIngEy34unkHGg83ZIBmg== - dependencies: - eventemitter3 "^3.1.0" - -p-queue@^6.6.2: - version "6.6.2" - resolved "https://registry.yarnpkg.com/p-queue/-/p-queue-6.6.2.tgz#2068a9dcf8e67dd0ec3e7a2bcb76810faa85e426" - integrity sha512-RwFpb72c/BhQLEXIZ5K2e+AhgNVmIejGlTgiB9MzZ0e93GRvqZ7uSi0dvRF7/XIXDeNkra2fNHBxTyPDGySpjQ== - dependencies: - eventemitter3 "^4.0.4" - p-timeout "^3.2.0" - -p-reduce@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-1.0.0.tgz#18c2b0dd936a4690a529f8231f58a0fdb6a47dfa" - integrity sha1-GMKw3ZNqRpClKfgjH1ig/bakffo= - -p-reduce@^2.0.0, p-reduce@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" - integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== - -p-timeout@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" - integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== - dependencies: - p-finally "^1.0.0" - -p-try@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" - integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= - p-try@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" + resolved "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz" integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== -p-waterfall@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-1.0.0.tgz#7ed94b3ceb3332782353af6aae11aa9fc235bb00" - integrity sha1-ftlLPOszMngjU69qrhGqn8I1uwA= - dependencies: - p-reduce "^1.0.0" - -p-waterfall@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/p-waterfall/-/p-waterfall-2.1.1.tgz#63153a774f472ccdc4eb281cdb2967fcf158b2ee" - integrity sha512-RRTnDb2TBG/epPRI2yYXsimO0v3BXC8Yd3ogr1545IaqKK17VGhbWVeGGN+XfCm/08OK8635nH31c8bATkHuSw== - dependencies: - p-reduce "^2.0.0" - -pacote@^11.2.6, pacote@^11.2.7: +pacote@^11.2.7: version "11.3.5" - resolved "https://registry.yarnpkg.com/pacote/-/pacote-11.3.5.tgz#73cf1fc3772b533f575e39efa96c50be8c3dc9d2" + resolved "https://registry.npmjs.org/pacote/-/pacote-11.3.5.tgz" integrity sha512-fT375Yczn4zi+6Hkk2TBe1x1sP8FgFsEIZ2/iWaXY2r/NkhDJfxbcn5paz1+RTFCyNf+dPnaoBDJoAxXSU8Bkg== dependencies: "@npmcli/git" "^2.1.0" @@ -8493,12 +5214,12 @@ pacote@^11.2.6, pacote@^11.2.7: pako@~1.0.5: version "1.0.10" - resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.10.tgz#4328badb5086a426aa90f541977d4955da5c9732" + resolved "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz" integrity sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw== parallel-transform@^1.1.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/parallel-transform/-/parallel-transform-1.2.0.tgz#9049ca37d6cb2182c3b1d2c720be94d14a5814fc" + resolved "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz" integrity sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg== dependencies: cyclist "^1.0.1" @@ -8507,14 +5228,14 @@ parallel-transform@^1.1.0: parent-module@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" + resolved "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz" integrity sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g== dependencies: callsites "^3.0.0" parse-asn1@^5.0.0: version "5.1.5" - resolved "https://registry.yarnpkg.com/parse-asn1/-/parse-asn1-5.1.5.tgz#003271343da58dc94cace494faef3d2147ecea0e" + resolved "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz" integrity sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ== dependencies: asn1.js "^4.0.0" @@ -8524,29 +5245,9 @@ parse-asn1@^5.0.0: pbkdf2 "^3.0.3" safe-buffer "^5.1.1" -parse-github-repo-url@^1.3.0: - version "1.4.1" - resolved "https://registry.yarnpkg.com/parse-github-repo-url/-/parse-github-repo-url-1.4.1.tgz#9e7d8bb252a6cb6ba42595060b7bf6df3dbc1f50" - integrity sha1-nn2LslKmy2ukJZUGC3v23z28H1A= - -parse-json@^2.2.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-2.2.0.tgz#f480f40434ef80741f8469099f8dea18f55a4dc9" - integrity sha1-9ID0BDTvgHQfhGkJn43qGPVaTck= - dependencies: - error-ex "^1.2.0" - -parse-json@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" - integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= - dependencies: - error-ex "^1.3.1" - json-parse-better-errors "^1.0.1" - parse-json@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-5.0.0.tgz#73e5114c986d143efa3712d4ea24db9a4266f60f" + resolved "https://registry.npmjs.org/parse-json/-/parse-json-5.0.0.tgz" integrity sha512-OOY5b7PAEFV0E2Fir1KOkxchnZNCdowAJgQ5NuxjpBKTRP3pQhwkrkxqQjeoKJ+fO7bCpmIZaogI4eZGDMEGOw== dependencies: "@babel/code-frame" "^7.0.0" @@ -8554,105 +5255,64 @@ parse-json@^5.0.0: json-parse-better-errors "^1.0.1" lines-and-columns "^1.1.6" -parse-path@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/parse-path/-/parse-path-4.0.1.tgz#0ec769704949778cb3b8eda5e994c32073a1adff" - integrity sha512-d7yhga0Oc+PwNXDvQ0Jv1BuWkLVPXcAoQ/WREgd6vNNoKYaW52KI+RdOFjI63wjkmps9yUE8VS4veP+AgpQ/hA== - dependencies: - is-ssh "^1.3.0" - protocols "^1.4.0" - -parse-url@^5.0.0: - version "5.0.1" - resolved "https://registry.yarnpkg.com/parse-url/-/parse-url-5.0.1.tgz#99c4084fc11be14141efa41b3d117a96fcb9527f" - integrity sha512-flNUPP27r3vJpROi0/R3/2efgKkyXqnXwyP1KQ2U0SfFRgdizOdWfvrrvJg1LuOoxs7GQhmxJlq23IpQ/BkByg== - dependencies: - is-ssh "^1.3.0" - normalize-url "^3.3.0" - parse-path "^4.0.0" - protocols "^1.4.0" - parse5@5.1.1: version "5.1.1" - resolved "https://registry.yarnpkg.com/parse5/-/parse5-5.1.1.tgz#f68e4e5ba1852ac2cadc00f4555fff6c2abb6178" + resolved "https://registry.npmjs.org/parse5/-/parse5-5.1.1.tgz" integrity sha512-ugq4DFI0Ptb+WWjAdOK16+u/nHfiIrcE+sh8kZMaM0WllQKLI9rOUq6c2b7cwPkXdzfQESqvoqK6ug7U/Yyzug== pascalcase@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" + resolved "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz" integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= path-browserify@0.0.1: version "0.0.1" - resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-0.0.1.tgz#e6c4ddd7ed3aa27c68a20cc4e50e1a4ee83bbc4a" + resolved "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz" integrity sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ== path-dirname@^1.0.0: version "1.0.2" - resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + resolved "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz" integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= -path-exists@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-2.1.0.tgz#0feb6c64f0fc518d9a754dd5efb62c7022761f4b" - integrity sha1-D+tsZPD8UY2adU3V77YscCJ2H0s= - dependencies: - pinkie-promise "^2.0.0" - path-exists@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz" integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= path-exists@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" + resolved "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz" integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== path-is-absolute@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" + resolved "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz" integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= path-key@^2.0.0, path-key@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" + resolved "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz" integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= path-key@^3.0.0, path-key@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" + resolved "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz" integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== path-parse@^1.0.6: version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" + resolved "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz" integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== -path-type@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-1.1.0.tgz#59c44f7ee491da704da415da5a4070ba4f8fe441" - integrity sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE= - dependencies: - graceful-fs "^4.1.2" - pify "^2.0.0" - pinkie-promise "^2.0.0" - -path-type@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-3.0.0.tgz#cef31dc8e0a1a3bb0d105c0cd97cf3bf47f4e36f" - integrity sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg== - dependencies: - pify "^3.0.0" - path-type@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" + resolved "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz" integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== pbkdf2@^3.0.3: version "3.0.17" - resolved "https://registry.yarnpkg.com/pbkdf2/-/pbkdf2-3.0.17.tgz#976c206530617b14ebb32114239f7b09336e93a6" + resolved "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz" integrity sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA== dependencies: create-hash "^1.1.2" @@ -8663,94 +5323,67 @@ pbkdf2@^3.0.3: pend@~1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" + resolved "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz" integrity sha1-elfrVQpng/kRUzH89GY9XI4AelA= performance-now@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" + resolved "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz" integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.2.3: version "2.3.0" - resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972" + resolved "https://registry.npmjs.org/picomatch/-/picomatch-2.3.0.tgz" integrity sha512-lY1Q/PiJGC2zOv/z391WOTD+Z02bCgsFfvxoXXf6h7kv9o+WmsmzYqrAwY63sNgOxE4xEdq0WyUnXfKeBrSvYw== -pify@^2.0.0, pify@^2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-2.3.0.tgz#ed141a6ac043a849ea588498e7dca8b15330e90c" - integrity sha1-7RQaasBDqEnqWISY59yosVMw6Qw= - -pify@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" - integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= - pify@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" + resolved "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz" integrity sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g== -pify@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/pify/-/pify-5.0.0.tgz#1f5eca3f5e87ebec28cc6d54a0e4aaf00acc127f" - integrity sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA== - -pinkie-promise@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/pinkie-promise/-/pinkie-promise-2.0.1.tgz#2135d6dfa7a358c069ac9b178776288228450ffa" - integrity sha1-ITXW36ejWMBprJsXh3YogihFD/o= - dependencies: - pinkie "^2.0.0" - -pinkie@^2.0.0: - version "2.0.4" - resolved "https://registry.yarnpkg.com/pinkie/-/pinkie-2.0.4.tgz#72556b80cfa0d48a974e80e77248e80ed4f7f870" - integrity sha1-clVrgM+g1IqXToDnckjoDtT3+HA= - pirates@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/pirates/-/pirates-4.0.1.tgz#643a92caf894566f91b2b986d2c66950a8e2fb87" + resolved "https://registry.npmjs.org/pirates/-/pirates-4.0.1.tgz" integrity sha512-WuNqLTbMI3tmfef2TKxlQmAiLHKtFhlsCZnPIpuv2Ow0RDVO8lfy1Opf4NUzlMXLjPl+Men7AuVdX6TA+s+uGA== dependencies: node-modules-regexp "^1.0.0" pkg-dir@4.2.0, pkg-dir@^4.2.0: version "4.2.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-4.2.0.tgz#f099133df7ede422e81d1d8448270eeb3e4261f3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz" integrity sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ== dependencies: find-up "^4.0.0" pkg-dir@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pkg-dir/-/pkg-dir-3.0.0.tgz#2749020f239ed990881b1f71210d51eb6523bea3" + resolved "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz" integrity sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw== dependencies: find-up "^3.0.0" please-upgrade-node@^3.2.0: version "3.2.0" - resolved "https://registry.yarnpkg.com/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz#aeddd3f994c933e4ad98b99d9a556efa0e2fe942" + resolved "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz" integrity sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg== dependencies: semver-compare "^1.0.0" pnp-webpack-plugin@^1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz#65741384f6d8056f36e2255a8d67ffc20866f5c9" + resolved "https://registry.npmjs.org/pnp-webpack-plugin/-/pnp-webpack-plugin-1.7.0.tgz" integrity sha512-2Rb3vm+EXble/sMXNSu6eoBx8e79gKqhNq9F5ZWW6ERNCTE/Q0wQNne5541tE5vKjfM8hpNCYL+LGc1YTfI0dg== dependencies: ts-pnp "^1.1.6" posix-character-classes@^0.1.0: version "0.1.1" - resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" + resolved "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz" integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= postcss-calc@^8.0.0: version "8.0.0" - resolved "https://registry.yarnpkg.com/postcss-calc/-/postcss-calc-8.0.0.tgz#a05b87aacd132740a5db09462a3612453e5df90a" + resolved "https://registry.npmjs.org/postcss-calc/-/postcss-calc-8.0.0.tgz" integrity sha512-5NglwDrcbiy8XXfPM11F3HeC6hoT9W7GUH/Zi5U/p7u3Irv4rHhdDcIZwG0llHXV4ftsBjpfWMXAnXNl4lnt8g== dependencies: postcss-selector-parser "^6.0.2" @@ -8758,7 +5391,7 @@ postcss-calc@^8.0.0: postcss-colormin@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/postcss-colormin/-/postcss-colormin-5.2.0.tgz#2b620b88c0ff19683f3349f4cf9e24ebdafb2c88" + resolved "https://registry.npmjs.org/postcss-colormin/-/postcss-colormin-5.2.0.tgz" integrity sha512-+HC6GfWU3upe5/mqmxuqYZ9B2Wl4lcoUUNkoaX59nEWV4EtADCMiBqui111Bu8R8IvaZTmqmxrqOAqjbHIwXPw== dependencies: browserslist "^4.16.6" @@ -8768,34 +5401,34 @@ postcss-colormin@^5.2.0: postcss-convert-values@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz#4ec19d6016534e30e3102fdf414e753398645232" + resolved "https://registry.npmjs.org/postcss-convert-values/-/postcss-convert-values-5.0.1.tgz" integrity sha512-C3zR1Do2BkKkCgC0g3sF8TS0koF2G+mN8xxayZx3f10cIRmTaAnpgpRQZjNekTZxM2ciSPoh2IWJm0VZx8NoQg== dependencies: postcss-value-parser "^4.1.0" postcss-discard-comments@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz#9eae4b747cf760d31f2447c27f0619d5718901fe" + resolved "https://registry.npmjs.org/postcss-discard-comments/-/postcss-discard-comments-5.0.1.tgz" integrity sha512-lgZBPTDvWrbAYY1v5GYEv8fEO/WhKOu/hmZqmCYfrpD6eyDWWzAOsl2rF29lpvziKO02Gc5GJQtlpkTmakwOWg== postcss-discard-duplicates@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz#68f7cc6458fe6bab2e46c9f55ae52869f680e66d" + resolved "https://registry.npmjs.org/postcss-discard-duplicates/-/postcss-discard-duplicates-5.0.1.tgz" integrity sha512-svx747PWHKOGpAXXQkCc4k/DsWo+6bc5LsVrAsw+OU+Ibi7klFZCyX54gjYzX4TH+f2uzXjRviLARxkMurA2bA== postcss-discard-empty@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz#ee136c39e27d5d2ed4da0ee5ed02bc8a9f8bf6d8" + resolved "https://registry.npmjs.org/postcss-discard-empty/-/postcss-discard-empty-5.0.1.tgz" integrity sha512-vfU8CxAQ6YpMxV2SvMcMIyF2LX1ZzWpy0lqHDsOdaKKLQVQGVP1pzhrI9JlsO65s66uQTfkQBKBD/A5gp9STFw== postcss-discard-overridden@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz#454b41f707300b98109a75005ca4ab0ff2743ac6" + resolved "https://registry.npmjs.org/postcss-discard-overridden/-/postcss-discard-overridden-5.0.1.tgz" integrity sha512-Y28H7y93L2BpJhrdUR2SR2fnSsT+3TVx1NmVQLbcnZWwIUpJ7mfcTC6Za9M2PG6w8j7UQRfzxqn8jU2VwFxo3Q== postcss-merge-longhand@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz#277ada51d9a7958e8ef8cf263103c9384b322a41" + resolved "https://registry.npmjs.org/postcss-merge-longhand/-/postcss-merge-longhand-5.0.2.tgz" integrity sha512-BMlg9AXSI5G9TBT0Lo/H3PfUy63P84rVz3BjCFE9e9Y9RXQZD3+h3YO1kgTNsNJy7bBc1YQp8DmSnwLIW5VPcw== dependencies: css-color-names "^1.0.1" @@ -8804,7 +5437,7 @@ postcss-merge-longhand@^5.0.2: postcss-merge-rules@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz#d6e4d65018badbdb7dcc789c4f39b941305d410a" + resolved "https://registry.npmjs.org/postcss-merge-rules/-/postcss-merge-rules-5.0.2.tgz" integrity sha512-5K+Md7S3GwBewfB4rjDeol6V/RZ8S+v4B66Zk2gChRqLTCC8yjnHQ601omj9TKftS19OPGqZ/XzoqpzNQQLwbg== dependencies: browserslist "^4.16.6" @@ -8815,14 +5448,14 @@ postcss-merge-rules@^5.0.2: postcss-minify-font-values@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz#a90cefbfdaa075bd3dbaa1b33588bb4dc268addf" + resolved "https://registry.npmjs.org/postcss-minify-font-values/-/postcss-minify-font-values-5.0.1.tgz" integrity sha512-7JS4qIsnqaxk+FXY1E8dHBDmraYFWmuL6cgt0T1SWGRO5bzJf8sUoelwa4P88LEWJZweHevAiDKxHlofuvtIoA== dependencies: postcss-value-parser "^4.1.0" postcss-minify-gradients@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-minify-gradients/-/postcss-minify-gradients-5.0.2.tgz#7c175c108f06a5629925d698b3c4cf7bd3864ee5" + resolved "https://registry.npmjs.org/postcss-minify-gradients/-/postcss-minify-gradients-5.0.2.tgz" integrity sha512-7Do9JP+wqSD6Prittitt2zDLrfzP9pqKs2EcLX7HJYxsxCOwrrcLt4x/ctQTsiOw+/8HYotAoqNkrzItL19SdQ== dependencies: colord "^2.6" @@ -8831,7 +5464,7 @@ postcss-minify-gradients@^5.0.2: postcss-minify-params@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz#371153ba164b9d8562842fdcd929c98abd9e5b6c" + resolved "https://registry.npmjs.org/postcss-minify-params/-/postcss-minify-params-5.0.1.tgz" integrity sha512-4RUC4k2A/Q9mGco1Z8ODc7h+A0z7L7X2ypO1B6V8057eVK6mZ6xwz6QN64nHuHLbqbclkX1wyzRnIrdZehTEHw== dependencies: alphanum-sort "^1.0.2" @@ -8842,7 +5475,7 @@ postcss-minify-params@^5.0.1: postcss-minify-selectors@^5.1.0: version "5.1.0" - resolved "https://registry.yarnpkg.com/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz#4385c845d3979ff160291774523ffa54eafd5a54" + resolved "https://registry.npmjs.org/postcss-minify-selectors/-/postcss-minify-selectors-5.1.0.tgz" integrity sha512-NzGBXDa7aPsAcijXZeagnJBKBPMYLaJJzB8CQh6ncvyl2sIndLVWfbcDi0SBjRWk5VqEjXvf8tYwzoKf4Z07og== dependencies: alphanum-sort "^1.0.2" @@ -8850,12 +5483,12 @@ postcss-minify-selectors@^5.1.0: postcss-modules-extract-imports@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz#cda1f047c0ae80c97dbe28c3e76a43b88025741d" + resolved "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz" integrity sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw== postcss-modules-local-by-default@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz#ebbb54fae1598eecfdf691a02b3ff3b390a5a51c" + resolved "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.0.tgz" integrity sha512-sT7ihtmGSF9yhm6ggikHdV0hlziDTX7oFoXtuVWeDd3hHObNkcHRo9V3yg7vCAY7cONyxJC/XXCmmiHHcvX7bQ== dependencies: icss-utils "^5.0.0" @@ -8864,26 +5497,26 @@ postcss-modules-local-by-default@^4.0.0: postcss-modules-scope@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz#9ef3151456d3bbfa120ca44898dfca6f2fa01f06" + resolved "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.0.0.tgz" integrity sha512-hncihwFA2yPath8oZ15PZqvWGkWf+XUfQgUGamS4LqoP1anQLOsOJw0vr7J7IwLpoY9fatA2qiGUGmuZL0Iqlg== dependencies: postcss-selector-parser "^6.0.4" postcss-modules-values@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz#d7c5e7e68c3bb3c9b27cbf48ca0bb3ffb4602c9c" + resolved "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz" integrity sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ== dependencies: icss-utils "^5.0.0" postcss-normalize-charset@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz#121559d1bebc55ac8d24af37f67bd4da9efd91d0" + resolved "https://registry.npmjs.org/postcss-normalize-charset/-/postcss-normalize-charset-5.0.1.tgz" integrity sha512-6J40l6LNYnBdPSk+BHZ8SF+HAkS4q2twe5jnocgd+xWpz/mx/5Sa32m3W1AA8uE8XaXN+eg8trIlfu8V9x61eg== postcss-normalize-display-values@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz#62650b965981a955dffee83363453db82f6ad1fd" + resolved "https://registry.npmjs.org/postcss-normalize-display-values/-/postcss-normalize-display-values-5.0.1.tgz" integrity sha512-uupdvWk88kLDXi5HEyI9IaAJTE3/Djbcrqq8YgjvAVuzgVuqIk3SuJWUisT2gaJbZm1H9g5k2w1xXilM3x8DjQ== dependencies: cssnano-utils "^2.0.1" @@ -8891,14 +5524,14 @@ postcss-normalize-display-values@^5.0.1: postcss-normalize-positions@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz#868f6af1795fdfa86fbbe960dceb47e5f9492fe5" + resolved "https://registry.npmjs.org/postcss-normalize-positions/-/postcss-normalize-positions-5.0.1.tgz" integrity sha512-rvzWAJai5xej9yWqlCb1OWLd9JjW2Ex2BCPzUJrbaXmtKtgfL8dBMOOMTX6TnvQMtjk3ei1Lswcs78qKO1Skrg== dependencies: postcss-value-parser "^4.1.0" postcss-normalize-repeat-style@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz#cbc0de1383b57f5bb61ddd6a84653b5e8665b2b5" + resolved "https://registry.npmjs.org/postcss-normalize-repeat-style/-/postcss-normalize-repeat-style-5.0.1.tgz" integrity sha512-syZ2itq0HTQjj4QtXZOeefomckiV5TaUO6ReIEabCh3wgDs4Mr01pkif0MeVwKyU/LHEkPJnpwFKRxqWA/7O3w== dependencies: cssnano-utils "^2.0.1" @@ -8906,14 +5539,14 @@ postcss-normalize-repeat-style@^5.0.1: postcss-normalize-string@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz#d9eafaa4df78c7a3b973ae346ef0e47c554985b0" + resolved "https://registry.npmjs.org/postcss-normalize-string/-/postcss-normalize-string-5.0.1.tgz" integrity sha512-Ic8GaQ3jPMVl1OEn2U//2pm93AXUcF3wz+OriskdZ1AOuYV25OdgS7w9Xu2LO5cGyhHCgn8dMXh9bO7vi3i9pA== dependencies: postcss-value-parser "^4.1.0" postcss-normalize-timing-functions@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz#8ee41103b9130429c6cbba736932b75c5e2cb08c" + resolved "https://registry.npmjs.org/postcss-normalize-timing-functions/-/postcss-normalize-timing-functions-5.0.1.tgz" integrity sha512-cPcBdVN5OsWCNEo5hiXfLUnXfTGtSFiBU9SK8k7ii8UD7OLuznzgNRYkLZow11BkQiiqMcgPyh4ZqXEEUrtQ1Q== dependencies: cssnano-utils "^2.0.1" @@ -8921,7 +5554,7 @@ postcss-normalize-timing-functions@^5.0.1: postcss-normalize-unicode@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz#82d672d648a411814aa5bf3ae565379ccd9f5e37" + resolved "https://registry.npmjs.org/postcss-normalize-unicode/-/postcss-normalize-unicode-5.0.1.tgz" integrity sha512-kAtYD6V3pK0beqrU90gpCQB7g6AOfP/2KIPCVBKJM2EheVsBQmx/Iof+9zR9NFKLAx4Pr9mDhogB27pmn354nA== dependencies: browserslist "^4.16.0" @@ -8929,7 +5562,7 @@ postcss-normalize-unicode@^5.0.1: postcss-normalize-url@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz#ddcdfb7cede1270740cf3e4dfc6008bd96abc763" + resolved "https://registry.npmjs.org/postcss-normalize-url/-/postcss-normalize-url-5.0.2.tgz" integrity sha512-k4jLTPUxREQ5bpajFQZpx8bCF2UrlqOTzP9kEqcEnOfwsRshWs2+oAFIHfDQB8GO2PaUaSE0NlTAYtbluZTlHQ== dependencies: is-absolute-url "^3.0.3" @@ -8938,14 +5571,14 @@ postcss-normalize-url@^5.0.2: postcss-normalize-whitespace@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz#b0b40b5bcac83585ff07ead2daf2dcfbeeef8e9a" + resolved "https://registry.npmjs.org/postcss-normalize-whitespace/-/postcss-normalize-whitespace-5.0.1.tgz" integrity sha512-iPklmI5SBnRvwceb/XH568yyzK0qRVuAG+a1HFUsFRf11lEJTiQQa03a4RSCQvLKdcpX7XsI1Gen9LuLoqwiqA== dependencies: postcss-value-parser "^4.1.0" postcss-ordered-values@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz#1f351426977be00e0f765b3164ad753dac8ed044" + resolved "https://registry.npmjs.org/postcss-ordered-values/-/postcss-ordered-values-5.0.2.tgz" integrity sha512-8AFYDSOYWebJYLyJi3fyjl6CqMEG/UVworjiyK1r573I56kb3e879sCJLGvR3merj+fAdPpVplXKQZv+ey6CgQ== dependencies: cssnano-utils "^2.0.1" @@ -8953,7 +5586,7 @@ postcss-ordered-values@^5.0.2: postcss-reduce-initial@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz#9d6369865b0f6f6f6b165a0ef5dc1a4856c7e946" + resolved "https://registry.npmjs.org/postcss-reduce-initial/-/postcss-reduce-initial-5.0.1.tgz" integrity sha512-zlCZPKLLTMAqA3ZWH57HlbCjkD55LX9dsRyxlls+wfuRfqCi5mSlZVan0heX5cHr154Dq9AfbH70LyhrSAezJw== dependencies: browserslist "^4.16.0" @@ -8961,7 +5594,7 @@ postcss-reduce-initial@^5.0.1: postcss-reduce-transforms@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz#93c12f6a159474aa711d5269923e2383cedcf640" + resolved "https://registry.npmjs.org/postcss-reduce-transforms/-/postcss-reduce-transforms-5.0.1.tgz" integrity sha512-a//FjoPeFkRuAguPscTVmRQUODP+f3ke2HqFNgGPwdYnpeC29RZdCBvGRGTsKpMURb/I3p6jdKoBQ2zI+9Q7kA== dependencies: cssnano-utils "^2.0.1" @@ -8969,7 +5602,7 @@ postcss-reduce-transforms@^5.0.1: postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector-parser@^6.0.5: version "6.0.6" - resolved "https://registry.yarnpkg.com/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz#2c5bba8174ac2f6981ab631a42ab0ee54af332ea" + resolved "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.6.tgz" integrity sha512-9LXrvaaX3+mcv5xkg5kFwqSzSH1JIObIx51PrndZwlmznwXRfxMddDvo9gve3gVR8ZTKgoFDdWkbRFmEhT4PMg== dependencies: cssesc "^3.0.0" @@ -8977,7 +5610,7 @@ postcss-selector-parser@^6.0.2, postcss-selector-parser@^6.0.4, postcss-selector postcss-svgo@^5.0.2: version "5.0.2" - resolved "https://registry.yarnpkg.com/postcss-svgo/-/postcss-svgo-5.0.2.tgz#bc73c4ea4c5a80fbd4b45e29042c34ceffb9257f" + resolved "https://registry.npmjs.org/postcss-svgo/-/postcss-svgo-5.0.2.tgz" integrity sha512-YzQuFLZu3U3aheizD+B1joQ94vzPfE6BNUcSYuceNxlVnKKsOtdo6hL9/zyC168Q8EwfLSgaDSalsUGa9f2C0A== dependencies: postcss-value-parser "^4.1.0" @@ -8985,7 +5618,7 @@ postcss-svgo@^5.0.2: postcss-unique-selectors@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz#3be5c1d7363352eff838bd62b0b07a0abad43bfc" + resolved "https://registry.npmjs.org/postcss-unique-selectors/-/postcss-unique-selectors-5.0.1.tgz" integrity sha512-gwi1NhHV4FMmPn+qwBNuot1sG1t2OmacLQ/AX29lzyggnjd+MnVD5uqQmpXO3J17KGL2WAxQruj1qTd3H0gG/w== dependencies: alphanum-sort "^1.0.2" @@ -8994,12 +5627,12 @@ postcss-unique-selectors@^5.0.1: postcss-value-parser@^4.0.2, postcss-value-parser@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz#443f6a20ced6481a2bda4fa8532a6e55d789a2cb" + resolved "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.1.0.tgz" integrity sha512-97DXOFbQJhk71ne5/Mt6cOu6yxsSfM0QGQyl0L25Gca4yGWEGJaig7l7gbCX623VqTBNGLRLaVUCnNkcedlRSQ== postcss@^8.2.1, postcss@^8.2.15: version "8.3.6" - resolved "https://registry.yarnpkg.com/postcss/-/postcss-8.3.6.tgz#2730dd76a97969f37f53b9a6096197be311cc4ea" + resolved "https://registry.npmjs.org/postcss/-/postcss-8.3.6.tgz" integrity sha512-wG1cc/JhRgdqB6WHEuyLTedf3KIRuD0hG6ldkFEZNCjRxiC+3i6kkWUUbiJQayP28iwG35cEmAbe98585BYV0A== dependencies: colorette "^1.2.2" @@ -9008,17 +5641,17 @@ postcss@^8.2.1, postcss@^8.2.15: prelude-ls@~1.1.2: version "1.1.2" - resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54" + resolved "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz" integrity sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ= prettier@^2.4.1: version "2.4.1" - resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.4.1.tgz#671e11c89c14a4cfc876ce564106c4a6726c9f5c" + resolved "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz" integrity sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA== pretty-format@^25.2.1, pretty-format@^25.5.0: version "25.5.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-25.5.0.tgz#7873c1d774f682c34b8d48b6743a2bf2ac55791a" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-25.5.0.tgz" integrity sha512-kbo/kq2LQ/A/is0PQwsEHM7Ca6//bGPPvU6UnsdDRSKTWxT/ru/xb88v4BJf6a69H+uTytOEsTusT9ksd/1iWQ== dependencies: "@jest/types" "^25.5.0" @@ -9028,7 +5661,7 @@ pretty-format@^25.2.1, pretty-format@^25.5.0: pretty-format@^26.1.0: version "26.1.0" - resolved "https://registry.yarnpkg.com/pretty-format/-/pretty-format-26.1.0.tgz#272b9cd1f1a924ab5d443dc224899d7a65cb96ec" + resolved "https://registry.npmjs.org/pretty-format/-/pretty-format-26.1.0.tgz" integrity sha512-GmeO1PEYdM+non4BKCj+XsPJjFOJIPnsLewqhDVoqY1xo0yNmDas7tC2XwpMrRAHR3MaE2hPo37deX5OisJ2Wg== dependencies: "@jest/types" "^26.1.0" @@ -9038,40 +5671,32 @@ pretty-format@^26.1.0: process-nextick-args@~2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" + resolved "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== process@^0.11.10: version "0.11.10" - resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182" + resolved "https://registry.npmjs.org/process/-/process-0.11.10.tgz" integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI= progress@2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.1.tgz#c9242169342b1c29d275889c95734621b1952e31" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.1.tgz" integrity sha512-OE+a6vzqazc+K6LxJrX5UPyKFvGnL5CYmq2jFGNIBWHpc4QyE49/YOumcrpQFJpfejmvRtbJzgO1zPmMCqlbBg== progress@^2.0.3: version "2.0.3" - resolved "https://registry.yarnpkg.com/progress/-/progress-2.0.3.tgz#7e8cf8d8f5b8f239c1bc68beb4eb78567d572ef8" + resolved "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz" integrity sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA== promise-inflight@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/promise-inflight/-/promise-inflight-1.0.1.tgz#98472870bf228132fcbdd868129bad12c3c029e3" + resolved "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz" integrity sha1-mEcocL8igTL8vdhoEputEsPAKeM= -promise-retry@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-1.1.1.tgz#6739e968e3051da20ce6497fb2b50f6911df3d6d" - integrity sha1-ZznpaOMFHaIM5kl/srUPaRHfPW0= - dependencies: - err-code "^1.0.0" - retry "^0.10.0" - promise-retry@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/promise-retry/-/promise-retry-2.0.1.tgz#ff747a13620ab57ba688f5fc67855410c370da22" + resolved "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz" integrity sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g== dependencies: err-code "^2.0.2" @@ -9079,54 +5704,30 @@ promise-retry@^2.0.1: prompts@^2.0.1: version "2.3.2" - resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" + resolved "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz" integrity sha512-Q06uKs2CkNYVID0VqwfAl9mipo99zkBv/n2JtWY89Yxa3ZabWSrs0e2KTudKVa3peLUvYXMefDqIleLPVUBZMA== dependencies: kleur "^3.0.3" sisteransi "^1.0.4" -promzard@^0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/promzard/-/promzard-0.3.0.tgz#26a5d6ee8c7dee4cb12208305acfb93ba382a9ee" - integrity sha1-JqXW7ox97kyxIggwWs+5O6OCqe4= - dependencies: - read "1" - -proto-list@~1.2.1: - version "1.2.4" - resolved "https://registry.yarnpkg.com/proto-list/-/proto-list-1.2.4.tgz#212d5bfe1318306a420f6402b8e26ff39647a849" - integrity sha1-IS1b/hMYMGpCD2QCuOJv85ZHqEk= - -protocols@^1.1.0, protocols@^1.4.0: - version "1.4.7" - resolved "https://registry.yarnpkg.com/protocols/-/protocols-1.4.7.tgz#95f788a4f0e979b291ffefcf5636ad113d037d32" - integrity sha512-Fx65lf9/YDn3hUX08XUc0J8rSux36rEsyiv21ZGUC1mOyeM3lTRpZLcrm8aAolzS4itwVfm7TAPyxC2E5zd6xg== - -protoduck@^5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/protoduck/-/protoduck-5.0.1.tgz#03c3659ca18007b69a50fd82a7ebcc516261151f" - integrity sha512-WxoCeDCoCBY55BMvj4cAEjdVUFGRWed9ZxPlqTKYyw1nDDTQ4pqmnIMAGfJlg7Dx35uB/M+PHJPTmGOvaCaPTg== - dependencies: - genfun "^5.0.0" - proxy-from-env@1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" + resolved "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz" integrity sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg== prr@~1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/prr/-/prr-1.0.1.tgz#d3fc114ba06995a45ec6893f484ceb1d78f5f476" + resolved "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz" integrity sha1-0/wRS6BplaRexok/SEzrHXj19HY= psl@^1.1.28: version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" + resolved "https://registry.npmjs.org/psl/-/psl-1.8.0.tgz" integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== public-encrypt@^4.0.0: version "4.0.3" - resolved "https://registry.yarnpkg.com/public-encrypt/-/public-encrypt-4.0.3.tgz#4fcc9d77a07e48ba7527e7cbe0de33d0701331e0" + resolved "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz" integrity sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q== dependencies: bn.js "^4.1.0" @@ -9138,7 +5739,7 @@ public-encrypt@^4.0.0: pump@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz" integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== dependencies: end-of-stream "^1.1.0" @@ -9146,7 +5747,7 @@ pump@^2.0.0: pump@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" + resolved "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz" integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww== dependencies: end-of-stream "^1.1.0" @@ -9154,7 +5755,7 @@ pump@^3.0.0: pumpify@^1.3.3: version "1.5.1" - resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + resolved "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz" integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== dependencies: duplexify "^3.6.0" @@ -9163,17 +5764,17 @@ pumpify@^1.3.3: punycode@1.3.2, punycode@^1.2.4, punycode@^1.3.2: version "1.3.2" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-1.3.2.tgz#9653a036fb7c1ee42342f2325cceefea3926c48d" + resolved "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz" integrity sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0= punycode@^2.1.0, punycode@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" + resolved "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz" integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== puppeteer-core@^10.0.0: version "10.2.0" - resolved "https://registry.yarnpkg.com/puppeteer-core/-/puppeteer-core-10.2.0.tgz#8d6606cf345fc0e421bc0612055579ea53234111" + resolved "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-10.2.0.tgz" integrity sha512-c1COxSnfynsE6Mtt+dW0t3TITjF9Ku4dnJbFMDDVhLQuMTYSpz4rkSP37qvzcSo3k02/Ac3GYWk0/ncp6DKZNA== dependencies: debug "4.3.1" @@ -9189,46 +5790,31 @@ puppeteer-core@^10.0.0: unbzip2-stream "1.3.3" ws "7.4.6" -q@^1.5.1: - version "1.5.1" - resolved "https://registry.yarnpkg.com/q/-/q-1.5.1.tgz#7e32f75b41381291d04611f1bf14109ac00651d7" - integrity sha1-fjL3W0E4EpHQRhHxvxQQmsAGUdc= - qs@~6.5.2: version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" + resolved "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz" integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== querystring-es3@^0.2.0: version "0.2.1" - resolved "https://registry.yarnpkg.com/querystring-es3/-/querystring-es3-0.2.1.tgz#9ec61f79049875707d69414596fd907a4d711e73" + resolved "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz" integrity sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM= querystring@0.2.0: version "0.2.0" - resolved "https://registry.yarnpkg.com/querystring/-/querystring-0.2.0.tgz#b209849203bb25df820da756e747005878521620" + resolved "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz" integrity sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA= -quick-lru@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8" - integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g= - -quick-lru@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f" - integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g== - randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5, randombytes@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" + resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz" integrity sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ== dependencies: safe-buffer "^5.1.0" randomfill@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/randomfill/-/randomfill-1.0.4.tgz#c92196fc86ab42be983f1bf31778224931d61458" + resolved "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz" integrity sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw== dependencies: randombytes "^2.0.5" @@ -9236,7 +5822,7 @@ randomfill@^1.0.3: rc@^1.2.7: version "1.2.8" - resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed" + resolved "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz" integrity sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw== dependencies: deep-extend "^0.6.0" @@ -9246,139 +5832,47 @@ rc@^1.2.7: react-is@^16.12.0: version "16.13.1" - resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" + resolved "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz" integrity sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ== react@^17.0.2: version "17.0.2" - resolved "https://registry.yarnpkg.com/react/-/react-17.0.2.tgz#d0b5cc516d29eb3eee383f75b62864cfb6800037" + resolved "https://registry.npmjs.org/react/-/react-17.0.2.tgz" integrity sha512-gnhPt75i/dq/z3/6q/0asP78D0u592D5L1pd7M8P+dck6Fu/jJeL6iVVK23fptSUZj8Vjf++7wXA8UNclGQcbA== dependencies: loose-envify "^1.1.0" object-assign "^4.1.1" -read-cmd-shim@^1.0.1: - version "1.0.5" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-1.0.5.tgz#87e43eba50098ba5a32d0ceb583ab8e43b961c16" - integrity sha512-v5yCqQ/7okKoZZkBQUAfTsQ3sVJtXdNfbPnI5cceppoxEVLYA3k+VtV2omkeo8MS94JCy4fSiUwlRBAwCVRPUA== - dependencies: - graceful-fs "^4.1.2" - -read-cmd-shim@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/read-cmd-shim/-/read-cmd-shim-2.0.0.tgz#4a50a71d6f0965364938e9038476f7eede3928d9" - integrity sha512-HJpV9bQpkl6KwjxlJcBoqu9Ba0PQg8TqSNIOrulGt54a0uup0HtevreFHzYzkm0lpnleRdNBzXznKrgxglEHQw== - read-package-json-fast@^2.0.1: version "2.0.3" - resolved "https://registry.yarnpkg.com/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz#323ca529630da82cb34b36cc0b996693c98c2b83" + resolved "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-2.0.3.tgz" integrity sha512-W/BKtbL+dUjTuRL2vziuYhp76s5HZ9qQhd/dKfWIZveD0O40453QNyZhC0e63lqZrAQ4jiOapVoeJ7JrszenQQ== dependencies: json-parse-even-better-errors "^2.3.0" npm-normalize-package-bin "^1.0.1" -"read-package-json@1 || 2", read-package-json@^2.0.0, read-package-json@^2.0.13: - version "2.1.2" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-2.1.2.tgz#6992b2b66c7177259feb8eaac73c3acd28b9222a" - integrity sha512-D1KmuLQr6ZSJS0tW8hf3WGpRlwszJOXZ3E8Yd/DNRaM5d+1wVRZdHlpGBLAuovjr28LbWvjpWkBHMxpRGGjzNA== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^2.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-json@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-3.0.1.tgz#c7108f0b9390257b08c21e3004d2404c806744b9" - integrity sha512-aLcPqxovhJTVJcsnROuuzQvv6oziQx4zd3JvG0vGCL5MjTONUc4uJ90zCBC6R7W7oUKBNoR/F8pkyfVwlbxqng== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-json@^4.1.1: - version "4.1.1" - resolved "https://registry.yarnpkg.com/read-package-json/-/read-package-json-4.1.1.tgz#153be72fce801578c1c86b8ef2b21188df1b9eea" - integrity sha512-P82sbZJ3ldDrWCOSKxJT0r/CXMWR0OR3KRh55SgKo3p91GSIEEC32v3lSHAvO/UcH3/IoL7uqhOFBduAnwdldw== - dependencies: - glob "^7.1.1" - json-parse-even-better-errors "^2.3.0" - normalize-package-data "^3.0.0" - npm-normalize-package-bin "^1.0.0" - -read-package-tree@^5.1.6, read-package-tree@^5.3.1: - version "5.3.1" - resolved "https://registry.yarnpkg.com/read-package-tree/-/read-package-tree-5.3.1.tgz#a32cb64c7f31eb8a6f31ef06f9cedf74068fe636" - integrity sha512-mLUDsD5JVtlZxjSlPPx1RETkNjjvQYuweKwNVt1Sn8kP5Jh44pvYuUHCp6xSVDZWbNxVxG5lyZJ921aJH61sTw== - dependencies: - read-package-json "^2.0.0" - readdir-scoped-modules "^1.0.0" - util-promisify "^2.1.0" - -read-pkg-up@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-1.0.1.tgz#9d63c13276c065918d57f002a57f40a1b643fb02" - integrity sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI= - dependencies: - find-up "^1.0.0" - read-pkg "^1.0.0" - -read-pkg-up@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07" - integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc= - dependencies: - find-up "^2.0.0" - read-pkg "^3.0.0" - read-pkg-up@^7.0.1: version "7.0.1" - resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507" + resolved "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-7.0.1.tgz" integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg== dependencies: find-up "^4.1.0" read-pkg "^5.2.0" type-fest "^0.8.1" -read-pkg@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-1.1.0.tgz#f5ffaa5ecd29cb31c0474bca7d756b6bb29e3f28" - integrity sha1-9f+qXs0pyzHAR0vKfXVra7KePyg= - dependencies: - load-json-file "^1.0.0" - normalize-package-data "^2.3.2" - path-type "^1.0.0" - -read-pkg@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389" - integrity sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k= - dependencies: - load-json-file "^4.0.0" - normalize-package-data "^2.3.2" - path-type "^3.0.0" - read-pkg@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc" + resolved "https://registry.npmjs.org/read-pkg/-/read-pkg-5.2.0.tgz" integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg== dependencies: "@types/normalize-package-data" "^2.4.0" normalize-package-data "^2.5.0" - parse-json "^5.0.0" - type-fest "^0.6.0" - -read@1, read@~1.0.1: - version "1.0.7" - resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4" - integrity sha1-s9oZvQUkMal2cdRKQmNK33ELQMQ= - dependencies: - mute-stream "~0.0.4" + parse-json "^5.0.0" + type-fest "^0.6.0" -"readable-stream@1 || 2", "readable-stream@2 || 3", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== dependencies: core-util-is "~1.0.0" @@ -9389,28 +5883,18 @@ read@1, read@~1.0.1: string_decoder "~1.1.1" util-deprecate "~1.0.1" -readable-stream@3, readable-stream@^3.0.0, readable-stream@^3.0.2, readable-stream@^3.1.1, readable-stream@^3.4.0: +readable-stream@^3.1.1, readable-stream@^3.4.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.6.0.tgz#337bbda3adc0706bd3e024426a286d4b4b2c9198" + resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz" integrity sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA== dependencies: inherits "^2.0.3" string_decoder "^1.1.1" util-deprecate "^1.0.1" -readdir-scoped-modules@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.1.0.tgz#8d45407b4f870a0dcaebc0e28670d18e74514309" - integrity sha512-asaikDeqAQg7JifRsZn1NJZXo9E+VwlyCfbkZhwyISinqk5zNS6266HS5kah6P0SaQKGF6SkNnZVHUzHFYxYDw== - dependencies: - debuglog "^1.0.1" - dezalgo "^1.0.0" - graceful-fs "^4.1.2" - once "^1.3.0" - readdirp@^2.2.1: version "2.2.1" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz" integrity sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ== dependencies: graceful-fs "^4.1.11" @@ -9419,50 +5903,26 @@ readdirp@^2.2.1: readdirp@~3.6.0: version "3.6.0" - resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.6.0.tgz#74a370bd857116e245b29cc97340cd431a02a6c7" + resolved "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz" integrity sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA== dependencies: picomatch "^2.2.1" rechoir@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" + resolved "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz" integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= dependencies: resolve "^1.1.6" -redent@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-1.0.0.tgz#cf916ab1fd5f1f16dfb20822dd6ec7f730c2afde" - integrity sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94= - dependencies: - indent-string "^2.1.0" - strip-indent "^1.0.1" - -redent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa" - integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo= - dependencies: - indent-string "^3.0.0" - strip-indent "^2.0.0" - -redent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f" - integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg== - dependencies: - indent-string "^4.0.0" - strip-indent "^3.0.0" - regenerator-runtime@^0.13.4: version "0.13.5" - resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz#d878a1d094b4306d10b9096484b33ebd55e26697" + resolved "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.5.tgz" integrity sha512-ZS5w8CpKFinUzOwW3c83oPeVXoNsrLsaCoLtJvAClH135j/R77RuymhiSErhm2lKcwSCIpmvIWSbDkIfAqKQlA== regex-not@^1.0.0, regex-not@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" + resolved "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz" integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== dependencies: extend-shallow "^3.0.2" @@ -9470,45 +5930,38 @@ regex-not@^1.0.0, regex-not@^1.0.2: remove-trailing-separator@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef" + resolved "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz" integrity sha1-wkvOKig62tW8P1jg1IJJuSN52O8= repeat-element@^1.1.2: version "1.1.3" - resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" + resolved "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz" integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== repeat-string@^1.6.1: version "1.6.1" - resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" + resolved "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz" integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= -repeating@^2.0.0: - version "2.0.1" - resolved "https://registry.yarnpkg.com/repeating/-/repeating-2.0.1.tgz#5214c53a926d3552707527fbab415dbc08d06dda" - integrity sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo= - dependencies: - is-finite "^1.0.0" - request-promise-core@1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/request-promise-core/-/request-promise-core-1.1.3.tgz#e9a3c081b51380dfea677336061fea879a829ee9" + resolved "https://registry.npmjs.org/request-promise-core/-/request-promise-core-1.1.3.tgz" integrity sha512-QIs2+ArIGQVp5ZYbWD5ZLCY29D5CfWizP8eWnm8FoGD1TX61veauETVQbrV60662V0oFBkrDOuaBI8XgtuyYAQ== dependencies: lodash "^4.17.15" request-promise-native@^1.0.8: version "1.0.8" - resolved "https://registry.yarnpkg.com/request-promise-native/-/request-promise-native-1.0.8.tgz#a455b960b826e44e2bf8999af64dff2bfe58cb36" + resolved "https://registry.npmjs.org/request-promise-native/-/request-promise-native-1.0.8.tgz" integrity sha512-dapwLGqkHtwL5AEbfenuzjTYg35Jd6KPytsC2/TLkVMz8rm+tNt72MGUWT1RP/aYawMpN6HqbNGBQaRcBtjQMQ== dependencies: request-promise-core "1.1.3" stealthy-require "^1.1.1" tough-cookie "^2.3.3" -request@^2.87.0, request@^2.88.2: +request@^2.88.2: version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" + resolved "https://registry.npmjs.org/request/-/request-2.88.2.tgz" integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== dependencies: aws-sign2 "~0.7.0" @@ -9534,66 +5987,46 @@ request@^2.87.0, request@^2.88.2: require-directory@^2.1.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" + resolved "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz" integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= require-main-filename@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" + resolved "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz" integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== -resolve-cwd@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-2.0.0.tgz#00a9f7387556e27038eae232caa372a6a59b665a" - integrity sha1-AKn3OHVW4nA46uIyyqNypqWbZlo= - dependencies: - resolve-from "^3.0.0" - resolve-cwd@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" + resolved "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz" integrity sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg== dependencies: resolve-from "^5.0.0" -resolve-from@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-3.0.0.tgz#b22c7af7d9d6881bc8b6e653335eebcb0a188748" - integrity sha1-six699nWiBvItuZTM17rywoYh0g= - resolve-from@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz" integrity sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g== resolve-from@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" + resolved "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== resolve-url@^0.2.1: version "0.2.1" - resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" + resolved "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz" integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= resolve@^1.1.6, resolve@^1.10.0, resolve@^1.11.0, resolve@^1.11.1, resolve@^1.17.0, resolve@^1.3.2: version "1.17.0" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" + resolved "https://registry.npmjs.org/resolve/-/resolve-1.17.0.tgz" integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== dependencies: path-parse "^1.0.6" -restore-cursor@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-2.0.0.tgz#9f7ee287f82fd326d4fd162923d62129eee0dfaf" - integrity sha1-n37ih/gv0ybU/RYpI9YhKe7g368= - dependencies: - onetime "^2.0.0" - signal-exit "^3.0.2" - restore-cursor@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/restore-cursor/-/restore-cursor-3.1.0.tgz#39f67c54b3a7a58cea5236d95cf0034239631f7e" + resolved "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz" integrity sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA== dependencies: onetime "^5.1.0" @@ -9601,49 +6034,44 @@ restore-cursor@^3.1.0: ret@~0.1.10: version "0.1.15" - resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" + resolved "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz" integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== -retry@^0.10.0: - version "0.10.1" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.10.1.tgz#e76388d217992c252750241d3d3956fed98d8ff4" - integrity sha1-52OI0heZLCUnUCQdPTlW/tmNj/Q= - retry@^0.12.0: version "0.12.0" - resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b" + resolved "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz" integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs= reusify@^1.0.4: version "1.0.4" - resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76" + resolved "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz" integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw== -rimraf@2, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3: - version "2.7.1" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@3.0.2, rimraf@^3.0.0, rimraf@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz" integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== dependencies: glob "^7.1.3" +rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.3: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + ripemd160@^2.0.0, ripemd160@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/ripemd160/-/ripemd160-2.0.2.tgz#a1c1a6f624751577ba5d07914cbc92850585890c" + resolved "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz" integrity sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA== dependencies: hash-base "^3.0.0" inherits "^2.0.1" -rollup-plugin-commonjs@^10.0.0, rollup-plugin-commonjs@^10.1.0: +rollup-plugin-commonjs@^10.0.0: version "10.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz#417af3b54503878e084d127adf4d1caf8beb86fb" + resolved "https://registry.npmjs.org/rollup-plugin-commonjs/-/rollup-plugin-commonjs-10.1.0.tgz" integrity sha512-jlXbjZSQg8EIeAAvepNwhJj++qJWNJw1Cl0YnOqKtP5Djx+fFGkp3WRh+W0ASCaFG5w1jhmzDxgu3SJuVxPF4Q== dependencies: estree-walker "^0.6.1" @@ -9652,9 +6080,9 @@ rollup-plugin-commonjs@^10.0.0, rollup-plugin-commonjs@^10.1.0: resolve "^1.11.0" rollup-pluginutils "^2.8.1" -rollup-plugin-filesize@^9.0.1, rollup-plugin-filesize@^9.1.1: +rollup-plugin-filesize@^9.0.1: version "9.1.1" - resolved "https://registry.yarnpkg.com/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.1.tgz#31a6b02b27ce08082ef0970cfe4c451714ff91c4" + resolved "https://registry.npmjs.org/rollup-plugin-filesize/-/rollup-plugin-filesize-9.1.1.tgz" integrity sha512-x0r2A85TCEdRwF3rm+bcN4eAmbER8tt+YVf88gBQ6sLyH4oGcnNLPQqAUX+v7mIvHC/y59QwZvo6vxaC2ias6Q== dependencies: "@babel/runtime" "^7.13.8" @@ -9666,9 +6094,9 @@ rollup-plugin-filesize@^9.0.1, rollup-plugin-filesize@^9.1.1: pacote "^11.2.7" terser "^5.6.0" -rollup-plugin-node-resolve@^5.0.0, rollup-plugin-node-resolve@^5.2.0: +rollup-plugin-node-resolve@^5.0.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz#730f93d10ed202473b1fb54a5997a7db8c6d8523" + resolved "https://registry.npmjs.org/rollup-plugin-node-resolve/-/rollup-plugin-node-resolve-5.2.0.tgz" integrity sha512-jUlyaDXts7TW2CqQ4GaO5VJ4PwwaV8VUGA7+km3n6k6xtOEacf61u0VXwN80phY/evMcaS+9eIeJ9MOyDxt5Zw== dependencies: "@types/resolve" "0.0.8" @@ -9677,9 +6105,9 @@ rollup-plugin-node-resolve@^5.0.0, rollup-plugin-node-resolve@^5.2.0: resolve "^1.11.1" rollup-pluginutils "^2.8.1" -rollup-plugin-replace@^2.1.0, rollup-plugin-replace@^2.2.0: +rollup-plugin-replace@^2.1.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz#f41ae5372e11e7a217cde349c8b5d5fd115e70e3" + resolved "https://registry.npmjs.org/rollup-plugin-replace/-/rollup-plugin-replace-2.2.0.tgz" integrity sha512-/5bxtUPkDHyBJAKketb4NfaeZjL5yLZdeUihSfbF2PQMz+rSTEb8ARKoOl3UBT4m7/X+QOXJo3sLTcq+yMMYTA== dependencies: magic-string "^0.25.2" @@ -9687,7 +6115,7 @@ rollup-plugin-replace@^2.1.0, rollup-plugin-replace@^2.2.0: rollup-plugin-terser@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz#071866585aea104bfbb9dd1019ac523e63c81e45" + resolved "https://registry.npmjs.org/rollup-plugin-terser/-/rollup-plugin-terser-6.1.0.tgz" integrity sha512-4fB3M9nuoWxrwm39habpd4hvrbrde2W2GG4zEGPQg1YITNkM3Tqur5jSuXlWNzbv/2aMLJ+dZJaySc3GCD8oDw== dependencies: "@babel/code-frame" "^7.8.3" @@ -9695,84 +6123,69 @@ rollup-plugin-terser@^6.1.0: serialize-javascript "^3.0.0" terser "^4.7.0" -rollup-plugin-terser@^7.0.2: - version "7.0.2" - resolved "https://registry.yarnpkg.com/rollup-plugin-terser/-/rollup-plugin-terser-7.0.2.tgz#e8fbba4869981b2dc35ae7e8a502d5c6c04d324d" - integrity sha512-w3iIaU4OxcF52UUXiZNsNeuXIMDvFrr+ZXK6bFZ0Q60qyVfq4uLptoS4bbq3paG3x216eQllFZX7zt6TIImguQ== - dependencies: - "@babel/code-frame" "^7.10.4" - jest-worker "^26.2.1" - serialize-javascript "^4.0.0" - terser "^5.0.0" - rollup-pluginutils@^2.6.0, rollup-pluginutils@^2.8.1: version "2.8.2" - resolved "https://registry.yarnpkg.com/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" + resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== dependencies: estree-walker "^0.6.1" -rollup@^2.18.1, rollup@^2.56.3: +rollup@^2.18.1: version "2.56.3" - resolved "https://registry.yarnpkg.com/rollup/-/rollup-2.56.3.tgz#b63edadd9851b0d618a6d0e6af8201955a77aeff" + resolved "https://registry.npmjs.org/rollup/-/rollup-2.56.3.tgz" integrity sha512-Au92NuznFklgQCUcV96iXlxUbHuB1vQMaH76DHl5M11TotjOHwqk9CwcrT78+Tnv4FN9uTBxq6p4EJoYkpyekg== optionalDependencies: fsevents "~2.3.2" rsvp@^4.8.4: version "4.8.5" - resolved "https://registry.yarnpkg.com/rsvp/-/rsvp-4.8.5.tgz#c8f155311d167f68f21e168df71ec5b083113734" + resolved "https://registry.npmjs.org/rsvp/-/rsvp-4.8.5.tgz" integrity sha512-nfMOlASu9OnRJo1mbEk2cz0D56a1MBNrJ7orjRZQG10XDyuvwksKbuXNp6qa+kbn839HwjwhBzhFmdsaEAfauA== -run-async@^2.2.0, run-async@^2.4.0: - version "2.4.1" - resolved "https://registry.yarnpkg.com/run-async/-/run-async-2.4.1.tgz#8440eccf99ea3e70bd409d49aab88e10c189a455" - integrity sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ== - run-parallel@^1.1.9: version "1.1.9" - resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679" + resolved "https://registry.npmjs.org/run-parallel/-/run-parallel-1.1.9.tgz" integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q== run-queue@^1.0.0, run-queue@^1.0.3: version "1.0.3" - resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47" + resolved "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz" integrity sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec= dependencies: aproba "^1.1.1" -rxjs@^6.4.0, rxjs@^6.6.0, rxjs@^6.6.7: +rxjs@^6.6.7: version "6.6.7" - resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.6.7.tgz#90ac018acabf491bf65044235d5863c4dab804c9" + resolved "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz" integrity sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ== dependencies: tslib "^1.9.0" -safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@^5.2.0, safe-buffer@^5.2.1: - version "5.2.1" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.1.tgz#1eaf9fa9bdb1fdd4ec75f58f9cdb4e6b7827eec6" - integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== - -safe-buffer@~5.1.0, safe-buffer@~5.1.1: +safe-buffer@^5.0.1, safe-buffer@^5.1.0, safe-buffer@^5.1.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1: version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz" integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== +safe-buffer@^5.2.1: + version "5.2.1" + resolved "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz" + integrity sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ== + safe-regex@^1.1.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" + resolved "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz" integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= dependencies: ret "~0.1.10" "safer-buffer@>= 2.1.2 < 3", "safer-buffer@>= 2.1.2 < 3.0.0", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" + resolved "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz" integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== sane@^4.0.3: version "4.1.0" - resolved "https://registry.yarnpkg.com/sane/-/sane-4.1.0.tgz#ed881fd922733a6c461bc189dc2b6c006f3ffded" + resolved "https://registry.npmjs.org/sane/-/sane-4.1.0.tgz" integrity sha512-hhbzAgTIX8O7SHfp2c8/kREfEn4qO/9q8C9beyY6+tvZ87EpoZ3i1RIEvp27YBswnNbY9mWd6paKVmKbAgLfZA== dependencies: "@cnakazawa/watch" "^1.0.3" @@ -9787,19 +6200,19 @@ sane@^4.0.3: sax@^1.2.4: version "1.2.4" - resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" + resolved "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== saxes@^5.0.0: version "5.0.1" - resolved "https://registry.yarnpkg.com/saxes/-/saxes-5.0.1.tgz#eebab953fa3b7608dbe94e5dadb15c888fa6696d" + resolved "https://registry.npmjs.org/saxes/-/saxes-5.0.1.tgz" integrity sha512-5LBh1Tls8c9xgGjw3QrMwETmTMVk0oFgvrFSvWx62llR2hcEInrKNZ2GZCCuuy2lvWrdl5jhbpeqc5hRYKFOcw== dependencies: xmlchars "^2.2.0" schema-utils@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-1.0.0.tgz#0b79a93204d7b600d4b2850d1f66c2a34951c770" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz" integrity sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g== dependencies: ajv "^6.1.0" @@ -9808,7 +6221,7 @@ schema-utils@^1.0.0: schema-utils@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/schema-utils/-/schema-utils-3.1.1.tgz#bc74c4b6b6995c1d88f76a8b77bea7219e0c8281" + resolved "https://registry.npmjs.org/schema-utils/-/schema-utils-3.1.1.tgz" integrity sha512-Y5PQxS4ITlC+EahLuXaY86TXfR7Dc5lw294alXOq86JAHCihAIZfqv8nNCWvaEJvaC51uN9hbLGeV0cFBdH+Fw== dependencies: "@types/json-schema" "^7.0.8" @@ -9817,53 +6230,41 @@ schema-utils@^3.0.0: semver-compare@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/semver-compare/-/semver-compare-1.0.0.tgz#0dee216a1c941ab37e9efb1788f6afc5ff5537fc" + resolved "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz" integrity sha1-De4hahyUGrN+nvsXiPavxf9VN/w= -"semver@2 || 3 || 4 || 5", "semver@2.x || 3.x || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.5.1, semver@^5.6.0, semver@^5.7.0: +"semver@2 || 3 || 4 || 5", semver@^5.3.0, semver@^5.4.1, semver@^5.5.0, semver@^5.6.0: version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" + resolved "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz" integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== -semver@7.3.5, semver@7.x, semver@^7.1.1, semver@^7.1.3, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: +semver@7.3.5, semver@7.x, semver@^7.1.1, semver@^7.2.1, semver@^7.3.2, semver@^7.3.4, semver@^7.3.5: version "7.3.5" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.5.tgz#0b621c879348d8998e4b0e4be94b3f12e6018ef7" + resolved "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz" integrity sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ== dependencies: lru-cache "^6.0.0" -semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: +semver@^6.0.0, semver@^6.3.0: version "6.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" + resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== -semver@~5.3.0: - version "5.3.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" - integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= - serialize-javascript@^3.0.0, serialize-javascript@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-3.1.0.tgz#8bf3a9170712664ef2561b44b691eafe399214ea" + resolved "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-3.1.0.tgz" integrity sha512-JIJT1DGiWmIKhzRsG91aS6Ze4sFUrYbltlkg2onR5OrnNM02Kl/hnY/T4FN2omvyeBbQmMJv+K4cPOpGzOTFBg== dependencies: randombytes "^2.1.0" -serialize-javascript@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/serialize-javascript/-/serialize-javascript-4.0.0.tgz#b525e1238489a5ecfc42afacc3fe99e666f4b1aa" - integrity sha512-GaNA54380uFefWghODBWEGisLZFj00nS5ACs6yHa9nLqlLpVLO8ChDGeKRjZnV4Nh4n0Qi7nhYZD/9fCPzEqkw== - dependencies: - randombytes "^2.1.0" - set-blocking@^2.0.0, set-blocking@~2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" + resolved "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz" integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= set-value@^2.0.0, set-value@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" + resolved "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz" integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== dependencies: extend-shallow "^2.0.1" @@ -9873,51 +6274,44 @@ set-value@^2.0.0, set-value@^2.0.1: setimmediate@^1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/setimmediate/-/setimmediate-1.0.5.tgz#290cbb232e306942d7d7ea9b83732ab7856f8285" + resolved "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz" integrity sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU= sha.js@^2.4.0, sha.js@^2.4.8: version "2.4.11" - resolved "https://registry.yarnpkg.com/sha.js/-/sha.js-2.4.11.tgz#37a5cf0b81ecbc6943de109ba2960d1b26584ae7" + resolved "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz" integrity sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ== dependencies: inherits "^2.0.1" safe-buffer "^5.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" - integrity sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA== - dependencies: - kind-of "^6.0.2" - shebang-command@^1.2.0: version "1.2.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz" integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= dependencies: shebang-regex "^1.0.0" shebang-command@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" + resolved "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz" integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== dependencies: shebang-regex "^3.0.0" shebang-regex@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz" integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= shebang-regex@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" + resolved "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz" integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== shelljs@^0.8.3, shelljs@^0.8.4: version "0.8.4" - resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" + resolved "https://registry.npmjs.org/shelljs/-/shelljs-0.8.4.tgz" integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== dependencies: glob "^7.0.0" @@ -9926,12 +6320,12 @@ shelljs@^0.8.3, shelljs@^0.8.4: shellwords@^0.1.1: version "0.1.1" - resolved "https://registry.yarnpkg.com/shellwords/-/shellwords-0.1.1.tgz#d6b9181c1a48d397324c84871efbcfc73fc0654b" + resolved "https://registry.npmjs.org/shellwords/-/shellwords-0.1.1.tgz" integrity sha512-vFwSUfQvqybiICwZY5+DAWIPLKsWO31Q91JSKl3UYv+K5c2QRPzn0qzec6QPu1Qc9eHYItiP3NdJqNVqetYAww== shx@^0.3.2: version "0.3.3" - resolved "https://registry.yarnpkg.com/shx/-/shx-0.3.3.tgz#681a88c7c10db15abe18525349ed474f0f1e7b9f" + resolved "https://registry.npmjs.org/shx/-/shx-0.3.3.tgz" integrity sha512-nZJ3HFWVoTSyyB+evEKjJ1STiixGztlqwKLTUNV5KqMWtGey9fTd4KU1gdZ1X9BV6215pswQ/Jew9NsuS/fNDA== dependencies: minimist "^1.2.3" @@ -9939,12 +6333,12 @@ shx@^0.3.2: signal-exit@^3.0.0, signal-exit@^3.0.2, signal-exit@^3.0.3: version "3.0.4" - resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.4.tgz#366a4684d175b9cab2081e3681fda3747b6c51d7" + resolved "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.4.tgz" integrity sha512-rqYhcAnZ6d/vTPGghdrw7iumdcbXpsk1b8IG/rz+VWV51DM0p7XCtMoJ3qhPLIbp3tvyt3pKRbaaEMZYpHto8Q== sirv@^1.0.7: version "1.0.17" - resolved "https://registry.yarnpkg.com/sirv/-/sirv-1.0.17.tgz#86e2c63c612da5a1dace1c16c46f524aaa26ac45" + resolved "https://registry.npmjs.org/sirv/-/sirv-1.0.17.tgz" integrity sha512-qx9go5yraB7ekT7bCMqUHJ5jEaOC/GXBxUWv+jeWnb7WzHUFdcQPGWk7YmAwFBaQBrogpuSqd/azbC2lZRqqmw== dependencies: "@polka/url" "^1.0.0-next.20" @@ -9953,26 +6347,12 @@ sirv@^1.0.7: sisteransi@^1.0.4: version "1.0.5" - resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + resolved "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz" integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== -size-limit@^4.5.2: - version "4.12.0" - resolved "https://registry.yarnpkg.com/size-limit/-/size-limit-4.12.0.tgz#ecc9c0448c049a40b10e76b5e1b4a20f99a54468" - integrity sha512-LwlUDPxFJbJDIJsBE5bKo8kFMuxmuewBMDjgfSoQwnO27V8DSK+j6881nsrX3GoM3bJMFIeEq56thqBEdYC8bw== - dependencies: - bytes-iec "^3.1.1" - chokidar "^3.5.1" - ci-job-number "^1.2.2" - colorette "^1.2.2" - globby "^11.0.3" - lilconfig "^2.0.3" - ora "^5.4.1" - read-pkg-up "^7.0.1" - size-limit@^5.0.3: version "5.0.3" - resolved "https://registry.yarnpkg.com/size-limit/-/size-limit-5.0.3.tgz#de4d4e9366274bd7987673ae76d51af02f57089b" + resolved "https://registry.npmjs.org/size-limit/-/size-limit-5.0.3.tgz" integrity sha512-522c33FTs09sDCN3SUjtxF3Jg361O8Xm1Rh9MUuGGVwY7XGvroE/vL20+//qGltUprGzYQONBbzy9TTdOJWgbw== dependencies: bytes-iec "^3.1.1" @@ -9983,24 +6363,14 @@ size-limit@^5.0.3: lilconfig "^2.0.3" mico-spinner "^1.2.2" -slash@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" - integrity sha1-xB8vbDn8FtHNF61LXYlhFK5HDVU= - -slash@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" - integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== - slash@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" + resolved "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz" integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== slice-ansi@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-3.0.0.tgz#31ddc10930a1b7e0b67b08c96c2f49b77a789787" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz" integrity sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ== dependencies: ansi-styles "^4.0.0" @@ -10009,26 +6379,21 @@ slice-ansi@^3.0.0: slice-ansi@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/slice-ansi/-/slice-ansi-4.0.0.tgz#500e8dd0fd55b05815086255b3195adf2a45fe6b" + resolved "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz" integrity sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ== dependencies: ansi-styles "^4.0.0" astral-regex "^2.0.0" is-fullwidth-code-point "^3.0.0" -slide@^1.1.6: - version "1.1.6" - resolved "https://registry.yarnpkg.com/slide/-/slide-1.1.6.tgz#56eb027d65b4d2dce6cb2e2d32c4d4afc9e1d707" - integrity sha1-VusCfWW00tzmyy4tMsTUr8nh1wc= - smart-buffer@^4.1.0: version "4.1.0" - resolved "https://registry.yarnpkg.com/smart-buffer/-/smart-buffer-4.1.0.tgz#91605c25d91652f4661ea69ccf45f1b331ca21ba" + resolved "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.1.0.tgz" integrity sha512-iVICrxOzCynf/SNaBQCw34eM9jROU/s5rzIhpOvzhzuYHfJR/DhZfDkXiZSgKXfgv26HT3Yni3AV/DGw0cGnnw== snapdragon-node@^2.0.1: version "2.1.1" - resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" + resolved "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz" integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== dependencies: define-property "^1.0.0" @@ -10037,14 +6402,14 @@ snapdragon-node@^2.0.1: snapdragon-util@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" + resolved "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz" integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== dependencies: kind-of "^3.2.0" snapdragon@^0.8.1: version "0.8.2" - resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" + resolved "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz" integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== dependencies: base "^0.11.1" @@ -10056,75 +6421,36 @@ snapdragon@^0.8.1: source-map-resolve "^0.5.0" use "^3.1.0" -socks-proxy-agent@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-4.0.2.tgz#3c8991f3145b2799e70e11bd5fbc8b1963116386" - integrity sha512-NT6syHhI9LmuEMSK6Kd2V7gNv5KFZoLE7V5udWmn0de+3Mkj3UMA/AJPLyeNUVmElCurSHtUdM3ETpR3z770Wg== - dependencies: - agent-base "~4.2.1" - socks "~2.3.2" - -socks-proxy-agent@^5.0.0: - version "5.0.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-5.0.0.tgz#7c0f364e7b1cf4a7a437e71253bed72e9004be60" - integrity sha512-lEpa1zsWCChxiynk+lCycKuC502RxDWLKJZoIhnxrWNjLSDGYRFflHA1/228VkRcnv9TIb8w98derGbpKxJRgA== - dependencies: - agent-base "6" - debug "4" - socks "^2.3.3" - socks-proxy-agent@^6.0.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz#869cf2d7bd10fea96c7ad3111e81726855e285c3" + resolved "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-6.1.0.tgz" integrity sha512-57e7lwCN4Tzt3mXz25VxOErJKXlPfXmkMLnk310v/jwW20jWRVcgsOit+xNkN3eIEdB47GwnfAEBLacZ/wVIKg== dependencies: agent-base "^6.0.2" debug "^4.3.1" socks "^2.6.1" -socks@^2.3.3, socks@^2.6.1: +socks@^2.6.1: version "2.6.1" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.6.1.tgz#989e6534a07cf337deb1b1c94aaa44296520d30e" + resolved "https://registry.npmjs.org/socks/-/socks-2.6.1.tgz" integrity sha512-kLQ9N5ucj8uIcxrDwjm0Jsqk06xdpBjGNQtpXy4Q8/QY2k+fY7nZH8CARy+hkbG+SGAovmzzuauCpBlb8FrnBA== dependencies: ip "^1.1.5" smart-buffer "^4.1.0" -socks@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/socks/-/socks-2.3.3.tgz#01129f0a5d534d2b897712ed8aceab7ee65d78e3" - integrity sha512-o5t52PCNtVdiOvzMry7wU4aOqYWL0PeCXRWBEiJow4/i/wr+wpsJQ9awEu1EonLIqsfGd5qSgDdxEOvCdmBEpA== - dependencies: - ip "1.1.5" - smart-buffer "^4.1.0" - -sort-keys@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-2.0.0.tgz#658535584861ec97d730d6cf41822e1f56684128" - integrity sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg= - dependencies: - is-plain-obj "^1.0.0" - -sort-keys@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/sort-keys/-/sort-keys-4.2.0.tgz#6b7638cee42c506fff8c1cecde7376d21315be18" - integrity sha512-aUYIEU/UviqPgc8mHR6IW1EGxkAXpeRETYcrzg8cLAvUPZcpAlleSXHV2mY7G12GphSH6Gzv+4MMVSSkbdteHg== - dependencies: - is-plain-obj "^2.0.0" - source-list-map@^2.0.0: version "2.0.1" - resolved "https://registry.yarnpkg.com/source-list-map/-/source-list-map-2.0.1.tgz#3993bd873bfc48479cca9ea3a547835c7c154b34" + resolved "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz" integrity sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw== source-map-js@^0.6.2: version "0.6.2" - resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" + resolved "https://registry.npmjs.org/source-map-js/-/source-map-js-0.6.2.tgz" integrity sha512-/3GptzWzu0+0MBQFrDKzw/DvvMTUORvgY6k6jd/VS6iCR4RDTKWH6v6WPwQoUO8667uQEf9Oe38DxAYWY5F/Ug== source-map-resolve@^0.5.0: version "0.5.3" - resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" + resolved "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.3.tgz" integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== dependencies: atob "^2.1.2" @@ -10135,7 +6461,7 @@ source-map-resolve@^0.5.0: source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.12, source-map-support@~0.5.20: version "0.5.20" - resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.20.tgz#12166089f8f5e5e8c56926b377633392dd2cb6c9" + resolved "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.20.tgz" integrity sha512-n1lZZ8Ve4ksRqizaBQgxXDgKwttHDhyfQjA6YZZn8+AroHbsIz+JjwxQDxbp+7y5OYCI8t1Yk7etjD9CRd2hIw== dependencies: buffer-from "^1.0.0" @@ -10143,32 +6469,32 @@ source-map-support@^0.5.17, source-map-support@^0.5.6, source-map-support@~0.5.1 source-map-url@^0.4.0: version "0.4.0" - resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" + resolved "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz" integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= source-map@^0.5.0, source-map@^0.5.6: version "0.5.7" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz" integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= source-map@^0.6.0, source-map@^0.6.1, source-map@~0.6.1: version "0.6.1" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz" integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== source-map@^0.7.3, source-map@~0.7.2: version "0.7.3" - resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" + resolved "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz" integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== sourcemap-codec@^1.4.4: version "1.4.6" - resolved "https://registry.yarnpkg.com/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz#e30a74f0402bad09807640d39e971090a08ce1e9" + resolved "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.6.tgz" integrity sha512-1ZooVLYFxC448piVLBbtOxFcXwnymH9oUF8nRd3CuYDVvkRBxRl6pB4Mtas5a4drtL+E8LDgFkQNcgIw6tc8Hg== spdx-correct@^3.0.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.1.tgz#dece81ac9c1e6713e5f7d1b6f17d468fa53d89a9" + resolved "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.1.tgz" integrity sha512-cOYcUWwhCuHCXi49RhFRCyJEK3iPj1Ziz9DpViV3tbZOwXD49QzIN3MpOLJNxh2qwq2lJJZaKMVw9qNi4jTC0w== dependencies: spdx-expression-parse "^3.0.0" @@ -10176,12 +6502,12 @@ spdx-correct@^3.0.0: spdx-exceptions@^2.1.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz#3f28ce1a77a00372683eade4a433183527a2163d" + resolved "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.3.0.tgz" integrity sha512-/tTrYOC7PPI1nUAgx34hUpqXuyJG+DTHJTnIULG4rDygi4xu/tfgmq1e1cIRwRzwZgo4NLySi+ricLkZkw4i5A== spdx-expression-parse@^3.0.0: version "3.0.1" - resolved "https://registry.yarnpkg.com/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz#cf70f50482eefdc98e3ce0a6833e4a53ceeba679" + resolved "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz" integrity sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q== dependencies: spdx-exceptions "^2.1.0" @@ -10189,50 +6515,29 @@ spdx-expression-parse@^3.0.0: spdx-license-ids@^3.0.0: version "3.0.5" - resolved "https://registry.yarnpkg.com/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz#3694b5804567a458d3c8045842a6358632f62654" + resolved "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz" integrity sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q== spec.ts@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/spec.ts/-/spec.ts-1.1.3.tgz#2951ed40a984386fdd5bb287719e67a1ceaafff1" + resolved "https://registry.npmjs.org/spec.ts/-/spec.ts-1.1.3.tgz" integrity sha512-xDzHAwbHqe9OIHT1c+pnVpVuYSHNC5vk51aFKKoql2aH1RCzHplkd7MoSV7uLfzgm3GmlfpAfwLtfH2T3lQMmw== split-string@^3.0.1, split-string@^3.0.2: version "3.1.0" - resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" + resolved "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz" integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== dependencies: extend-shallow "^3.0.0" -split2@^2.0.0: - version "2.2.0" - resolved "https://registry.yarnpkg.com/split2/-/split2-2.2.0.tgz#186b2575bcf83e85b7d18465756238ee4ee42493" - integrity sha512-RAb22TG39LhI31MbreBgIuKiIKhVsawfTgEGqKHTK87aG+ul/PB8Sqoi3I7kVdRWiCfrKxK3uo4/YUkpNvhPbw== - dependencies: - through2 "^2.0.2" - -split2@^3.0.0: - version "3.2.2" - resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" - integrity sha512-9NThjpgZnifTkJpzTZ7Eue85S49QwpNhZTq6GRJwObb6jnLFNGB7Qm73V5HewTROPyxD0C29xqmaI68bQtV+hg== - dependencies: - readable-stream "^3.0.0" - -split@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/split/-/split-1.0.1.tgz#605bd9be303aa59fb35f9229fbea0ddec9ea07d9" - integrity sha512-mTyOoPbrivtXnwnIxZRFYRrPNtEFKlpB2fvjSnCQUiAA6qAZzqwna5envK4uk6OIeP17CsdF3rSBGYVBsU0Tkg== - dependencies: - through "2" - sprintf-js@~1.0.2: version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" + resolved "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz" integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= sshpk@^1.7.0: version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" + resolved "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz" integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== dependencies: asn1 "~0.2.3" @@ -10245,7 +6550,7 @@ sshpk@^1.7.0: safer-buffer "^2.0.2" tweetnacl "~0.14.0" -ssri@^6.0.0, ssri@^6.0.1: +ssri@^6.0.1: version "6.0.2" resolved "https://registry.yarnpkg.com/ssri/-/ssri-6.0.2.tgz#157939134f20464e7301ddba3e90ffa8f7728ac5" integrity sha512-cepbSq/neFK7xB6A50KHN0xHDotYzq58wWCa5LeWqnPrHG8GzfEjO/4O8kpmcGW+oaxkvhEJCWgbgNk4/ZV93Q== @@ -10254,26 +6559,26 @@ ssri@^6.0.0, ssri@^6.0.1: ssri@^8.0.0, ssri@^8.0.1: version "8.0.1" - resolved "https://registry.yarnpkg.com/ssri/-/ssri-8.0.1.tgz#638e4e439e2ffbd2cd289776d5ca457c4f51a2af" + resolved "https://registry.npmjs.org/ssri/-/ssri-8.0.1.tgz" integrity sha512-97qShzy1AiyxvPNIkLWoGua7xoQzzPjQ0HAH4B0rWKo7SZ6USuPcrUiAFrws0UH8RrbWmgq3LMTObhPIHbbBeQ== dependencies: minipass "^3.1.1" stable@^0.1.8: version "0.1.8" - resolved "https://registry.yarnpkg.com/stable/-/stable-0.1.8.tgz#836eb3c8382fe2936feaf544631017ce7d47a3cf" + resolved "https://registry.npmjs.org/stable/-/stable-0.1.8.tgz" integrity sha512-ji9qxRnOVfcuLDySj9qzhGSEFVobyt1kIOSkj1qZzYLzq7Tos/oUUWvotUPQLlrsidqsK6tBH89Bc9kL5zHA6w== stack-utils@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/stack-utils/-/stack-utils-2.0.2.tgz#5cf48b4557becb4638d0bc4f21d23f5d19586593" + resolved "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.2.tgz" integrity sha512-0H7QK2ECz3fyZMzQ8rH0j2ykpfbnd20BFtfg/SqVC2+sCTtcw0aDTGB7dk+de4U4uUeuz6nOtJcrkFFLG1B0Rg== dependencies: escape-string-regexp "^2.0.0" static-extend@^0.1.1: version "0.1.2" - resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" + resolved "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz" integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= dependencies: define-property "^0.2.5" @@ -10281,12 +6586,12 @@ static-extend@^0.1.1: stealthy-require@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/stealthy-require/-/stealthy-require-1.1.1.tgz#35b09875b4ff49f26a777e509b3090a3226bf24b" + resolved "https://registry.npmjs.org/stealthy-require/-/stealthy-require-1.1.1.tgz" integrity sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks= stream-browserify@^2.0.1: version "2.0.2" - resolved "https://registry.yarnpkg.com/stream-browserify/-/stream-browserify-2.0.2.tgz#87521d38a44aa7ee91ce1cd2a47df0cb49dd660b" + resolved "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz" integrity sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg== dependencies: inherits "~2.0.1" @@ -10294,7 +6599,7 @@ stream-browserify@^2.0.1: stream-each@^1.1.0: version "1.2.3" - resolved "https://registry.yarnpkg.com/stream-each/-/stream-each-1.2.3.tgz#ebe27a0c389b04fbcc233642952e10731afa9bae" + resolved "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz" integrity sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw== dependencies: end-of-stream "^1.1.0" @@ -10302,14 +6607,14 @@ stream-each@^1.1.0: stream-events@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/stream-events/-/stream-events-1.0.5.tgz#bbc898ec4df33a4902d892333d47da9bf1c406d5" + resolved "https://registry.npmjs.org/stream-events/-/stream-events-1.0.5.tgz" integrity sha512-E1GUzBSgvct8Jsb3v2X15pjzN1tYebtbLaMg+eBOUOAxgbLoSbT2NS91ckc5lJD1KfLjId+jXJRgo0qnV5Nerg== dependencies: stubs "^3.0.0" stream-http@^2.7.2: version "2.8.3" - resolved "https://registry.yarnpkg.com/stream-http/-/stream-http-2.8.3.tgz#b2d242469288a5a27ec4fe8933acf623de6514fc" + resolved "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz" integrity sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw== dependencies: builtin-status-codes "^3.0.0" @@ -10320,42 +6625,34 @@ stream-http@^2.7.2: stream-shift@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.0.tgz#d5c752825e5367e786f78e18e445ea223a155952" + resolved "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz" integrity sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI= string-argv@0.3.1: version "0.3.1" - resolved "https://registry.yarnpkg.com/string-argv/-/string-argv-0.3.1.tgz#95e2fbec0427ae19184935f816d74aaa4c5c19da" + resolved "https://registry.npmjs.org/string-argv/-/string-argv-0.3.1.tgz" integrity sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg== string-length@^4.0.1: version "4.0.1" - resolved "https://registry.yarnpkg.com/string-length/-/string-length-4.0.1.tgz#4a973bf31ef77c4edbceadd6af2611996985f8a1" + resolved "https://registry.npmjs.org/string-length/-/string-length-4.0.1.tgz" integrity sha512-PKyXUd0LK0ePjSOnWn34V2uD6acUWev9uy0Ft05k0E8xRW+SKcA0F7eMr7h5xlzfn+4O3N+55rduYyet3Jk+jw== dependencies: char-regex "^1.0.2" strip-ansi "^6.0.0" -string-width@^1.0.1: +string-width@^1.0.1, "string-width@^1.0.2 || 2": version "1.0.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-1.0.2.tgz#118bdf5b8cdc51a2a7e70d211e07e2b0b9b107d3" + resolved "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz" integrity sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M= dependencies: code-point-at "^1.0.0" is-fullwidth-code-point "^1.0.0" strip-ansi "^3.0.0" -"string-width@^1.0.2 || 2", string-width@^2.1.0: - version "2.1.1" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-2.1.1.tgz#ab93f27a8dc13d28cac815c462143a6d9012ae9e" - integrity sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw== - dependencies: - is-fullwidth-code-point "^2.0.0" - strip-ansi "^4.0.0" - -string-width@^3.0.0, string-width@^3.1.0: +string-width@^3.0.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-3.1.0.tgz#22767be21b62af1081574306f69ac51b62203961" + resolved "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz" integrity sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w== dependencies: emoji-regex "^7.0.1" @@ -10364,39 +6661,23 @@ string-width@^3.0.0, string-width@^3.1.0: string-width@^4.0.0, string-width@^4.1.0, string-width@^4.2.0, string-width@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.2.tgz#dafd4f9559a7585cfba529c6a0a4f73488ebd4c5" + resolved "https://registry.npmjs.org/string-width/-/string-width-4.2.2.tgz" integrity sha512-XBJbT3N4JhVumXE0eoLU9DCjcaF92KLNqTmFCnG1pf8duUxFGwtP6AD6nkjw9a3IdiRtL3E2w3JDiE/xi3vOeA== dependencies: emoji-regex "^8.0.0" is-fullwidth-code-point "^3.0.0" strip-ansi "^6.0.0" -string.prototype.trimleft@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimleft/-/string.prototype.trimleft-2.1.0.tgz#6cc47f0d7eb8d62b0f3701611715a3954591d634" - integrity sha512-FJ6b7EgdKxxbDxc79cOlok6Afd++TTs5szo+zJTUyow3ycrRfJVE2pq3vcN53XexvKZu/DJMDfeI/qMiZTrjTw== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - -string.prototype.trimright@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/string.prototype.trimright/-/string.prototype.trimright-2.1.0.tgz#669d164be9df9b6f7559fa8e89945b168a5a6c58" - integrity sha512-fXZTSV55dNBwv16uw+hh5jkghxSnc5oHq+5K/gXgizHwAvMetdAJlHqqoFC1FSDVPYWLkAKl2cxpUT41sV7nSg== - dependencies: - define-properties "^1.1.3" - function-bind "^1.1.1" - string_decoder@^1.0.0, string_decoder@^1.1.1, string_decoder@~1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8" + resolved "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz" integrity sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg== dependencies: safe-buffer "~5.1.0" stringify-object@^3.3.0: version "3.3.0" - resolved "https://registry.yarnpkg.com/stringify-object/-/stringify-object-3.3.0.tgz#703065aefca19300d3ce88af4f5b3956d7556629" + resolved "https://registry.npmjs.org/stringify-object/-/stringify-object-3.3.0.tgz" integrity sha512-rHqiFh1elqCQ9WPLIC8I0Q/g/wj5J1eMkyoiD6eoQApWHP0FtlK7rqnhmabL5VUY9JQCcqwwvlOaSuutekgyrw== dependencies: get-own-enumerable-property-symbols "^3.0.0" @@ -10405,100 +6686,53 @@ stringify-object@^3.3.0: strip-ansi@^3.0.0, strip-ansi@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-3.0.1.tgz#6a385fb8853d952d5ff05d0e8aaf94278dc63dcf" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz" integrity sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8= dependencies: ansi-regex "^2.0.0" -strip-ansi@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-4.0.0.tgz#a8479022eb1ac368a871389b635262c505ee368f" - integrity sha1-qEeQIusaw2iocTibY1JixQXuNo8= - dependencies: - ansi-regex "^3.0.0" - -strip-ansi@^5.0.0, strip-ansi@^5.1.0, strip-ansi@^5.2.0: +strip-ansi@^5.1.0, strip-ansi@^5.2.0: version "5.2.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-5.2.0.tgz#8c9a536feb6afc962bdfa5b104a5091c1ad9c0ae" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz" integrity sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA== dependencies: ansi-regex "^4.1.0" strip-ansi@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" + resolved "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz" integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== dependencies: ansi-regex "^5.0.0" -strip-bom@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-2.0.0.tgz#6219a85616520491f35788bdbf1447a99c7e6b0e" - integrity sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4= - dependencies: - is-utf8 "^0.2.0" - -strip-bom@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" - integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= - strip-bom@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-4.0.0.tgz#9c3505c1db45bcedca3d9cf7a16f5c5aa3901878" + resolved "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz" integrity sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w== strip-eof@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf" + resolved "https://registry.npmjs.org/strip-eof/-/strip-eof-1.0.0.tgz" integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8= strip-final-newline@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-final-newline/-/strip-final-newline-2.0.0.tgz#89b852fb2fcbe936f6f4b3187afb0a12c1ab58ad" + resolved "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz" integrity sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA== -strip-indent@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-1.0.1.tgz#0c7962a6adefa7bbd4ac366460a638552ae1a0a2" - integrity sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI= - dependencies: - get-stdin "^4.0.1" - -strip-indent@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68" - integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g= - -strip-indent@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001" - integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ== - dependencies: - min-indent "^1.0.0" - strip-json-comments@~2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/strip-json-comments/-/strip-json-comments-2.0.1.tgz#3c531942e908c2697c0ec344858c286c7ca0a60a" + resolved "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz" integrity sha1-PFMZQukIwml8DsNEhYwobHygpgo= -strong-log-transformer@^2.0.0, strong-log-transformer@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/strong-log-transformer/-/strong-log-transformer-2.1.0.tgz#0f5ed78d325e0421ac6f90f7f10e691d6ae3ae10" - integrity sha512-B3Hgul+z0L9a236FAUC9iZsL+nVHgoCJnqCbN588DjYxvGXaXaaFbfmQ/JhvKjZwsOukuR72XbHv71Qkug0HxA== - dependencies: - duplexer "^0.1.1" - minimist "^1.2.0" - through "^2.3.4" - stubs@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/stubs/-/stubs-3.0.0.tgz#e8d2ba1fa9c90570303c030b6900f7d5f89abe5b" + resolved "https://registry.npmjs.org/stubs/-/stubs-3.0.0.tgz" integrity sha1-6NK6H6nJBXAwPAMLaQD31fiavls= style-loader@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/style-loader/-/style-loader-2.0.0.tgz#9669602fd4690740eaaec137799a03addbbc393c" + resolved "https://registry.npmjs.org/style-loader/-/style-loader-2.0.0.tgz" integrity sha512-Z0gYUJmzZ6ZdRUqpg1r8GsaFKypE+3xAzuFeMuoHgjc9KZv3wMyCRjQIWEbhoFSq7+7yoHXySDJyyWQaPajeiQ== dependencies: loader-utils "^2.0.0" @@ -10506,7 +6740,7 @@ style-loader@^2.0.0: stylehacks@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/stylehacks/-/stylehacks-5.0.1.tgz#323ec554198520986806388c7fdaebc38d2c06fb" + resolved "https://registry.npmjs.org/stylehacks/-/stylehacks-5.0.1.tgz" integrity sha512-Es0rVnHIqbWzveU1b24kbw92HsebBepxfcqe5iix7t9j0PQqhs0IxXVXv0pY2Bxa08CgMkzD6OWql7kbGOuEdA== dependencies: browserslist "^4.16.0" @@ -10514,21 +6748,21 @@ stylehacks@^5.0.1: supports-color@^5.3.0: version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz" integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== dependencies: has-flag "^3.0.0" supports-color@^7.0.0, supports-color@^7.1.0: version "7.1.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" + resolved "https://registry.npmjs.org/supports-color/-/supports-color-7.1.0.tgz" integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== dependencies: has-flag "^4.0.0" supports-hyperlinks@^2.0.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz#f663df252af5f37c5d49bbd7eeefa9e0b9e59e47" + resolved "https://registry.npmjs.org/supports-hyperlinks/-/supports-hyperlinks-2.1.0.tgz" integrity sha512-zoE5/e+dnEijk6ASB6/qrK+oYdm2do1hjoLWrqUC/8WEIW1gbxFcKuBof7sW8ArN6e+AYvsE8HBGiVRWL/F5CA== dependencies: has-flag "^4.0.0" @@ -10536,7 +6770,7 @@ supports-hyperlinks@^2.0.0: svgo@^2.3.0: version "2.6.1" - resolved "https://registry.yarnpkg.com/svgo/-/svgo-2.6.1.tgz#60b613937e0081028cffc2369090e366b08f1f0e" + resolved "https://registry.npmjs.org/svgo/-/svgo-2.6.1.tgz" integrity sha512-SDo274ymyG1jJ3HtCr3hkfwS8NqWdF0fMr6xPlrJ5y2QMofsQxIEFWgR1epwb197teKGgnZbzozxvJyIeJpE2Q== dependencies: "@trysound/sax" "0.2.0" @@ -10549,17 +6783,17 @@ svgo@^2.3.0: symbol-tree@^3.2.4: version "3.2.4" - resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" + resolved "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.4.tgz" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== tapable@^1.0.0, tapable@^1.1.3: version "1.1.3" - resolved "https://registry.yarnpkg.com/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" + resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== tar-fs@2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.0.tgz" integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA== dependencies: chownr "^1.1.1" @@ -10569,7 +6803,7 @@ tar-fs@2.0.0: tar-stream@^2.0.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.2.0.tgz#acad84c284136b060dc3faa64474aa9aebd77287" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.2.0.tgz" integrity sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ== dependencies: bl "^4.0.3" @@ -10578,7 +6812,7 @@ tar-stream@^2.0.0: inherits "^2.0.3" readable-stream "^3.1.1" -tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: +tar@^4: version "4.4.19" resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.19.tgz#2e4d7263df26f2b914dee10c825ab132123742f3" integrity sha512-a20gEsvHnWe0ygBY8JbxoM4w3SJdhc7ZAuxkLqh+nvNQN2IOt0B5lLgM490X5Hl8FF0dl0tOf2ewFYAlIFgzVA== @@ -10593,7 +6827,7 @@ tar@^4, tar@^4.4.10, tar@^4.4.12, tar@^4.4.8: tar@^6.0.2, tar@^6.1.0: version "6.1.11" - resolved "https://registry.yarnpkg.com/tar/-/tar-6.1.11.tgz#6760a38f003afa1b2ffd0ffe9e9abbd0eab3d621" + resolved "https://registry.npmjs.org/tar/-/tar-6.1.11.tgz" integrity sha512-an/KZQzQUkZCkuoAA64hM92X0Urb6VpRhAFllDzz44U2mcD5scmT3zBc4VgVpkugF580+DQn8eAFSyoQt0tznA== dependencies: chownr "^2.0.0" @@ -10605,7 +6839,7 @@ tar@^6.0.2, tar@^6.1.0: teeny-request@7.1.1: version "7.1.1" - resolved "https://registry.yarnpkg.com/teeny-request/-/teeny-request-7.1.1.tgz#2b0d156f4a8ad81de44303302ba8d7f1f05e20e6" + resolved "https://registry.npmjs.org/teeny-request/-/teeny-request-7.1.1.tgz" integrity sha512-iwY6rkW5DDGq8hE2YgNQlKbptYpY5Nn2xecjQiNjOXWbKzPGUfmeUBCSQbbr306d7Z7U2N0TPl+/SwYRfua1Dg== dependencies: http-proxy-agent "^4.0.0" @@ -10614,37 +6848,9 @@ teeny-request@7.1.1: stream-events "^1.0.5" uuid "^8.0.0" -temp-dir@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/temp-dir/-/temp-dir-1.0.0.tgz#0a7c0ea26d3a39afa7e0ebea9c1fc0bc4daa011d" - integrity sha1-CnwOom06Oa+n4OvqnB/AvE2qAR0= - -temp-write@^3.4.0: - version "3.4.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-3.4.0.tgz#8cff630fb7e9da05f047c74ce4ce4d685457d492" - integrity sha1-jP9jD7fp2gXwR8dM5M5NaFRX1JI= - dependencies: - graceful-fs "^4.1.2" - is-stream "^1.1.0" - make-dir "^1.0.0" - pify "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.0.1" - -temp-write@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/temp-write/-/temp-write-4.0.0.tgz#cd2e0825fc826ae72d201dc26eef3bf7e6fc9320" - integrity sha512-HIeWmj77uOOHb0QX7siN3OtwV3CTntquin6TNVg6SHOqCP3hYKmox90eeFOGaY1MqJ9WYDDjkyZrW6qS5AWpbw== - dependencies: - graceful-fs "^4.1.15" - is-stream "^2.0.0" - make-dir "^3.0.0" - temp-dir "^1.0.0" - uuid "^3.3.2" - terminal-link@^2.0.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/terminal-link/-/terminal-link-2.1.1.tgz#14a64a27ab3c0df933ea546fba55f2d078edc994" + resolved "https://registry.npmjs.org/terminal-link/-/terminal-link-2.1.1.tgz" integrity sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ== dependencies: ansi-escapes "^4.2.1" @@ -10652,7 +6858,7 @@ terminal-link@^2.0.0: terser-webpack-plugin@^1.4.3: version "1.4.4" - resolved "https://registry.yarnpkg.com/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz#2c63544347324baafa9a56baaddf1634c8abfc2f" + resolved "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.4.tgz" integrity sha512-U4mACBHIegmfoEe5fdongHESNJWqsGU+W0S/9+BmYGVQDw1+c2Ow05TpMhxjPK1sRb7cuYq1BPl1e5YHJMTCqA== dependencies: cacache "^12.0.2" @@ -10667,16 +6873,16 @@ terser-webpack-plugin@^1.4.3: terser@^4.1.2, terser@^4.7.0: version "4.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-4.8.0.tgz#63056343d7c70bb29f3af665865a46fe03a0df17" + resolved "https://registry.npmjs.org/terser/-/terser-4.8.0.tgz" integrity sha512-EAPipTNeWsb/3wLPeup1tVPaXfIaU68xMnVdPafIL1TV05OhASArYyIfFvnvJCNrR2NIOvDVNNTFRa+Re2MWyw== dependencies: commander "^2.20.0" source-map "~0.6.1" source-map-support "~0.5.12" -terser@^5.0.0, terser@^5.6.0: +terser@^5.6.0: version "5.8.0" - resolved "https://registry.yarnpkg.com/terser/-/terser-5.8.0.tgz#c6d352f91aed85cc6171ccb5e84655b77521d947" + resolved "https://registry.npmjs.org/terser/-/terser-5.8.0.tgz" integrity sha512-f0JH+6yMpneYcRJN314lZrSwu9eKkUFEHLN/kNy8ceh8gaRiLgFPJqrB9HsXjhEGdv4e/ekjTOFxIlL6xlma8A== dependencies: commander "^2.20.0" @@ -10685,109 +6891,68 @@ terser@^5.0.0, terser@^5.6.0: test-exclude@^6.0.0: version "6.0.0" - resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" + resolved "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz" integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== dependencies: "@istanbuljs/schema" "^0.1.2" glob "^7.1.4" minimatch "^3.0.4" -text-extensions@^1.0.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/text-extensions/-/text-extensions-1.9.0.tgz#1853e45fee39c945ce6f6c36b2d659b5aabc2a26" - integrity sha512-wiBrwC1EhBelW12Zy26JeOUkQ5mRu+5o8rpsJk5+2t+Y5vE7e842qtZDQ2g1NpX/29HdyFeJ4nSIhI47ENSxlQ== - -thenify-all@^1.0.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/thenify-all/-/thenify-all-1.6.0.tgz#1a1918d402d8fc3f98fbf234db0bcc8cc10e9726" - integrity sha1-GhkY1ALY/D+Y+/I02wvMjMEOlyY= - dependencies: - thenify ">= 3.1.0 < 4" - -"thenify@>= 3.1.0 < 4": - version "3.3.1" - resolved "https://registry.yarnpkg.com/thenify/-/thenify-3.3.1.tgz#8932e686a4066038a016dd9e2ca46add9838a95f" - integrity sha512-RVZSIV5IG10Hk3enotrhvz0T9em6cyHBLkH/YAZuKqd8hRkKhSfCGIcP2KUY0EPxndzANBmNllzWPwak+bheSw== - dependencies: - any-promise "^1.0.0" - throat@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/throat/-/throat-5.0.0.tgz#c5199235803aad18754a667d659b5e72ce16764b" + resolved "https://registry.npmjs.org/throat/-/throat-5.0.0.tgz" integrity sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA== -through2@^2.0.0, through2@^2.0.2: +through2@^2.0.0: version "2.0.5" - resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" + resolved "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== dependencies: readable-stream "~2.3.6" xtend "~4.0.1" -through2@^3.0.0: - version "3.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-3.0.2.tgz#99f88931cfc761ec7678b41d5d7336b5b6a07bf4" - integrity sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ== - dependencies: - inherits "^2.0.4" - readable-stream "2 || 3" - -through2@^4.0.0: - version "4.0.2" - resolved "https://registry.yarnpkg.com/through2/-/through2-4.0.2.tgz#a7ce3ac2a7a8b0b966c80e7c49f0484c3b239764" - integrity sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw== - dependencies: - readable-stream "3" - -through@2, "through@>=2.2.7 <3", through@^2.3.4, through@^2.3.6, through@^2.3.8: +through@^2.3.8: version "2.3.8" - resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" + resolved "https://registry.npmjs.org/through/-/through-2.3.8.tgz" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= timers-browserify@^2.0.4: version "2.0.11" - resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.11.tgz#800b1f3eee272e5bc53ee465a04d0e804c31211f" + resolved "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz" integrity sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ== dependencies: setimmediate "^1.0.4" timsort@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/timsort/-/timsort-0.3.0.tgz#405411a8e7e6339fe64db9a234de11dc31e02bd4" + resolved "https://registry.npmjs.org/timsort/-/timsort-0.3.0.tgz" integrity sha1-QFQRqOfmM5/mTbmiNN4R3DHgK9Q= -tmp@^0.0.33: - version "0.0.33" - resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" - integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== - dependencies: - os-tmpdir "~1.0.2" - tmpl@1.0.x: version "1.0.4" - resolved "https://registry.yarnpkg.com/tmpl/-/tmpl-1.0.4.tgz#23640dd7b42d00433911140820e5cf440e521dd1" + resolved "https://registry.npmjs.org/tmpl/-/tmpl-1.0.4.tgz" integrity sha1-I2QN17QtAEM5ERQIIOXPRA5SHdE= to-arraybuffer@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" + resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= to-fast-properties@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" + resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz" integrity sha1-3F5pjL0HkmW8c+A3doGk5Og/YW4= to-object-path@^0.3.0: version "0.3.0" - resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" + resolved "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz" integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= dependencies: kind-of "^3.0.2" to-regex-range@^2.1.0: version "2.1.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz" integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= dependencies: is-number "^3.0.0" @@ -10795,14 +6960,14 @@ to-regex-range@^2.1.0: to-regex-range@^5.0.1: version "5.0.1" - resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-5.0.1.tgz#1648c44aae7c8d988a326018ed72f5b4dd0392e4" + resolved "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz" integrity sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ== dependencies: is-number "^7.0.0" to-regex@^3.0.1, to-regex@^3.0.2: version "3.0.2" - resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" + resolved "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz" integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== dependencies: define-property "^2.0.2" @@ -10812,12 +6977,12 @@ to-regex@^3.0.1, to-regex@^3.0.2: totalist@^1.0.0: version "1.1.0" - resolved "https://registry.yarnpkg.com/totalist/-/totalist-1.1.0.tgz#a4d65a3e546517701e3e5c37a47a70ac97fe56df" + resolved "https://registry.npmjs.org/totalist/-/totalist-1.1.0.tgz" integrity sha512-gduQwd1rOdDMGxFG1gEvhV88Oirdo2p+KjoYFU7k2g+i7n6AFFbDQ5kMPUsW0pNbfQsB/cwXvT1i4Bue0s9g5g== tough-cookie@^2.3.3, tough-cookie@~2.5.0: version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz" integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== dependencies: psl "^1.1.28" @@ -10825,45 +6990,23 @@ tough-cookie@^2.3.3, tough-cookie@~2.5.0: tough-cookie@^3.0.1: version "3.0.1" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-3.0.1.tgz#9df4f57e739c26930a018184887f4adb7dca73b2" + resolved "https://registry.npmjs.org/tough-cookie/-/tough-cookie-3.0.1.tgz" integrity sha512-yQyJ0u4pZsv9D4clxO69OEjLWYw+jbgspjTue4lTQZLfV0c5l1VmK2y1JK8E9ahdpltPOaAThPcp5nKPUgSnsg== dependencies: ip-regex "^2.1.0" psl "^1.1.28" punycode "^2.1.1" -tr46@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-1.0.1.tgz#a8b13fd6bfd2489519674ccde55ba3693b706d09" - integrity sha1-qLE/1r/SSJUZZ0zN5VujaTtwbQk= - dependencies: - punycode "^2.1.0" - tr46@^2.1.0: version "2.1.0" - resolved "https://registry.yarnpkg.com/tr46/-/tr46-2.1.0.tgz#fa87aa81ca5d5941da8cbf1f9b749dc969a4e240" + resolved "https://registry.npmjs.org/tr46/-/tr46-2.1.0.tgz" integrity sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw== dependencies: punycode "^2.1.1" -trim-newlines@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-1.0.0.tgz#5887966bb582a4503a41eb524f7d35011815a613" - integrity sha1-WIeWa7WCpFA6QetST301ARgVphM= - -trim-newlines@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20" - integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA= - -trim-newlines@^3.0.0: - version "3.0.1" - resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.1.tgz#260a5d962d8b752425b32f3a7db0dcacd176c144" - integrity sha512-c1PTsA3tYrIsLGkJkzHF+w9F2EyxfXGo4UyJc4pFL++FMjnq0HJS69T3M7d//gKrFKwy429bouPescbjecU+Zw== - ts-jest@^26.1.1: version "26.1.1" - resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-26.1.1.tgz#b98569b8a4d4025d966b3d40c81986dd1c510f8d" + resolved "https://registry.npmjs.org/ts-jest/-/ts-jest-26.1.1.tgz" integrity sha512-Lk/357quLg5jJFyBQLnSbhycnB3FPe+e9i7ahxokyXxAYoB0q1pPmqxxRPYr4smJic1Rjcf7MXDBhZWgxlli0A== dependencies: bs-logger "0.x" @@ -10879,7 +7022,7 @@ ts-jest@^26.1.1: ts-node@^8.10.2: version "8.10.2" - resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.10.2.tgz#eee03764633b1234ddd37f8db9ec10b75ec7fb8d" + resolved "https://registry.npmjs.org/ts-node/-/ts-node-8.10.2.tgz" integrity sha512-ISJJGgkIpDdBhWVu3jufsWpK3Rzo7bdiIXJjQc0ynKxVOVcg2oIrf2H2cejminGrptVc6q6/uynAHNCuWGbpVA== dependencies: arg "^4.1.0" @@ -10890,27 +7033,27 @@ ts-node@^8.10.2: ts-pnp@^1.1.6: version "1.2.0" - resolved "https://registry.yarnpkg.com/ts-pnp/-/ts-pnp-1.2.0.tgz#a500ad084b0798f1c3071af391e65912c86bca92" + resolved "https://registry.npmjs.org/ts-pnp/-/ts-pnp-1.2.0.tgz" integrity sha512-csd+vJOb/gkzvcCHgTGSChYpy5f1/XKNsmvBGO4JXS+z1v2HobugDz4s1IeFXM3wZB44uczs+eazB5Q/ccdhQw== tslib@^1.13.0, tslib@^1.8.1, tslib@^1.9.0: version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" + resolved "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.0.0, tslib@^2.3.1: +tslib@^2.0.0: version "2.3.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.3.1.tgz#e8a335add5ceae51aa261d32a490158ef042ef01" + resolved "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz" integrity sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw== tslint-config-prettier@^1.18.0: version "1.18.0" - resolved "https://registry.yarnpkg.com/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz#75f140bde947d35d8f0d238e0ebf809d64592c37" + resolved "https://registry.npmjs.org/tslint-config-prettier/-/tslint-config-prettier-1.18.0.tgz" integrity sha512-xPw9PgNPLG3iKRxmK7DWr+Ea/SzrvfHtjFt5LBl61gk2UBG/DB9kCXRjv+xyIU1rUtnayLeMUVJBcMX8Z17nDg== -tslint@^6.1.2, tslint@^6.1.3: +tslint@^6.1.3: version "6.1.3" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-6.1.3.tgz#5c23b2eccc32487d5523bd3a470e9aa31789d904" + resolved "https://registry.npmjs.org/tslint/-/tslint-6.1.3.tgz" integrity sha512-IbR4nkT96EQOvKE2PW/djGz8iGNeJ4rF2mBfiYaR/nvUWYKJhLwimoJKgjIFEIDibBtOevj7BqCRL4oHeWWUCg== dependencies: "@babel/code-frame" "^7.0.0" @@ -10929,90 +7072,75 @@ tslint@^6.1.2, tslint@^6.1.3: tsutils@^2.29.0: version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" + resolved "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz" integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== dependencies: tslib "^1.8.1" tty-browserify@0.0.0: version "0.0.0" - resolved "https://registry.yarnpkg.com/tty-browserify/-/tty-browserify-0.0.0.tgz#a157ba402da24e9bf957f9aa69d524eed42901a6" + resolved "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz" integrity sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY= tunnel-agent@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" + resolved "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz" integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= dependencies: safe-buffer "^5.0.1" tweetnacl@^0.14.3, tweetnacl@~0.14.0: version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" + resolved "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz" integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= type-check@~0.3.2: version "0.3.2" - resolved "https://registry.yarnpkg.com/type-check/-/type-check-0.3.2.tgz#5884cab512cf1d355e3fb784f30804b2b520db72" + resolved "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz" integrity sha1-WITKtRLPHTVeP7eE8wgEsrUg23I= dependencies: prelude-ls "~1.1.2" type-detect@4.0.8: version "4.0.8" - resolved "https://registry.yarnpkg.com/type-detect/-/type-detect-4.0.8.tgz#7646fb5f18871cfbb7749e69bd39a6388eb7450c" + resolved "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz" integrity sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g== type-fest@^0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.11.0.tgz#97abf0872310fed88a5c466b25681576145e33f1" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz" integrity sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ== -type-fest@^0.18.0: - version "0.18.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.18.1.tgz#db4bc151a4a2cf4eebf9add5db75508db6cc841f" - integrity sha512-OIAYXk8+ISY+qTOwkHtKqzAuxchoMiD9Udx+FSGQDuiRR+PJKJHc2NJAXlbhkGwTt/4/nKZxELY1w3ReWOL8mw== - type-fest@^0.20.2: version "0.20.2" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.20.2.tgz#1bf207f4b28f91583666cb5fbd327887301cd5f4" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz" integrity sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ== -type-fest@^0.3.0: - version "0.3.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.3.1.tgz#63d00d204e059474fe5e1b7c011112bbd1dc29e1" - integrity sha512-cUGJnCdr4STbePCgqNFbpVNCepa+kAVohJs1sLhxzdH+gnEoOd8VhbYa7pD3zZYGiURWM2xzEII3fQcRizDkYQ== - -type-fest@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.4.1.tgz#8bdf77743385d8a4f13ba95f610f5ccd68c728f8" - integrity sha512-IwzA/LSfD2vC1/YDYMv/zHP4rDF1usCwllsDpbolT3D4fUepIO7f9K70jjmUewU/LmGUKJcwcVtDCpnKk4BPMw== - type-fest@^0.6.0: version "0.6.0" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.6.0.tgz" integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg== type-fest@^0.8.1: version "0.8.1" - resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d" + resolved "https://registry.npmjs.org/type-fest/-/type-fest-0.8.1.tgz" integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA== typedarray-to-buffer@^3.1.5: version "3.1.5" - resolved "https://registry.yarnpkg.com/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz#a97ee7a9ff42691b9f783ff1bc5112fe3fca9080" + resolved "https://registry.npmjs.org/typedarray-to-buffer/-/typedarray-to-buffer-3.1.5.tgz" integrity sha512-zdu8XMNEDepKKR+XYOXAVPtWui0ly0NtohUscw+UmaHiAWT8hrV1rr//H6V+0DvJ3OQ19S979M0laLfX8rm82Q== dependencies: is-typedarray "^1.0.0" typedarray@^0.0.6: version "0.0.6" - resolved "https://registry.yarnpkg.com/typedarray/-/typedarray-0.0.6.tgz#867ac74e3864187b1d3d47d996a78ec5c8830777" + resolved "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz" integrity sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c= typedoc-default-themes@^0.6.3: version "0.6.3" - resolved "https://registry.yarnpkg.com/typedoc-default-themes/-/typedoc-default-themes-0.6.3.tgz#c214ce5bbcc6045558448a8fd422b90e3e9b6782" + resolved "https://registry.npmjs.org/typedoc-default-themes/-/typedoc-default-themes-0.6.3.tgz" integrity sha512-rouf0TcIA4M2nOQFfC7Zp4NEwoYiEX4vX/ZtudJWU9IHA29MPC+PPgSXYLPESkUo7FuB//GxigO3mk9Qe1xp3Q== dependencies: backbone "^1.4.0" @@ -11022,14 +7150,14 @@ typedoc-default-themes@^0.6.3: typedoc-plugin-markdown@2.2.11: version "2.2.11" - resolved "https://registry.yarnpkg.com/typedoc-plugin-markdown/-/typedoc-plugin-markdown-2.2.11.tgz#81ea607a7bc82cf3ae0bc6de4bbb7e8ea6b437f2" + resolved "https://registry.npmjs.org/typedoc-plugin-markdown/-/typedoc-plugin-markdown-2.2.11.tgz" integrity sha512-tzBJJjM23DZMbfV+wds+M/IH8xNUVX4iyvABWyL9+gQZY6Fwbf2xGur2Dg6jNXGn2OsuqjZRI3dvSeqw64MSMA== dependencies: fs-extra "^8.1.0" typedoc@0.15.8: version "0.15.8" - resolved "https://registry.yarnpkg.com/typedoc/-/typedoc-0.15.8.tgz#d83195445a718d173e0d5c73b5581052cb47d4d9" + resolved "https://registry.npmjs.org/typedoc/-/typedoc-0.15.8.tgz" integrity sha512-a0zypcvfIFsS7Gqpf2MkC1+jNND3K1Om38pbDdy/gYWX01NuJZhC5+O0HkIp0oRIZOo7PWrA5+fC24zkANY28Q== dependencies: "@types/minimatch" "3.0.3" @@ -11046,40 +7174,25 @@ typedoc@0.15.8: typescript@3.7.x: version "3.7.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.7.7.tgz#c931733e2ec10dda56b855b379cc488a72a81199" + resolved "https://registry.npmjs.org/typescript/-/typescript-3.7.7.tgz" integrity sha512-MmQdgo/XenfZPvVLtKZOq9jQQvzaUAUpcKW8Z43x9B2fOm4S5g//tPtMweZUIP+SoBqrVPEIm+dJeQ9dfO0QdA== -typescript@3.9.4, typescript@^3.5.3: - version "3.9.4" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.4.tgz#5aa0a54904b51b96dfd67870ce2db70251802f10" - integrity sha512-9OL+r0KVHqsYVH7K18IBR9hhC82YwLNlpSZfQDupGcfg8goB9p/s/9Okcy+ztnTeHR2U68xq21/igW9xpoGTgA== - -typescript@^4.4.3: - version "4.4.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.4.3.tgz#bdc5407caa2b109efd4f82fe130656f977a29324" - integrity sha512-4xfscpisVgqqDfPaJo5vkd+Qd/ItkoagnHpufr+i2QCHBsNYp+G7UAoyFl8aPtx879u38wPV65rZ8qbGZijalA== +typescript@^3.8.3: + version "3.9.10" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.10.tgz#70f3910ac7a51ed6bef79da7800690b19bf778b8" + integrity sha512-w6fIxVE/H1PkLKcCPsFqKE7Kv7QUwhU8qQY2MueZXWx5cPZdwFupLgKK3vntcK98BtNHZtAF4LA/yl2a7k8R6Q== uglify-js@^3.1.4: version "3.6.2" - resolved "https://registry.yarnpkg.com/uglify-js/-/uglify-js-3.6.2.tgz#fd8048c86d990ddd29fe99d3300e0cb329103f4d" + resolved "https://registry.npmjs.org/uglify-js/-/uglify-js-3.6.2.tgz" integrity sha512-+gh/xFte41GPrgSMJ/oJVq15zYmqr74pY9VoM69UzMzq9NFk4YDylclb1/bhEzZSaUQjbW5RvniHeq1cdtRYjw== dependencies: commander "2.20.0" source-map "~0.6.1" -uid-number@0.0.6: - version "0.0.6" - resolved "https://registry.yarnpkg.com/uid-number/-/uid-number-0.0.6.tgz#0ea10e8035e8eb5b8e4449f06da1c730663baa81" - integrity sha1-DqEOgDXo61uOREnwbaHHMGY7qoE= - -umask@^1.1.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/umask/-/umask-1.1.0.tgz#f29cebf01df517912bb58ff9c4e50fde8e33320d" - integrity sha1-8pzr8B31F5ErtY/5xOUP3o4zMg0= - unbzip2-stream@1.3.3: version "1.3.3" - resolved "https://registry.yarnpkg.com/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz#d156d205e670d8d8c393e1c02ebd506422873f6a" + resolved "https://registry.npmjs.org/unbzip2-stream/-/unbzip2-stream-1.3.3.tgz" integrity sha512-fUlAF7U9Ah1Q6EieQ4x4zLNejrRvDWUYmxXUpN3uziFYCHapjWFaCAnreY9bGgxzaMCFAPPpYNng57CypwJVhg== dependencies: buffer "^5.2.1" @@ -11087,12 +7200,12 @@ unbzip2-stream@1.3.3: underscore@>=1.8.3, underscore@^1.9.1: version "1.13.1" - resolved "https://registry.yarnpkg.com/underscore/-/underscore-1.13.1.tgz#0c1c6bd2df54b6b69f2314066d65b6cde6fcf9d1" + resolved "https://registry.npmjs.org/underscore/-/underscore-1.13.1.tgz" integrity sha512-hzSoAVtJF+3ZtiFX0VgfFPHEDRm7Y/QPjGyNo4TVdnDTdft3tr8hEkD25a1jC+TjTuE7tkHGKkhwCgs9dgBB2g== union-value@^1.0.0: version "1.0.1" - resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" + resolved "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz" integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== dependencies: arr-union "^3.1.0" @@ -11102,78 +7215,56 @@ union-value@^1.0.0: uniqs@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/uniqs/-/uniqs-2.0.0.tgz#ffede4b36b25290696e6e165d4a59edb998e6b02" + resolved "https://registry.npmjs.org/uniqs/-/uniqs-2.0.0.tgz" integrity sha1-/+3ks2slKQaW5uFl1KWe25mOawI= unique-filename@^1.1.1: version "1.1.1" - resolved "https://registry.yarnpkg.com/unique-filename/-/unique-filename-1.1.1.tgz#1d69769369ada0583103a1e6ae87681b56573230" + resolved "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz" integrity sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ== dependencies: unique-slug "^2.0.0" unique-slug@^2.0.0: version "2.0.2" - resolved "https://registry.yarnpkg.com/unique-slug/-/unique-slug-2.0.2.tgz#baabce91083fc64e945b0f3ad613e264f7cd4e6c" + resolved "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz" integrity sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w== dependencies: imurmurhash "^0.1.4" -universal-user-agent@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-4.0.1.tgz#fd8d6cb773a679a709e967ef8288a31fcc03e557" - integrity sha512-LnST3ebHwVL2aNe4mejI9IQh2HfZ1RLo8Io2HugSif8ekzD1TlWpHpColOB/eh8JHMLkGH3Akqf040I+4ylNxg== - dependencies: - os-name "^3.1.0" - -universal-user-agent@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-6.0.0.tgz#3381f8503b251c0d9cd21bc1de939ec9df5480ee" - integrity sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w== - universalify@^0.1.0: version "0.1.2" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" + resolved "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz" integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== -universalify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/universalify/-/universalify-2.0.0.tgz#75a4984efedc4b08975c5aeb73f530d02df25717" - integrity sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ== - unset-value@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" + resolved "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz" integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= dependencies: has-value "^0.3.1" isobject "^3.0.0" -upath@^1.1.1, upath@^1.2.0: +upath@^1.1.1: version "1.2.0" - resolved "https://registry.yarnpkg.com/upath/-/upath-1.2.0.tgz#8f66dbcd55a883acdae4408af8b035a5044c1894" + resolved "https://registry.npmjs.org/upath/-/upath-1.2.0.tgz" integrity sha512-aZwGpamFO61g3OlfT7OQCHqhGnW43ieH9WZeP7QxN/G/jS4jfqUkZxoryvJgVPEcrl5NL/ggHsSmLMHuH64Lhg== -upath@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/upath/-/upath-2.0.1.tgz#50c73dea68d6f6b990f51d279ce6081665d61a8b" - integrity sha512-1uEe95xksV1O0CYKXo8vQvN1JEbtJp7lb7C5U9HMsIp6IVwntkH/oNUzyVNQSd4S1sYk2FpSSW44FqMc8qee5w== - uri-js@^4.2.2: version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" + resolved "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz" integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== dependencies: punycode "^2.1.0" urix@^0.1.0: version "0.1.0" - resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" + resolved "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz" integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= url@^0.11.0: version "0.11.0" - resolved "https://registry.yarnpkg.com/url/-/url-0.11.0.tgz#3838e97cfc60521eb73c525a8e55bfdd9e2e28f1" + resolved "https://registry.npmjs.org/url/-/url-0.11.0.tgz" integrity sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE= dependencies: punycode "1.3.2" @@ -11181,69 +7272,62 @@ url@^0.11.0: urlgrey@1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/urlgrey/-/urlgrey-1.0.0.tgz#72d2f904482d0b602e3c7fa599343d699bbe1017" + resolved "https://registry.npmjs.org/urlgrey/-/urlgrey-1.0.0.tgz" integrity sha512-hJfIzMPJmI9IlLkby8QrsCykQ+SXDeO2W5Q9QTW3QpqZVTx4a/K7p8/5q+/isD8vsbVaFgql/gvAoQCRQ2Cb5w== dependencies: fast-url-parser "^1.1.3" use@^3.1.0: version "3.1.1" - resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" + resolved "https://registry.npmjs.org/use/-/use-3.1.1.tgz" integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== util-deprecate@^1.0.1, util-deprecate@^1.0.2, util-deprecate@~1.0.1: version "1.0.2" - resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf" + resolved "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz" integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8= -util-promisify@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/util-promisify/-/util-promisify-2.1.0.tgz#3c2236476c4d32c5ff3c47002add7c13b9a82a53" - integrity sha1-PCI2R2xNMsX/PEcAKt18E7moKlM= - dependencies: - object.getownpropertydescriptors "^2.0.3" - util@0.10.3: version "0.10.3" - resolved "https://registry.yarnpkg.com/util/-/util-0.10.3.tgz#7afb1afe50805246489e3db7fe0ed379336ac0f9" + resolved "https://registry.npmjs.org/util/-/util-0.10.3.tgz" integrity sha1-evsa/lCAUkZInj23/g7TeTNqwPk= dependencies: inherits "2.0.1" util@^0.11.0: version "0.11.1" - resolved "https://registry.yarnpkg.com/util/-/util-0.11.1.tgz#3236733720ec64bb27f6e26f421aaa2e1b588d61" + resolved "https://registry.npmjs.org/util/-/util-0.11.1.tgz" integrity sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ== dependencies: inherits "2.0.3" -uuid@^3.0.1, uuid@^3.3.2, uuid@^3.3.3: +uuid@^3.3.2, uuid@^3.3.3: version "3.4.0" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.4.0.tgz#b23e4358afa8a202fe7a100af1f5f883f02007ee" + resolved "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz" integrity sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A== uuid@^7.0.3: version "7.0.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-7.0.3.tgz#c5c9f2c8cf25dc0a372c4df1441c41f5bd0c680b" + resolved "https://registry.npmjs.org/uuid/-/uuid-7.0.3.tgz" integrity sha512-DPSke0pXhTZgoF/d+WSt2QaKMCFSfx7QegxEWT+JOuHF5aWrKEn0G+ztjuJg/gG8/ItK+rbPCD/yNv8yyih6Cg== uuid@^8.0.0: version "8.3.2" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-8.3.2.tgz#80d5b5ced271bb9af6c445f21a1a04c606cefbe2" + resolved "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz" integrity sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg== v8-to-istanbul@^4.1.3: version "4.1.4" - resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" + resolved "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz" integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== dependencies: "@types/istanbul-lib-coverage" "^2.0.1" convert-source-map "^1.6.0" source-map "^0.7.3" -validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3, validate-npm-package-license@^3.0.4: +validate-npm-package-license@^3.0.1: version "3.0.4" - resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a" + resolved "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz" integrity sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew== dependencies: spdx-correct "^3.0.0" @@ -11251,19 +7335,19 @@ validate-npm-package-license@^3.0.1, validate-npm-package-license@^3.0.3, valida validate-npm-package-name@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz#5fa912d81eb7d0c74afc140de7317f0ca7df437e" + resolved "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-3.0.0.tgz" integrity sha1-X6kS2B630MdK/BQN5zF/DKffQ34= dependencies: builtins "^1.0.3" vendors@^1.0.3: version "1.0.4" - resolved "https://registry.yarnpkg.com/vendors/-/vendors-1.0.4.tgz#e2b800a53e7a29b93506c3cf41100d16c4c4ad8e" + resolved "https://registry.npmjs.org/vendors/-/vendors-1.0.4.tgz" integrity sha512-/juG65kTL4Cy2su4P8HjtkTxk6VmJDiOPBufWniqQ6wknac6jNiXS9vU+hO3wgusiyqWlzTbVHi0dyJqRONg3w== verror@1.10.0: version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" + resolved "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz" integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= dependencies: assert-plus "^1.0.0" @@ -11272,40 +7356,40 @@ verror@1.10.0: vm-browserify@^1.0.1: version "1.1.0" - resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019" + resolved "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.0.tgz" integrity sha512-iq+S7vZJE60yejDYM0ek6zg308+UZsdtPExWP9VZoCFCz1zkJoXFnAX7aZfd/ZwrkidzdUZL0C/ryW+JwAiIGw== w3c-hr-time@^1.0.2: version "1.0.2" - resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" + resolved "https://registry.npmjs.org/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz" integrity sha512-z8P5DvDNjKDoFIHK7q8r8lackT6l+jo/Ye3HOle7l9nICP9lf1Ci25fy9vHd0JOWewkIFzXIEig3TdKT7JQ5fQ== dependencies: browser-process-hrtime "^1.0.0" w3c-xmlserializer@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz#3e7104a05b75146cc60f564380b7f683acf1020a" + resolved "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-2.0.0.tgz" integrity sha512-4tzD0mF8iSiMiNs30BiLO3EpfGLZUT2MSX/G+o7ZywDzliWQ3OPtTZ0PTC3B3ca1UAf4cJMHB+2Bf56EriJuRA== dependencies: xml-name-validator "^3.0.0" walker@^1.0.7, walker@~1.0.5: version "1.0.7" - resolved "https://registry.yarnpkg.com/walker/-/walker-1.0.7.tgz#2f7f9b8fd10d677262b18a884e28d19618e028fb" + resolved "https://registry.npmjs.org/walker/-/walker-1.0.7.tgz" integrity sha1-L3+bj9ENZ3JisYqITijRlhjgKPs= dependencies: makeerror "1.0.x" watchpack-chokidar2@^2.0.1: version "2.0.1" - resolved "https://registry.yarnpkg.com/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz#38500072ee6ece66f3769936950ea1771be1c957" + resolved "https://registry.npmjs.org/watchpack-chokidar2/-/watchpack-chokidar2-2.0.1.tgz" integrity sha512-nCFfBIPKr5Sh61s4LPpy1Wtfi0HE8isJ3d2Yb5/Ppw2P2B/3eVSEBjKfN0fmHJSK14+31KwMKmcrzs2GM4P0Ww== dependencies: chokidar "^2.1.8" watchpack@^1.7.4: version "1.7.5" - resolved "https://registry.yarnpkg.com/watchpack/-/watchpack-1.7.5.tgz#1267e6c55e0b9b5be44c2023aed5437a2c26c453" + resolved "https://registry.npmjs.org/watchpack/-/watchpack-1.7.5.tgz" integrity sha512-9P3MWk6SrKjHsGkLT2KHXdQ/9SNkyoJbabxnKOoJepsvJjJG8uYTR3yTPxPQvNDI3w4Nz1xnE0TLHK4RIVe/MQ== dependencies: graceful-fs "^4.1.2" @@ -11314,31 +7398,19 @@ watchpack@^1.7.4: chokidar "^3.4.1" watchpack-chokidar2 "^2.0.1" -wcwidth@^1.0.0, wcwidth@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/wcwidth/-/wcwidth-1.0.1.tgz#f0b0dcf915bc5ff1528afadb2c0e17b532da2fe8" - integrity sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g= - dependencies: - defaults "^1.0.3" - -webidl-conversions@^4.0.2: - version "4.0.2" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad" - integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg== - webidl-conversions@^5.0.0: version "5.0.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-5.0.0.tgz#ae59c8a00b121543a2acc65c0434f57b0fc11aff" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-5.0.0.tgz" integrity sha512-VlZwKPCkYKxQgeSbH5EyngOmRp7Ww7I9rQLERETtf5ofd9pGeswWiOtogpEO850jziPRarreGxn5QIiTqpb2wA== webidl-conversions@^6.0.0, webidl-conversions@^6.1.0: version "6.1.0" - resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-6.1.0.tgz#9111b4d7ea80acd40f5270d666621afa78b69514" + resolved "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-6.1.0.tgz" integrity sha512-qBIvFLGiBpLjfwmYAaHPXsn+ho5xZnGvyGvsarywGNc8VyQJUMHJ8OBKGGrPER0okBeMDaan4mNBlgBROxuI8w== webpack-bundle-analyzer@^4.4.2: version "4.4.2" - resolved "https://registry.yarnpkg.com/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz#39898cf6200178240910d629705f0f3493f7d666" + resolved "https://registry.npmjs.org/webpack-bundle-analyzer/-/webpack-bundle-analyzer-4.4.2.tgz" integrity sha512-PIagMYhlEzFfhMYOzs5gFT55DkUdkyrJi/SxJp8EF3YMWhS+T9vvs2EoTetpk5qb6VsCq02eXTlRDOydRhDFAQ== dependencies: acorn "^8.0.4" @@ -11353,7 +7425,7 @@ webpack-bundle-analyzer@^4.4.2: webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: version "1.4.3" - resolved "https://registry.yarnpkg.com/webpack-sources/-/webpack-sources-1.4.3.tgz#eedd8ec0b928fbf1cbfe994e22d2d890f330a933" + resolved "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz" integrity sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ== dependencies: source-list-map "^2.0.0" @@ -11361,7 +7433,7 @@ webpack-sources@^1.1.0, webpack-sources@^1.4.0, webpack-sources@^1.4.1: webpack@^4.44.1: version "4.46.0" - resolved "https://registry.yarnpkg.com/webpack/-/webpack-4.46.0.tgz#bf9b4404ea20a073605e0a011d188d77cb6ad542" + resolved "https://registry.npmjs.org/webpack/-/webpack-4.46.0.tgz" integrity sha512-6jJuJjg8znb/xRItk7bkT0+Q7AHCYjjFnvKIWQPkNIOyRqoCGvkOs0ipeQzrqz4l5FtN5ZI/ukEHroeX/o1/5Q== dependencies: "@webassemblyjs/ast" "1.9.0" @@ -11390,28 +7462,19 @@ webpack@^4.44.1: whatwg-encoding@^1.0.5: version "1.0.5" - resolved "https://registry.yarnpkg.com/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz#5abacf777c32166a51d085d6b4f3e7d27113ddb0" + resolved "https://registry.npmjs.org/whatwg-encoding/-/whatwg-encoding-1.0.5.tgz" integrity sha512-b5lim54JOPN9HtzvK9HFXvBma/rnfFeqsic0hSpjtDbVxR3dJKLc+KB4V6GgiGOvl7CY/KNh8rxSo9DKQrnUEw== dependencies: iconv-lite "0.4.24" whatwg-mimetype@^2.3.0: version "2.3.0" - resolved "https://registry.yarnpkg.com/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz#3d4b1e0312d2079879f826aff18dbeeca5960fbf" + resolved "https://registry.npmjs.org/whatwg-mimetype/-/whatwg-mimetype-2.3.0.tgz" integrity sha512-M4yMwr6mAnQz76TbJm914+gPpB/nCwvZbJU28cUD6dR004SAxDLOOSUaB1JDRqLtaOV/vi0IC5lEAGFgrjGv/g== -whatwg-url@^7.0.0: - version "7.1.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06" - integrity sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg== - dependencies: - lodash.sortby "^4.7.0" - tr46 "^1.0.1" - webidl-conversions "^4.0.2" - -whatwg-url@^8.0.0, whatwg-url@^8.4.0: +whatwg-url@^8.0.0: version "8.7.0" - resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-8.7.0.tgz#656a78e510ff8f3937bc0bcbe9f5c0ac35941b77" + resolved "https://registry.npmjs.org/whatwg-url/-/whatwg-url-8.7.0.tgz" integrity sha512-gAojqb/m9Q8a5IV96E3fHJM70AzCkgt4uXYX2O7EmuyOnLrViCQlsEBmF9UQIu3/aeAIp2U17rtbpZWNntQqdg== dependencies: lodash "^4.7.0" @@ -11420,73 +7483,57 @@ whatwg-url@^8.0.0, whatwg-url@^8.4.0: which-module@^2.0.0: version "2.0.0" - resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" + resolved "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz" integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= -which@1, which@^1.2.9, which@^1.3.1: +which@^1.2.9: version "1.3.1" - resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" + resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== dependencies: isexe "^2.0.0" which@^2.0.1, which@^2.0.2: version "2.0.2" - resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" + resolved "https://registry.npmjs.org/which/-/which-2.0.2.tgz" integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== dependencies: isexe "^2.0.0" wide-align@^1.1.0: version "1.1.3" - resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457" + resolved "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz" integrity sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA== dependencies: string-width "^1.0.2 || 2" widest-line@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/widest-line/-/widest-line-3.1.0.tgz#8292333bbf66cb45ff0de1603b136b7ae1496eca" + resolved "https://registry.npmjs.org/widest-line/-/widest-line-3.1.0.tgz" integrity sha512-NsmoXalsWVDMGupxZ5R08ka9flZjjiLvHVAWYOKtiKM8ujtZWr9cRffak+uSE48+Ob8ObalXpwyeUiyDD6QFgg== dependencies: string-width "^4.0.0" -windows-release@^3.1.0: - version "3.3.3" - resolved "https://registry.yarnpkg.com/windows-release/-/windows-release-3.3.3.tgz#1c10027c7225743eec6b89df160d64c2e0293999" - integrity sha512-OSOGH1QYiW5yVor9TtmXKQvt2vjQqbYS+DqmsZw+r7xDwLXEeT3JGW0ZppFmHx4diyXmxt238KFR3N9jzevBRg== - dependencies: - execa "^1.0.0" - word-wrap@~1.2.3: version "1.2.3" - resolved "https://registry.yarnpkg.com/word-wrap/-/word-wrap-1.2.3.tgz#610636f6b1f703891bd34771ccb17fb93b47079c" + resolved "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz" integrity sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ== wordwrap@^1.0.0: version "1.0.0" - resolved "https://registry.yarnpkg.com/wordwrap/-/wordwrap-1.0.0.tgz#27584810891456a4171c8d0226441ade90cbcaeb" + resolved "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz" integrity sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus= worker-farm@^1.7.0: version "1.7.0" - resolved "https://registry.yarnpkg.com/worker-farm/-/worker-farm-1.7.0.tgz#26a94c5391bbca926152002f69b84a4bf772e5a8" + resolved "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz" integrity sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw== dependencies: errno "~0.1.7" -wrap-ansi@^5.1.0: - version "5.1.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-5.1.0.tgz#1fd1f67235d5b6d0fee781056001bfb694c03b09" - integrity sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q== - dependencies: - ansi-styles "^3.2.0" - string-width "^3.0.0" - strip-ansi "^5.0.0" - wrap-ansi@^6.2.0: version "6.2.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz" integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== dependencies: ansi-styles "^4.0.0" @@ -11495,7 +7542,7 @@ wrap-ansi@^6.2.0: wrap-ansi@^7.0.0: version "7.0.0" - resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-7.0.0.tgz#67e145cff510a6a6984bdf1152911d69d2eb9e43" + resolved "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz" integrity sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q== dependencies: ansi-styles "^4.0.0" @@ -11504,21 +7551,12 @@ wrap-ansi@^7.0.0: wrappy@1: version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" + resolved "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz" integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= -write-file-atomic@^2.0.0, write-file-atomic@^2.3.0, write-file-atomic@^2.4.2: - version "2.4.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-2.4.3.tgz#1fd2e9ae1df3e75b8d8c367443c692d4ca81f481" - integrity sha512-GaETH5wwsX+GcnzhPgKcKjJ6M2Cq3/iZp1WyY/X1CSqrW+jVNM9Y7D8EC2sM4ZG/V8wZlSniJnCKWPmBYAucRQ== - dependencies: - graceful-fs "^4.1.11" - imurmurhash "^0.1.4" - signal-exit "^3.0.2" - -write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: +write-file-atomic@^3.0.0: version "3.0.3" - resolved "https://registry.yarnpkg.com/write-file-atomic/-/write-file-atomic-3.0.3.tgz#56bd5c5a5c70481cd19c571bd39ab965a5de56e8" + resolved "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-3.0.3.tgz" integrity sha512-AvHcyZ5JnSfq3ioSyjrBkH9yW4m7Ayk8/9My/DD9onKeu/94fwrMocemO2QAJFAlnnDN+ZDS+ZjAR5ua1/PV/Q== dependencies: imurmurhash "^0.1.4" @@ -11526,150 +7564,72 @@ write-file-atomic@^3.0.0, write-file-atomic@^3.0.3: signal-exit "^3.0.2" typedarray-to-buffer "^3.1.5" -write-json-file@^2.2.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-2.3.0.tgz#2b64c8a33004d54b8698c76d585a77ceb61da32f" - integrity sha1-K2TIozAE1UuGmMdtWFp3zrYdoy8= - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.2" - make-dir "^1.0.0" - pify "^3.0.0" - sort-keys "^2.0.0" - write-file-atomic "^2.0.0" - -write-json-file@^3.2.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-3.2.0.tgz#65bbdc9ecd8a1458e15952770ccbadfcff5fe62a" - integrity sha512-3xZqT7Byc2uORAatYiP3DHUUAVEkNOswEWNs9H5KXiicRTvzYzYqKjYc4G7p+8pltvAw641lVByKVtMpf+4sYQ== - dependencies: - detect-indent "^5.0.0" - graceful-fs "^4.1.15" - make-dir "^2.1.0" - pify "^4.0.1" - sort-keys "^2.0.0" - write-file-atomic "^2.4.2" - -write-json-file@^4.3.0: - version "4.3.0" - resolved "https://registry.yarnpkg.com/write-json-file/-/write-json-file-4.3.0.tgz#908493d6fd23225344af324016e4ca8f702dd12d" - integrity sha512-PxiShnxf0IlnQuMYOPPhPkhExoCQuTUNPOa/2JWCYTmBquU9njyyDuwRKN26IZBlp4yn1nt+Agh2HOOBl+55HQ== - dependencies: - detect-indent "^6.0.0" - graceful-fs "^4.1.15" - is-plain-obj "^2.0.0" - make-dir "^3.0.0" - sort-keys "^4.0.0" - write-file-atomic "^3.0.0" - -write-pkg@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-3.2.0.tgz#0e178fe97820d389a8928bc79535dbe68c2cff21" - integrity sha512-tX2ifZ0YqEFOF1wjRW2Pk93NLsj02+n1UP5RvO6rCs0K6R2g1padvf006cY74PQJKMGS2r42NK7FD0dG6Y6paw== - dependencies: - sort-keys "^2.0.0" - write-json-file "^2.2.0" - -write-pkg@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/write-pkg/-/write-pkg-4.0.0.tgz#675cc04ef6c11faacbbc7771b24c0abbf2a20039" - integrity sha512-v2UQ+50TNf2rNHJ8NyWttfm/EJUBWMJcx6ZTYZr6Qp52uuegWw/lBkCtCbnYZEmPRNL61m+u67dAmGxo+HTULA== - dependencies: - sort-keys "^2.0.0" - type-fest "^0.4.1" - write-json-file "^3.2.0" - ws@7.4.6, ws@^7.2.3, ws@^7.3.1: version "7.4.6" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.4.6.tgz#5654ca8ecdeee47c33a9a4bf6d28e2be2980377c" + resolved "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz" integrity sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A== xml-name-validator@^3.0.0: version "3.0.0" - resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a" + resolved "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-3.0.0.tgz" integrity sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw== xml@^1.0.1: version "1.0.1" - resolved "https://registry.yarnpkg.com/xml/-/xml-1.0.1.tgz#78ba72020029c5bc87b8a81a3cfcd74b4a2fc1e5" + resolved "https://registry.npmjs.org/xml/-/xml-1.0.1.tgz" integrity sha1-eLpyAgApxbyHuKgaPPzXS0ovweU= xmlchars@^2.2.0: version "2.2.0" - resolved "https://registry.yarnpkg.com/xmlchars/-/xmlchars-2.2.0.tgz#060fe1bcb7f9c76fe2a17db86a9bc3ab894210cb" + resolved "https://registry.npmjs.org/xmlchars/-/xmlchars-2.2.0.tgz" integrity sha512-JZnDKK8B0RCDw84FNdDAIpZK+JuJw+s7Lz8nksI7SIuU3UXJJslUthsi+uWBUYOwPFwW7W7PRLRfUKpxjtjFCw== xtend@^4.0.0, xtend@~4.0.1: version "4.0.2" - resolved "https://registry.yarnpkg.com/xtend/-/xtend-4.0.2.tgz#bb72779f5fa465186b1f438f674fa347fdb5db54" + resolved "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz" integrity sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ== y18n@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" + resolved "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz" integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== y18n@^5.0.5: version "5.0.8" - resolved "https://registry.yarnpkg.com/y18n/-/y18n-5.0.8.tgz#7f4934d0f7ca8c56f95314939ddcd2dd91ce1d55" + resolved "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz" integrity sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA== -yallist@^3.0.0, yallist@^3.0.2, yallist@^3.0.3, yallist@^3.1.1: +yallist@^3.0.0, yallist@^3.0.2, yallist@^3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" + resolved "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== yallist@^4.0.0: version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" + resolved "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz" integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== yaml@^1.10.0, yaml@^1.10.2: version "1.10.2" - resolved "https://registry.yarnpkg.com/yaml/-/yaml-1.10.2.tgz#2301c5ffbf12b467de8da2333a459e29e7920e4b" + resolved "https://registry.npmjs.org/yaml/-/yaml-1.10.2.tgz" integrity sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg== yargs-parser@18.x, yargs-parser@^18.1.1: version "18.1.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz" integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== dependencies: camelcase "^5.0.0" decamelize "^1.2.0" -yargs-parser@20.2.4, yargs-parser@^20.2.2, yargs-parser@^20.2.3: +yargs-parser@^20.2.2: version "20.2.4" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-20.2.4.tgz#b42890f14566796f85ae8e3a25290d205f154a54" + resolved "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz" integrity sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA== -yargs-parser@^15.0.1: - version "15.0.3" - resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-15.0.3.tgz#316e263d5febe8b38eef61ac092b33dfcc9b1115" - integrity sha512-/MVEVjTXy/cGAjdtQf8dW3V9b97bPN7rNn8ETj6BmAQL7ibC7O1Q9SPJbGjgh3SlwoBNXMzj/ZGIj8mBgl12YA== - dependencies: - camelcase "^5.0.0" - decamelize "^1.2.0" - -yargs@^14.2.2: - version "14.2.3" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-14.2.3.tgz#1a1c3edced1afb2a2fea33604bc6d1d8d688a414" - integrity sha512-ZbotRWhF+lkjijC/VhmOT9wSgyBQ7+zr13+YLkhfsSiTriYsMzkTUFP18pFhWwBeMa5gUc1MzbhrO6/VB7c9Xg== - dependencies: - cliui "^5.0.0" - decamelize "^1.2.0" - find-up "^3.0.0" - get-caller-file "^2.0.1" - require-directory "^2.1.1" - require-main-filename "^2.0.0" - set-blocking "^2.0.0" - string-width "^3.0.0" - which-module "^2.0.0" - y18n "^4.0.0" - yargs-parser "^15.0.1" - yargs@^15.3.1: version "15.3.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.3.1.tgz#9505b472763963e54afe60148ad27a330818e98b" + resolved "https://registry.npmjs.org/yargs/-/yargs-15.3.1.tgz" integrity sha512-92O1HWEjw27sBfgmXiixJWT5hRBp2eobqXicLtPBIDBhYB+1HpwZlXmbW2luivBJHBzki+7VyCLRtAkScbTBQA== dependencies: cliui "^6.0.0" @@ -11684,22 +7644,9 @@ yargs@^15.3.1: y18n "^4.0.0" yargs-parser "^18.1.1" -yargs@^16.2.0: - version "16.2.0" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-16.2.0.tgz#1c82bf0f6b6a66eafce7ef30e376f49a12477f66" - integrity sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw== - dependencies: - cliui "^7.0.2" - escalade "^3.1.1" - get-caller-file "^2.0.5" - require-directory "^2.1.1" - string-width "^4.2.0" - y18n "^5.0.5" - yargs-parser "^20.2.2" - yargs@^17.0.1: version "17.1.1" - resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.1.1.tgz#c2a8091564bdb196f7c0a67c1d12e5b85b8067ba" + resolved "https://registry.npmjs.org/yargs/-/yargs-17.1.1.tgz" integrity sha512-c2k48R0PwKIqKhPMWjeiF6y2xY/gPMUlro0sgxqXpbOIohWiLNXWslsootttv7E1e73QPAMQSg5FeySbVcpsPQ== dependencies: cliui "^7.0.2" @@ -11712,7 +7659,7 @@ yargs@^17.0.1: yarn-deduplicate@^3.1.0: version "3.1.0" - resolved "https://registry.yarnpkg.com/yarn-deduplicate/-/yarn-deduplicate-3.1.0.tgz#3018d93e95f855f236a215b591fe8bc4bcabba3e" + resolved "https://registry.npmjs.org/yarn-deduplicate/-/yarn-deduplicate-3.1.0.tgz" integrity sha512-q2VZ6ThNzQpGfNpkPrkmV7x5HT9MOhCUsTxVTzyyZB0eSXz1NTodHn+r29DlLb+peKk8iXxzdUVhQG9pI7moFw== dependencies: "@yarnpkg/lockfile" "^1.1.0" @@ -11721,7 +7668,7 @@ yarn-deduplicate@^3.1.0: yauzl@^2.10.0: version "2.10.0" - resolved "https://registry.yarnpkg.com/yauzl/-/yauzl-2.10.0.tgz#c7eb17c93e112cb1086fa6d8e51fb0667b79a5f9" + resolved "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz" integrity sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk= dependencies: buffer-crc32 "~0.2.3" @@ -11729,5 +7676,5 @@ yauzl@^2.10.0: yn@3.1.1: version "3.1.1" - resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50" + resolved "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz" integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==